From 0eb3a83beaa6f5e3790b6a0b9be2aa34ef989a77 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 4 Sep 2024 15:12:58 +0200 Subject: [PATCH 01/62] Updated Workflow --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2afdf6d..61217505 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,11 +16,11 @@ jobs: - name: Checkout code uses: actions/checkout@v3 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v3 with: distribution: 'temurin' - java-version: '17' + java-version: '21' - name: Cache Gradle packages uses: actions/cache@v3 From 92a9cd1278e084eaff747837fe8de9b5d6146d83 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 4 Sep 2024 15:56:43 +0200 Subject: [PATCH 02/62] Create PullRequest.md --- .github/PULL_REQUEST_TEMPLATE/PullRequest.md | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/PullRequest.md diff --git a/.github/PULL_REQUEST_TEMPLATE/PullRequest.md b/.github/PULL_REQUEST_TEMPLATE/PullRequest.md new file mode 100644 index 00000000..2241979c --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/PullRequest.md @@ -0,0 +1,26 @@ +## Description + + +## Changes +- **Change 1**: Description of what was changed. +- **Change 2**: Description of what was changed. + +## How has this been tested? + + +## Screenshots (if applicable) + + +## Type of Change +- [ ] Bug fix +- [ ] New feature +- [ ] Documentation update + +## Checklist +- [ ] My code follows the style guidelines of this project. [Contributing](https://github.com/MeAlam1/BlueLib/blob/1.21/CONTRIBUTING.md) +- [ ] I have performed a self-review of my own code. +- [ ] I have commented my code following the guidelines. [Contributing](https://github.com/MeAlam1/BlueLib/blob/1.21/CONTRIBUTING.md) +- [ ] My changes generate no new warnings. + +## Related Issues + \ No newline at end of file From 69c49ef1dcffe21f533074e834efad27e11ff5f1 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 4 Sep 2024 16:06:47 +0200 Subject: [PATCH 03/62] Update PULL_REQUEST_TEMPLATE.md --- .../PullRequest.md => PULL_REQUEST_TEMPLATE.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{PULL_REQUEST_TEMPLATE/PullRequest.md => PULL_REQUEST_TEMPLATE.md} (100%) diff --git a/.github/PULL_REQUEST_TEMPLATE/PullRequest.md b/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE/PullRequest.md rename to .github/PULL_REQUEST_TEMPLATE.md From f4b5466fea97bcbbf5052ace6fc51f6f3fca4486 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 4 Sep 2024 19:43:20 +0200 Subject: [PATCH 04/62] Ported Forge from 1.20 to 1.21 --- .../bluelib/event/ReloadEventHandler.java | 4 +- .../example/entity/dragon/DragonEntity.java | 25 ++++++----- .../example/entity/dragon/DragonModel.java | 4 +- .../bluelib/example/entity/rex/RexEntity.java | 43 +++++++++++-------- .../bluelib/example/entity/rex/RexModel.java | 4 +- .../bluelib/example/init/ModEntities.java | 4 +- .../variant/base/IVariantEntityBase.java | 2 +- 7 files changed, 48 insertions(+), 38 deletions(-) diff --git a/Forge/src/main/java/software/bluelib/event/ReloadEventHandler.java b/Forge/src/main/java/software/bluelib/event/ReloadEventHandler.java index 9a095c52..9da36f9a 100644 --- a/Forge/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/Forge/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -65,8 +65,8 @@ public class ReloadEventHandler { * @since 1.0.0 */ protected static void registerEntityVariants(MinecraftServer pServer, String pEntityName, String pModID, String pModPathLocation, String pDataPathLocation) { - ResourceLocation modLocation = new ResourceLocation(pModID, pModPathLocation); - ResourceLocation dataLocation = new ResourceLocation(pModID, pDataPathLocation); + ResourceLocation modLocation = ResourceLocation.fromNamespaceAndPath(pModID, pModPathLocation); + ResourceLocation dataLocation = ResourceLocation.fromNamespaceAndPath(pModID, pDataPathLocation); try { VariantLoader.loadVariants(modLocation, dataLocation, pServer, pEntityName); } catch (JsonParseException pException) { diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 00e15560..56a55393 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -11,13 +11,14 @@ import net.minecraft.world.entity.*; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import software.bernie.geckolib.animatable.GeoEntity; -import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; -import software.bernie.geckolib.core.animation.AnimatableManager; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.util.GeckoLibUtil; import software.bluelib.interfaces.variant.IVariantEntity; import software.bluelib.utils.ParameterUtils; @@ -33,10 +34,10 @@ *

* Key Methods: *

    - *
  • {@link #defineSynchedData()} - Defines the synchronized data for the dragon entity, including its variant.
  • + *
  • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
  • *
  • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
  • *
  • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
  • - *
  • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData, CompoundTag)} - Finalizes the spawning process and sets up parameters.
  • + *
  • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
  • *
  • {@link #setVariantName(String)} - Sets the variant name of the dragon.
  • *
  • {@link #getVariantName()} - Retrieves the current variant name of the dragon.
  • *
@@ -89,9 +90,9 @@ public DragonEntity(EntityType pEntityType, Level pLeve * @Co-author Dan */ @Override - protected void defineSynchedData() { - super.defineSynchedData(); - this.entityData.define(VARIANT, "normal"); + protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder) { + super.defineSynchedData(pBuilder); + pBuilder.define(VARIANT, "normal"); } /** @@ -140,7 +141,6 @@ public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. * @param pReason {@link MobSpawnType} - The reason for spawning the entity. * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. - * @param pDataTag {@link CompoundTag} - Additional data for spawning. * @return {@link SpawnGroupData} - Updated spawn data. * * @since 1.0.0 @@ -148,7 +148,7 @@ public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { * @Co-author Dan */ @Override - public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData, @Nullable CompoundTag pDataTag) { + public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { if (getVariantName() == null || getVariantName().isEmpty()) { this.setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); ParameterUtils.ParameterBuilder.forVariant(entityName,this.getVariantName()) @@ -158,7 +158,7 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul .withParameter("array") .connect(); } - return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData, pDataTag); + return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } /** @@ -217,4 +217,9 @@ public AnimatableInstanceCache getAnimatableInstanceCache() { public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { return null; } + + @Override + public boolean isFood(@NotNull ItemStack pItemStack) { + return false; + } } diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java index 67091901..49db6249 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java +++ b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java @@ -12,7 +12,7 @@ public class DragonModel extends GeoModel { // Get the Model Location @Override public ResourceLocation getModelResource(DragonEntity pObject) { - return new ResourceLocation(BlueLib.MODID, "geo/dragon.geo.json"); + return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "geo/dragon.geo.json"); } // Get the Texture Location @@ -24,6 +24,6 @@ public ResourceLocation getTextureResource(DragonEntity pObject) { // Get the Animation Location @Override public ResourceLocation getAnimationResource(DragonEntity pAnimatable) { - return new ResourceLocation(BlueLib.MODID, "animations/dragon.animation.json"); + return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "animations/dragon.animation.json"); } } diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index fcb85a52..1823e889 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -11,13 +11,14 @@ import net.minecraft.world.entity.*; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import software.bernie.geckolib.animatable.GeoEntity; -import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; -import software.bernie.geckolib.core.animation.AnimatableManager; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.util.GeckoLibUtil; import software.bluelib.interfaces.variant.IVariantEntity; import software.bluelib.utils.ParameterUtils; @@ -26,19 +27,19 @@ * A {@code RexEntity} class representing a Rex entity in the game, which extends {@link TamableAnimal} * and implements {@link IVariantEntity} and {@link GeoEntity}. *

- * This class manages the rex's variant system, its data synchronization, and integrates with the GeckoLib + * This class manages the Rex's variant system, its data synchronization, and integrates with the GeckoLib * animation system. *

* *

* Key Methods: *

    - *
  • {@link #defineSynchedData()} - Defines the synchronized data for the rex entity, including its variant.
  • + *
  • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
  • *
  • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
  • *
  • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
  • - *
  • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData, CompoundTag)} - Finalizes the spawning process and sets up parameters.
  • - *
  • {@link #setVariantName(String)} - Sets the variant name of the rex.
  • - *
  • {@link #getVariantName()} - Retrieves the current variant name of the rex.
  • + *
  • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
  • + *
  • {@link #setVariantName(String)} - Sets the variant name of the Rex.
  • + *
  • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
  • *
*

* @@ -48,7 +49,7 @@ */ public class RexEntity extends TamableAnimal implements IVariantEntity, GeoEntity { /** - * Entity data accessor for the variant of the rex. + * Entity data accessor for the variant of the Rex. *

* This is used to store and retrieve the variant data for synchronization between server and client. *

@@ -62,7 +63,7 @@ public class RexEntity extends TamableAnimal implements IVariantEntity, GeoEntit * @Co-author MeAlam, Dan * @since 1.0.0 */ - protected final String entityName = "rex"; + protected final String entityName = "Rex"; /** * Constructs a new {@link RexEntity} instance with the specified entity type and level. @@ -79,7 +80,7 @@ public RexEntity(EntityType pEntityType, Level pLevel) } /** - * Defines the synchronized data for this rex entity, including the variant. + * Defines the synchronized data for this Rex entity, including the variant. *

* This method initializes the {@link EntityDataAccessor} to handle the variant data. *

@@ -89,9 +90,9 @@ public RexEntity(EntityType pEntityType, Level pLevel) * @Co-author Dan */ @Override - protected void defineSynchedData() { - super.defineSynchedData(); - this.entityData.define(VARIANT, "normal"); + protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder) { + super.defineSynchedData(pBuilder); + pBuilder.define(VARIANT, "normal"); } /** @@ -131,7 +132,7 @@ public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { } /** - * Finalizes the spawning of the rex entity. + * Finalizes the spawning of the Rex entity. *

* This method sets up the variant for the entity and connects parameters if needed. *

@@ -140,7 +141,6 @@ public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. * @param pReason {@link MobSpawnType} - The reason for spawning the entity. * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. - * @param pDataTag {@link CompoundTag} - Additional data for spawning. * @return {@link SpawnGroupData} - Updated spawn data. * * @since 1.0.0 @@ -148,7 +148,7 @@ public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { * @Co-author Dan */ @Override - public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData, @Nullable CompoundTag pDataTag) { + public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { if (getVariantName() == null || getVariantName().isEmpty()) { this.setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); ParameterUtils.ParameterBuilder.forVariant(entityName,this.getVariantName()) @@ -158,11 +158,11 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul .withParameter("array") .connect(); } - return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData, pDataTag); + return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } /** - * Sets the variant name for the rex entity. + * Sets the variant name for the Rex entity. * * @param pName {@link String} - The name of the variant to set. * @@ -175,7 +175,7 @@ public void setVariantName(String pName) { } /** - * Retrieves the current variant name of the rex entity. + * Retrieves the current variant name of the Rex entity. * * @return {@link String} - The current variant name. * @@ -217,4 +217,9 @@ public AnimatableInstanceCache getAnimatableInstanceCache() { public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { return null; } + + @Override + public boolean isFood(@NotNull ItemStack pItemStack) { + return false; + } } diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java index 6084892c..1e0f85e3 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java +++ b/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java @@ -12,7 +12,7 @@ public class RexModel extends GeoModel { // Get the Model Location @Override public ResourceLocation getModelResource(RexEntity pObject) { - return new ResourceLocation(BlueLib.MODID, "geo/rex.geo.json"); + return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "geo/rex.geo.json"); } // Get the Texture Location @@ -24,6 +24,6 @@ public ResourceLocation getTextureResource(RexEntity pObject) { // Get the Animation Location @Override public ResourceLocation getAnimationResource(RexEntity pAnimatable) { - return new ResourceLocation(BlueLib.MODID, "animations/rex.animation.json"); + return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "animations/rex.animation.json"); } } diff --git a/Forge/src/main/java/software/bluelib/example/init/ModEntities.java b/Forge/src/main/java/software/bluelib/example/init/ModEntities.java index 2825e2fe..6f82f193 100644 --- a/Forge/src/main/java/software/bluelib/example/init/ModEntities.java +++ b/Forge/src/main/java/software/bluelib/example/init/ModEntities.java @@ -25,7 +25,7 @@ public class ModEntities { .setUpdateInterval(3) .fireImmune() .sized(0.6f, 1.8f) - .build(new ResourceLocation(BlueLib.MODID, "dragon").toString())); + .build(ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "dragon").toString())); public static final RegistryObject> REX = REGISTER.register("example_two", () -> EntityType.Builder.of(RexEntity::new, MobCategory.AMBIENT) @@ -34,7 +34,7 @@ public class ModEntities { .setUpdateInterval(3) .fireImmune() .sized(0.6f, 1.8f) - .build(new ResourceLocation(BlueLib.MODID, "rex").toString())); + .build(ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "rex").toString())); public static void register(IEventBus eventBus) { REGISTER.register(eventBus); diff --git a/Forge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/Forge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index 3b905d28..baecfe62 100644 --- a/Forge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/Forge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -41,7 +41,7 @@ public interface IVariantEntityBase { * @since 1.0.0 */ default ResourceLocation getTextureLocation(String pModId, String pPath) { - return new ResourceLocation(pModId, pPath); + return ResourceLocation.fromNamespaceAndPath(pModId, pPath); } /** From 32e45fcf5f2cd34017967a5ac5a78a4eb6c2cf0b Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 4 Sep 2024 21:37:41 +0200 Subject: [PATCH 05/62] Fixed Forge 1.21 --- Forge/build.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Forge/build.gradle b/Forge/build.gradle index 340258b7..2225558a 100644 --- a/Forge/build.gradle +++ b/Forge/build.gradle @@ -2,7 +2,7 @@ plugins { id 'eclipse' id 'idea' id 'maven-publish' - id 'net.minecraftforge.gradle' version '[6.0.16,6.2)' + id 'net.minecraftforge.gradle' version '[6.0.24,6.2)' id 'org.spongepowered.mixin' version '0.7.+' } @@ -34,7 +34,7 @@ java.toolchain.languageVersion = JavaLanguageVersion.of(java_version) println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" minecraft { mappings channel: mapping_channel, version: mapping_version - + reobf = false copyIdeResources = true runs { @@ -80,6 +80,7 @@ dependencies { //runtimeOnly fg.deobf("software.bernie.geckolib:geckolib-forge-${minecraft_version}:${geckolib_version}") runtimeOnly "curse.maven:geckolib-388172:${geckolib_file}" compileOnly "curse.maven:geckolib-388172:${geckolib_file}" + implementation('net.sf.jopt-simple:jopt-simple:5.0.4') { version { strictly '5.0.4' } } } tasks.named('processResources', ProcessResources).configure { From 203871282f81ca6ededc60da35a9df83881a4f73 Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 5 Sep 2024 14:41:38 +0200 Subject: [PATCH 06/62] Added Logo --- Forge/src/main/resources/META-INF/mods.toml | 4 ++-- Forge/src/main/resources/bluelib.png | Bin 0 -> 145980 bytes NeoForge/src/main/resources/META-INF/mods.toml | 4 ++-- NeoForge/src/main/resources/bluelib.png | Bin 0 -> 145980 bytes 4 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 Forge/src/main/resources/bluelib.png create mode 100644 NeoForge/src/main/resources/bluelib.png diff --git a/Forge/src/main/resources/META-INF/mods.toml b/Forge/src/main/resources/META-INF/mods.toml index d79a67b3..cf09a122 100644 --- a/Forge/src/main/resources/META-INF/mods.toml +++ b/Forge/src/main/resources/META-INF/mods.toml @@ -6,8 +6,8 @@ license="${mod_license}" modId="${mod_id}" version="${mod_version}" displayName="${mod_name}" -displayURL="https://github.com/MeAlam1/BlueLib/wiki" -#logoFile="examplemod.png" +displayURL="https://mealam1.github.io/BlueLib/" +logoFile="bluelib.png" credits="Anyone who contributed to the Source Code of BlueLib!" authors="${mod_authors}" description='''${mod_description}''' diff --git a/Forge/src/main/resources/bluelib.png b/Forge/src/main/resources/bluelib.png new file mode 100644 index 0000000000000000000000000000000000000000..1896bcddc2e07570d39d3922ac91b9824e85c4b5 GIT binary patch literal 145980 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%0D$ z6mG^tkInEVobXHpH|Y2b-LIY3&HKm0xE@}w`y@;nIlfxw5_ZksnR)VMCa++o*JA}b^-cDbOhd1GDFFGSTr@_xM;eF?ZwUoTf4BY&FH5fIp%Z3zS1d~n(p7_dd zYw`#^dLoBtrxEWETEb4-7Y~2JeY|fMEw%_R2O>AifM&-MFCD#|C%AWJxMv4KhR7%d)iTU^=Y2mY^d+6;{!=wH zZF!FcO^5lD?jiA{XQeB62AeV9MK&Swsbu1jPY4d^JPT&I&U~Hrm5z5`F2i5Md@te% zf33dTAg(Eq$%etW=$DS6KXx^s*}mky?x!`r zaCD;k4?JG_+5e+xDHmk0kBpkPcR)rIKDM#P4hq^nnCQ1^@pRJz64PWrUSEAt;j|Nr zIz-uh-1@;~zyD!%f`F~mWKmKHS?3V`v zUazv?M*MY}?9V5!;-$?*+MqTqmC;X*z78u?}~ zjdSRh76vblS{mCzmb`I?2uGX#s&XXXIDzjyU5**WWrbEO2c*u^<1m(vOdeb1Tjge4 zDfQ$bd?pbF=n)T3g*Fv?4CVssA}$?6Z_)~H(fy7GenRa}0~0rSKl9IZY{E)8dI&2{ z;7Np?OZf_I>qxD1i{sdE`-e4H>bQn7c};`o>h7cL5#0F^y{Do+gD-S;o@g@I!HR#m z0&MJ<+=dU`cFGAHapZx9_t90A8xsaM&u@IU%qV}at1c)PCJyeQT&;nQqp;UCalWFX zF}DTL;e7+Yjw*vS`WntoPM4Xlr;{IWK+;R<;JOPRj_5p!5B~5*HaNoL$cv3W@z4)1 zleO

E7FDPw4r|!!ah16f({!e%}vh1$IVxRs*0zKc5aUJD)RXe zl_rV_3e~161fRjjbokV0$G{P!@QVT>??7-yxBUj?g4srold2Caya{#Lrz5m94yCVEBR>6*+)@0+&uWlShdmgHy5e_WJo)WK({aT03(Cb(I7Ciq z6?l_wK2tW&er8!Mj`RBn!Pw(9_!<{oguSjRZZTcPZc+Fi-&qfm*&0l6p>UpbG)a8@ zf1$R=Bq6}(PyY8Bgz84_2_1=m^Da|yw^JsT0%+`7-st{7BTZ<>iR=bC?`sc}L{t_bonB1{d|H>$88b=y#bA4fBHDzV4%Ka~`CUkAy{uD$4R24MgwK zu^LXYnq^Wr_oR-Po?3j2vdAQT=Qk-Yni%k%dNI=Xz1&pKP0duEJjj2|z4O8rB-D_7<*<;~ml9jagSBoFa- zAAh5R&chL_x55?$2 z9)u-JerKN#3A|NAd`#H&fYZ;U#3_3QP7S0tX^^;49sQ&_M~)VlSkFG%{O$UPmmU{x zbOr|*{VA`)C+{Qy$f;ZOZPmZhg9dX68Am*HMbG@F@?Vo*;H(C`mp`k#)L=y&bU(Am zDU}}RuuYnsfc+@qINFTz9pOD%v7dfGI;y@ogMQ}U7IX7810o%rcSSsTshiQ^zf>LG zex&Sn*c)ZLiw?f>F!CN;=?)n_Cf^ep=>0AV?Nq!}A;(S(`aB%-^5^wP^5;;}K#aWW z!F>&Y`njkF2VQzYlZTG<+}BW~wzdV3Yp+Mc_6%{;7}4Zi@y`!LfC!9jt5h*(8;J&aGV7*SiLQfa!6Q8ag{Q1 zIYA>%XI03m@Yega>tKLTe7u8D`Mdp$_yo^CE}ylc+yZnpupM0-f)71m@ut4Y#9$lg ziQi(vMJ{RQqja8B9zOI_m8jse|5*9af&n1E3}QU}`lp(tPX1ykw@nzxihsTyZNlO*&o5zrS z45jiI?TYfQa>b;f*FkWE!s9o)xiJWa7ab`FGLkrQftJA*b;eVdF6+)e>xm$E#ZTU< zBhqg>$j`gKM{)W0!2QhyK3GP+{PL2JbKa8__k;nNMvK-m5gQVUPh08s=Q)L`07>9(2Xaah3HUEpefagvi2}IAMNAjS=zrNJA?OvA06H0+d?iaiB6d zf9;eGMZ;r7b_kH!1v5`OQUy(rPMG58p{>V1GnYRNH#(q59wbV4 zak^~6?))VoKKO6^$Y%4PR)rm&RXM(DNFDuzElH$6}%WnZyM41wWK#kmue9gDmAw-Sem~ePmL-*Z~{%fA={Qi*X|?bX34gaG ze}IsdR9zz%2Fbbp!xTM9M~OoG@ZvZ)@!;P}kA!&&8=on=bVJ-l3!X4>_@leyz`sSH z?pXxzv|K*-bLre$RCZYG7!wGM0Z_(hz*`{PXiOnc04apvjtckiQ;u%jYV=GT3=|X! zm5v=c2FFyK33Aii9b5ENO6p-WCJ>Ud$;s|zO(N1m-t7yMN6Ja+4NW(`9-@bDSJ>o- z@9=^jnK}?YrNQ8i_o{p}5YRwg)sKmU34=J3$N3jjRw}Q1zwuxox=yRj>oss($N&`m z3Z1_)=RvZ}xd_R>(j9-`4TP=KL3zh_$l*x{N^u_pDg5AnrZ{z3z+m$w)iH+6qp0nZ z7C&{*%wToGxh)7s*%NnuOk8-t=f-;SimC46o!_E+01qrWAn@Ys=l>Ok7ahq1x>(TM zsyg7FfqfJYtN1Vd$&$vF{ly3TS=3mO1|b_^y|CHuz6F6|W~)YztWQPBjfiWy4T5iN>GA zbDZRKF61%L{Bl0QOW#;*gtyrUDk`?Z5aF+Q+Q(3lNO;Bi@P90JEx0;RMlXJ*W8PvM zJF(eSfDf(H6A!J+TxOg{r+N4x3k4PcPyd$c@+&rh^a@tSwk8mzUsIzRH>k-RnNCpg z1+(KC{$5xqK#8zY%8rAb4*F^AVPW#%<|M~e{--zHCUO0YLV&!`=_X*{u)@ej`NX%D z#3y&AHR6Q3@vdbTLM0v>%KzaKJ|W$qB z0|UnwJef5n5LA@iEnCuqDx1~C@!&uXqT(}HsF2|e4{80jSmfs^O>+0>IHkk$S`A-( zN*HVv*sS>Na}9bX6_4u|{bk4Lv;*N7q?uHWmtaD4_&tsfEIg#yMey_yJgmy?G`baM z;s(dNQJkmaBdb_e{XD*lf9wb{!Px~a;0O|`ebYwR8BjN|VIEy7TgyNXQow+Zylucx zx=fT$N#bV!9J`V8nhdxIDSaeC~Y4&>N3Zjt{FyoK0|oY^ zk07>@M~Ufc%8Hjx%NxdYw5}KO8o*DbzVL{2YrxtI*tH`|m?%El*Afo?_A~1II)?Bh zDTWJLJ@GRj0AmwmH}aYW2I})_`F{fgUI+17OmYra(k>&(WY?B5?tY`v_^#VXU95N_ z$R1@$*}wlkU+TVdoYji?($oRmHYDS+@TDXuV+JsQ2?E{9s|Rt#IqqbjK+ua4{NV?$ z0)THm-SBRuh46bEPwIb;{L6)AgV>e4ClBf75!q8}x85B~H;Wo>wsSKU9D^ph7?2H; z9bt?XozCui6O#2xUW~{_WXLJPWWz4qN2D;Ii=X17UX*mY%6ISx{nDda+&r!}q(ud~ zxNk?>z#aoBH*YB`>ykXjXvCqffqnEvRO%png(KkT7j*oieg>bShUhS3kQGMfgdWMr zf+%^Tf>%iNp&wC*j}7?3z|+4jM0k&~71{77eVh=Pqx47bQG8{Og+9Ar!nAQ7Nv2Kh zs|**Fw=Gw5cr~{Txhi1eDsPyu9+O7I`-@8cof0~4I-TR zLdyAU8VNR$I|QZ2fiCd)_+n-(;e8zhKiM7e6pPDbHdwZ1)ug#!!cEMb&>HiW+S19H zJY_`3W<^N;Z_*%l4XahbB{h^+gm;HWmwxV~rY;xgH*4j^{SRm-)zIGc0o|O|VAml7 z7N%1k_~bN<%|Y|Fw8>K%+jH(iy!wBvP))n z{Kel{bXi7q#IYh12~Lr9@b1)A4wN%E??B`u$F{U}|HCSk%^G9^yPye{Qvt6yOON>} zfB<$WFNIvI;GO^gAOJ~3K~&_`wv}X3<9N#H;&;FWT`EUhWT3|dc;5iDAJ&Nx*JW@kjC12Djb$m(ff(JkR;-~t-+X(6byC9jVLK&4;{1o)o|4N3h zcpWP4hAOmGMPIWAJ7`uk%$O%NpwTI_YOzfUK$S^nd{sYoJ=wC`9Ck{Nf~`2|R7%We z#XNi>5~2mBOIKbb@|C=eJa;iW))9)A4JvkZ0zsz9Im)H^cF%Wfpx5BaB*Zf5pq#T~$$((64LP_|(UX zVJ(<-t6YZbu&hMy@R@;m#jNC`tmDYR`6{3S<%p0MrRWrjVrqiRz`i$^Z%is;?Q5eG9|=< zas)jP6xuhU#OvqP4;{$N$Ggx8(cwX-mBo?L@`KLq&t#WRmLblsfs>s_v@_aj-~G{L zKw`9D>rT3MabWIL%H7I;#N!4rQdm)A9bF!2~Dj4nu; zJO`~v;v*ElClM4N+vULl!4V?315STfXSWX@CZ5x(%I`3ol{;#-uFtdqu{$l@?dmR)NEQrY4UzT6Ak~9gU6h05}WXn zC`cJ4O^A&*83x3c$;c*<16M!exah~ikw<+ECRDr!9ba*F%k02tD;`h856OMB;;68n zL?O8C~Scnu{tx4oaKck8c`Y&O5B*hEg}aEE=EGI!D0$8Vd*eC z`Qx|7D~7F(E;jt&En03mGShn?5&pQ~f4YO=_&5m~&87Syc+cO~p!)60fQEf&o_uw5 z<+M;%DcZe%Q@)+iXU_l0GT@1H0AivpZq}sDu?OYIaRNtL9DSv}PH8aY;RS5J^l0JH z0s=#85Io^7zL{sz!(jHn-_r!B9chP`HRz!8HFlut7}u!TVgiUtBE&r)Do<`lF!7_z z1mxX$q`nKlKcXc=(9o57g~TqzyPdKJ4zMoaoE_O@P~`LS$XXs-`eB361*EubDh!0?Fq50; ze#BOx?;DBP{Z47#L?6euC_y*SbS?;8p~;`B0)IcuZ7;kKi1QP#Rds#f>WAO)Vc3+I zAu=T3Clo&u>&*`>3xXT(*Y5nY+F|^no>=^dcvRONINg9|Vf>k)Z#g|EX7t7m#S8F{AaG0Mm^TMC$T=?skIED7W zzq720*&cB}#Geh(3W(zsb`8k5BU6})>(3X?9(lW!RrFX*io}3SXFadU!-b|wN#hv> zj1HiDg1#s=c8QlQRyJEJW68J?c2?P-=25p3uu%-;husJN2f;Tk6=woG4y0qd6HEe_ zFjOS|-2eSLw))m(g;tbp zt^CO++l=Bl6p_4{$31$Hjg$6Kba(KQg`b7Mo2p9&a3&D$HE|z;y5{(bC#hV2vVRC< zjGZ+605a@Y(k^L(Zg=I6+blk+U)TlWMY~mH;MINdRr=^tTZ@%Ocb>$@(}>hnC;kgv_Fqf6wdsk?fY*twdSFXZR1;)A=Sh3AyRV?0NPRnppl!yNS;&g}|`@I~QcO zDoXkpr1-EKHw``D;e&p|6)FUjD#x-#U$E^;2IV7z4ZxYJ^FSaS?yT^jTe|!YkI;Qk zFiNbXL5T+$@^(RujVH1CKyJAm7ghu#FX1_az{o=68E)=-q|KNKCN?o-u=K4%7G&Vb{`C!*k$md+~{B~AMw%o zut|Og2!BO@d@paM@BT3jN;e+XdQLu)#|xi6pivL_m#3g_eN)i6MF* zQI9;L%773VLM9KFh43BR79_~v!7(g8QjQ$GzVNAq6CT^3eF^Z%Z4SKn4Im4=^J#XF zrLM6bd$2kyzAXCQpbp7X0GfX3V-_g>EtdF|5HWls6o38|g3C%gs9<5n{i2s1Tgr^x zDvPOwsIa2=eYO1JsV=hW2Vc;U^0hLv8)u_s+gQ!mDNX zU4Lci6P{RwXZ*SCVb!S?BX8&^EIl1f`tS|@z;9|jBim4ZrG zybgq8g_(xNbJf@;opR{xiQ}#ZHFQq-3XgRZ?Z&(Hh~eL?$)j*IO6>7Zd_MmRDq~H; zr|(_-2KSyH)e8PQWarxD2@|&I7k+U`Q!l*l!Tk?|{9wg&PLnk|LIwot!S4Z(AJwJJ zmTeyUjo*cGI(4!r-EkcP6CHe&@pYQm?*FJ%PQ0&Z00LN)T>ShJ-@3-nhO|mu7+_qd z;=%V!3MpsPMC$yo^0W$NLRm7XeDU`e<#YYUS9a5W_d_<|;UzTQ7a3p!N#S4Dh0=A3f0pe}P7ov6hP@<;pT z0f*D?SDV#Xa_&);`SY@&KF-4i8?{wz`yB`^3gVMu1|F;4Dt{&UM9bEj=arAes2FVA z;s^S`30On|^fAUBCL?~suG*pHiyz(rBV)pd&c6s?!t$7;Ho}gk*XfY^N=DZFUhFH! z`yho_JPe$V|G!E|;a%!nJT=8c0Zgn54x|c?|5(ONU{-P*cd^~)Mj|V6b{$k6s}%~$ zzou-fF$wRNoiqq~pi|>u(xBq9%C;{}9>+M6V1Qk%MA2If@2r-%I6Q1@QDq! z?B1EET$sF{6V9Dh<;~GmjzRGIRXUsStPs)9Zf3lAbfDHTTz6f>_bCi*tGJlzYXqqC}75436ceSGCg3 zSvkk3+z99CFL;NZVN5syJ4D(e^~S)l>nS_0>?LbcgxJTnfH-=*l3!51deNYK17l~f zB&~=6|NPU^BcD;6@-PcNUj|TS&S%Ns+pvi)e3cFOC^zRrA**9PFGGK(e*z4AW)Ks* zU@xBVPkK&f5hE7vCHlb8WM|K z7V4ZN5cj{N(86xOl77 z#KQpKl@;k7;6Xfm)qqEb6#czF zv6L$}YylcL=b)eexbAEGs!_{?nKFSvG;Du6Npap+;O2A6$1BHk(uGg( ziUxlgzg;aF7CDpUJT~<;=#G>g;`tE`P4RueI~foCyNiD_-z(L5UVTz|Q#}58B2=CM zo6&`kvKr+I5grp1C@hf?v5(3>av_3y@zI4}*rn|jPxz8ICJqmp*bwl95=T3$ARgH8 z&pxU@L?8U@WT=M@TMu0zFIj9;4%CJ3O@UK-DF}tc17$OL11pi`zG ziKEX6;WTlO4~XD64t+zDE|bL;h~~G~B};xeg#Zwx9_cea9YDW;zuUdx$-eZZ zoXjS@d>@QF(O>CruPIzI(R9wy*qHD>O4Io0Hln;<7Eqw*CA<d5L z7%u+4CIkKKv;sO3t9{Px_}|gISd|Ws9528 zqol(Js^DDciqk+?4Y6&;j$e4(Qz(|Bli=9IH|k?V#M9&D1G_T@Sn}%*B0Y2pAN}Af zG6lVJ5O;%wuHU`itKHpSQDdym0G$;Y?;y~KT~4yWKx0?A=;u|Cg3zDb!pD_3lBGmG4$4QqjC)H+d*KY=1 z9)yPp`W1GNK;)2B+-iL>b;&PvNf`)lHgv$F&_0r0*vHlF6ujiDxA+GGk+KtBP+mM~ zapQ89Jnb$2_X9d$n+hp!>#lOOkKl`k|IHB_iW%6oQ>R{hDP$mI*H4}K-iWxs8RXxn zgF=m<<;U5myx1q0LNC0_N_xv>IZ-^Kr!1WpF~E~J{SMY$;K`?K5cmBx)h~S|rY%cC z^a_SL_bCndl!+G+gR&i=92n63)SUV?yENLr+xa%@=H<^#2qhWI9{iDIN6-D*dp@?j zX#1IepgLB693UTAw6V+a#!!%>AT{) z^zGu;@VrjKfk5IYFUNK@QU*G2M>VN%{+<>=BW0!Z*w2;HWKba!1UDeLcfqQHG=)zm z9d_bFLg{l}eOW4s)fk-@`#edp3dr*-xz6K`w1V$ETk+^yDg&LP!i!JbkmVfy$zN1w&_s%2@aT`QpL7vFW$1wnz1UQT3D9|7 zR=IG`!}2JAuNcMz4GtusbgTi#2bA}CIjPA+;m9ir(AR;qGq51<`w4Ye@;1SXs!xEO z$Hm8%I9Hb?Z6taL6DNvp(Z`@iI`$MMe=dhU+DXUAv-mtvN;H6+WuYObkU`w%)S^+w zE)(ImpnR*qddC1m8A}&CYwB+cq=&CKvkS@21Rd<&{bY{f?kfmE(9bq}0a=hd&UleW z87fYm>^hgKd&<(~fb8@eG?7xi!^DUj$Qd=^NiuPcPZFU^u*GJl785KEd9jkk(e)ZP zm`tg&)afF@S^UO09k zW)Y5o>`Q;7enKS*naXAb!Dp12G(35*>aK>{)eckW;-`jAr)9N6#W7)c;zB+0L!fB^ zhkv_Z53T3f14q}fq8C+mfsU(4@;k)9jl>dR@VMuDmrmi`g_KZU?ARXp8SyAzcCibh zUwCil6>`rbI~TN4He*0kn$_3HX4eCAd;+iESk*!UI=_^#OQeHQ9=&|b8s3Cfuzq3Z zbnkaJ9gXc}j@V?2$%A)50v>{}3DK$abR^+d0-Df9f2 zr%?}Gf#Te6jBSTKzm3-eaiz^t?ZtZSw1_RtP6YZ~wpN3WP5*Y{fIu6fy;+Ci0}#fM zgcaw=>G7Xm+TbZIW*BRjgnWdqv4lZ<=QuEwFA?%^{rfkYZ~Q(@8pv)re87xv>^8lN zU*i$Z?J4ane#1*Vuq(Z$GcrBwy1>u+I`47fv%cfV9Pq46AR*2fB0b~6+e10T8GgSR z$Uy(-&o1(A^wp_YQS;;k74CCMRiL3|ii%@P#}N^e1|5!_22U$6KyJYi{<)ziAF)BG zpBwL%vdc)2pVH^fhA4Joqs0duo`C4wG{5D2ngBGZ0-kg~S(C?tasx$g)Y^v9lrP(C z{yzkhF+iuxxw1P`gz#ks;p|t@yow^e#*1v>xdF<~GJcpe%aF$QjE7nHo4-v*V_HSd zzztC*Jb2FinS#Ep@66IWR5x2=au6@^F#*>AWmaTGgABNRBw>Wn%SHGtdfB4g&>kQE z1^KDn0_DCFs@{gT$2V1_ zi3W<#1MnCv6@-pd6cfTZ{Wi}m70o}ff#%6V0|+-uXk4r~=%k)xcKImw<3McV7ahl) zLm__kBcENm%r|wERJL8?GW&?JT_E0jzei7&=*Z7URN}*@7av`|bw$48bM%t7N-k>H zxz{tkB__1rU}ZpqM?YL5Ze7%Y;_isT+g)9txsIu40D_559b5``9Y+tE$TPqUKjDlH z;ww5pVgI3@ROhWp6V`y=K39ST#`!-9b_wlcp{%;=@9}N1WtA&j>KyWx&y_wjpqfz^ z$};*1`3c8jhTkCwZxOa^iROIJmQ;t{MRtDa<>3o_wH$R;W$HA%=s<^sE>Gb_7E}c{$%c%p8Ok*>3%B1q-zgcjUDWBKR@i;pOFKp$*)wk6V z*fa!UHsGwtCxEd58@E2Z*k|lANS8s(<Q66eVmhUT%?+pIo7x_WS0)jT%=iL_cOg;S zLg#}t`U29q1<-=)d|OOA61(KUAEoOk`VNzO&>De&IJGOTM(c)f3^cMIARHruBTxx?38Z{JeFJokq7VrK8)np(EG$9K~isUVlbg z=$}wSV@0Nh_u#i^Mf9`Fi2RID(o9RDMXigo=R6HGe1o+Z33|2% zNrW5DXadz_I|Jp!W5#sYmsAc+9t>=wj!X9}cic33*6PAOcW1Fl`C|`!!ZMU{@r!}b zBb%~JSr`AVfNx)Uf-DAn;{`ka^B-(B$Yed2#l$vT2|like4sPL=vSKj0tAo`l@rMR zBPnK=sp0`x*hRw|U%^GT`cae$<7AN-FLA+EN-WHlzN1?@?PiHG*i z6ALFAcj~D0*6&ciRC~Kx`dp{T$_{UjUsPLTM{`pBkA*D1B2cD+n5nYbR zcn{^NUs`sEWqvEL`^iHnq-Pv7@;L*1z#46#9O&AmH++QfsBFFrP!mWr$MK{Ig>z+h z+>SWgL$-{)pm;&YjS@XOzz*iH`z8>@5Gzm7KYZq4s}j zYn#&`$=ewX3iiib2bY(%ss#M>)n^ouBZqW==yia=42Oh@0l7xosjB!W^D&7aDgoC` zl^>Hk>5-RSuFX!|n^9iKgs6}-$G(R^g08bDAPrN}O~CC$X|e#=HwKaJn<lLXQ#oxdwxNE?);}Es~yLsn?#UJAA5-ozrQ-J8RfS3i==UbqvHF2 zXtVjuKN4>M-vJ6kagx2wKr)1{r&EC7pi@UU-tkHvf?k)%*{H%U*W-s2TronWoeUin z?z2@+@}Wh(ixXAM{LlQh@*{dWVQ4AnHMLufO#(v(<|HaKZ!08s>{%&v`1NB2Lr6o| z2We=Bc+epvD)ZC~4cvKDg`)RbGQ6YlBQ01V^@G94&}Q!dbgBOVAYVeoSp zJ>gU6_6r}l&`A@AjxXT{-{Yi#;JUofd@GK&W;0uO2Zyi+Q^60KAP@Q7d<`RRig$o^Au@WQIWHV=SMFZ6wv31TI;6$)>CvN`+T z%QEeDt2~fB25=ALq>j_sK@5<+*VMl*Y5;RUjKAVI|F{-x8lPBf<(>wU2*x6j98Zpwr6%Xh`fD8c7 z49EkW2Ck>gaK)FaH&>nd?-ngFierfrD(wnBhVl3On9dgOD}IUc=?%V}l|mV6N92G8 z4|Z&;h2mJnf#348>ol=0@*CH!S0N39Bc6HHXKv}B!SJ*NZ?SR?&EP&4JUVz5pMjoE z&CPFqOdi}2=37cU-swk_HBcu13=%wT!?WfzM9#jEVG#DN;kR|ql0bH~&g z?~J?cyEdEm|Bc1gO#9-OlphUVFMM1b{d0|qf%4DTGU%XaE~n~TE~ns|8b?Je@fKP1 z58aXNAw;FqPOSub`VC>?#Y+%lu+Bgm@Pi}TdGX)y`0%LPUFl`fLtT3DBjHg$6`%Ds zhRa6)03ZNKL_t)U9zKX=)Of{bA4vOG1m_K08X7u!oOA>D^Knr=xXC*mv?uGVvan7e z5_()ghnY$lbma0YIxHORawNu0cRpv5wp@~10rK2iL;&hv4(5h zujM^7^m6RQgk=zsdn*2vh$fqJPb_@sML$Pb=zjKhi+>7|PiK#O)zA4&S%QN>bdWf6qM@c_&nl5RGv5T4LF|CPnnDuF0Y*l;e0IAiAN(r666(ZwM9B?d!umR@kf z1cji)NGmxKAd6u8(10!G1-17odvOojZX7faDoOT7V*#aso|hk4S>$|`mz4N~y}!oV z4N=*eD6Ur{V&%fBg~9Yqh5jD{vcam7o7nIBJImv_*aOH9+hZmv1`P&}FRBqf^E*oe zH4oK7S>f}@z!E2!VqgNJk#k<|4kml(W1z`kgFb){+PVBCJjyhRU?5)UK?mR9TCL>x zoD5Hf0hg3d>_*PWeu=X!Onx5x@#aU9d0jf0JovWK1(o5EAfKat@PYuyPmdc}m&$8| zJL{HQlW~1ek7dwDSJBh>Ml`evJs=b3hmP`%cF6H1WywN-Iy8tcb&>XiEQ=KeQEnjf zC@`N8p)En{_sU$>;L2a?Y;k01CvJy}MY|TiJW!R7Cd*GVv@#g^=zP)D`4E*ao;U~t zC71jWCeOAdn_k6Bh9|Drq0?WOP?;dOf5=XNg%mi-B_C?ET-otgr`4wTucjR+Oa5g6 zI{5w>{|o)%*(ICU$32e|itvpp{>^c|j?Ib7{XeMh)BS>YTK*+w1qnxaf)*cs4R)B4 zpu7MJDyZ}rr$|Gi9(F-=&GgbaY|ZqymR5;JaY7s*o^YSy<}4M!|BtpBU0CIFe02yU zLjh8d;WdvFia{%(t%ek2SJ>?1??}Q+qUoxn2YLo5(^Mg;oSWab+`pj#2DqQY#|r6W z9+)XEbnC~Ps)k#N&T3o}h$~kE022x?+x^KuSQ_`kKc(`yd6}pfB>3SYlgyL9qNw;; z#RZc0gy7xy7+ml{fbXoDp4Q|8c*mhU5jrkDCbzC*+^j7f$hGJa?+6$K?6`Qg-dlY6 zfZeO`S9$OR%D`vNrZ0MW2)`z4{_n*a@Sg_(?j>z~G6EfRAfW48Fv}p*NcM#bym72} zw}R*d+4*84%+O}u@Em1BqGk;rp?*%5P1+Z2z<9N{_`)DU`5Gj^LV$OD*nKjgQ_p-l zhlKu62}%Z0#t-@z4{z`U)=Q5r$~gVti`3DN43i_Dk>>`v``p5M_$r;ehsBSl zM)^m1?(^jvHlNeP#lKiMsT~W)bsX0}pj|YJ&(Hm=RKhDh{Vk9PVd)`E{>-E_y0;*_ z;Ps3ma-{9dBS%b-br*Nsn!SJ0FW@sNvE-xVfTfv^ZL!?Qp53&Zv>*F z^g7U`k|PhJKto7~xm|H+y8!>Y9DKsLA{1uQ01b{aQg$7EyK9;*{O820KBK|&!KK4e z9BJtA45&^H4WNT_^Nq=e=lTEee^@3Ej<0xx@xJd<(;_#FlNrTc%ehgN&Ejzx~r8JWy zlM?q_e55tYN`YM5g6q%ds8AEq8u0lN2GUo4Pt+#pyt?ogw9P;#5}QhIb+m3EJi(Dq z^Z})Zyfu^C3FJj|piAnRbbva{Bmgdhp6Q(tL~OzrnsBM-)RFTY9_*@}nMd)l7!dsi zwbNI=xYWVoq}sLGV0I?HKS6$FEl64Q5GMV+sENQF zq6C=&=Mw{hl(owUT;Uyt$D9i-szD9e&O_pFa9mX4bp$p8Tp~SaRkOB^3<=W3|UldX=(`wWMYM(qf)n)grD+L z=yEpln3vew#U7*Bc#76Ji3ONgz9nl#?5|@c1ywSiGdei+K2n z4?wOGt90q%c!fz8K6q&8{Boql07c$`t2A((P~P9r4#g8A`C3T6zWawomtSjeLFM$i zCXox8WCzIJX&q5uDzK#CY(qu$vH_et6S8LNM^DPS|B! zcf%rQ8=!?_0_7~<_pqWz@|hG8Vvq7Bd?RHhe*2bC$x)U)j_(D|TTg>ed104dmwhgi1v`NZN*A`9`$Iou2&NUUbtyh35i>1(rfn%Q zX8&c<`<8Sp7E~H>21JjOWYnPymTYW&V${Hk2uH_{s|8o zg9w9k{1ECOj;?~(B$-Jlv>xIgH~RB+52!P*0Y{7cE3Kh^?tjM2tGIYt)_E2M<&5U+5nH*GpT04?h9d zAG##K1WG=<>yxYjMWruaO9o%rcK?<EY^7Bmir`ke(N%! z;EPSiKE6#rd7OSo_gyrJ(B9tj6MAw`CkT16aj=W;mJcgy^kd4YbPhU^j>C7QUAM(F z$V5apOU2C+yh5S|m}p~x(wpR>WTf^-X4(DRp;jwIxI@yz(?*;PDa~7)&;5ZahEd{D$kWAcR+ zyl=WQaL6y@X>@*RPI0#dWQ9w^*vc+66iXKarY8?{X<#A044mM35^M})<@+c<_y@}7ynj*Gx5GQdif7eE2>&HosG{?ki(K`!}q9U(^>QMoesGwAbT zo6SKhyA-$cNhpXrPQa%h<$AS37Bqec0zMe^^D37(yn;mEpiP$i&JY0_afA?w9vnkI zv<~2uF1CfTl_+MIq{9y`fZD~=X=N)mSpe}5@fZ{Ggcc$9Gx@Ci)-iVJ=YN3kvg~_* za=AZ}HU+uVV^K;qW_(0r$L}iMeG3z9fwF1f_EEU7^_NoddrZb%Cpr+AaZUG;(KY$u z#F5frU=*tO9D*j(axxVVsS!%Xc~D0@r@`ct|MT*016#A$oYGp8tUM;-li#pcA0-SiKILC{krId2oZ5r2h|b3GlCT zd2*^Bak&97Xsbh7PjiMSs}biVbacuGKjtVL10QdQzoFH(ed`TO{-INUhae3Pn&1DR z8mTMNYRC-sGN&i>Qu4a zK)xx!g!l}%FWX}9VdqFdUkAwy6cKbNG*0oGA3R{D4)`K3-;SDna2_S(8{TR^OyH>U zKMTW#6&{oi$wCd9(_CbS8}S>}8~>rwpZ`#qqY#|{Y{VT_qVGJssDfeT#{g)Nq7erY zE~x`V@CjYcNx(cD8Inr`9?>8lf-WCo!!h~t3ux#Xz=ZO^52dH9f@$4UIGJZmM<$tslnDVQ!z=nd8oco@Tk?{nMUVduyqwPs=Cg;H;)FD7O zvVl1r{JszwpzB#M^Ocq)h`^FMxZ*TGm`oY5T*eu(l23ko$t>Tq^7*QCl6e=9&gCB=C=4kg~(~tX@|>upjc9bkOJZ z)6Q=OjsSMSMU~4%j;AEglP)eF>alFnQT@O`DHwwdc=!Yis=lvOc|NWBJg-53|4cW7 z%ck;zE$V!%60s>r`S@sJK^^~^a*9OKvcsy^|9C7kLTr}ZfhLVyLdCtqReoLPmGAK5 zFYF1uD}@K7K*h2J+)!tbgb$W2^E0B-OeT9L5z&Vz5j804YT$$-zFdeL0DfmMHP(y= z{A0}Njy9ey3%aKdtn7|)n!vkjj05-mz-IG-|4?!DDMQ(zjnL;m_y4G^X>2)lpN_x( zRB_3UK1zP8ZbtuC;oI%_PPy30C4WJendQY#^a$a641(+=PKEXkYe%OGyiwjsyYS&T zimvV!)+LNnq{i%yaL;2E1e`Y>|&gz}jpdatm5s;6EWScJ+Z#8`B>t#a2^f8^nJeo*0oL6uf44A|j zAboBw+$eNK@zr%hnWr)o-D-!0Z{($VB#Up9H8&?ONyjDGvcJN=smYLu~~}Ek^H_zFv6J$Hc*d zFpvM-fn6pKFFZsa{AGKL17&!;r$Zj3J4c$Z$90RMONbH29KI;uOTj7x5ZV$n_U*gu z*R7TlhJ-7o$Er*`qkvZU(A6u@arC+rCV}Gh%Dh(+{DB@1jBccCK4WQU{y|b znM@4G@@s&pEq#sVXe%#to{+B^t2g}L4z~~Kdqcjz_OwDxfHNR|y#~#b@^KBgZ$h45 zQD@}QQhdg>Cp zGC-T5Ugq}VvQvhr-#foyxdDzVyhZ+u+QeR{a^!x|3_RX_2q+6|DPVWW(`fiZJ(K^m zY2@I^k8~zk_ydWOzw~9wJ#q7uk8TeUAPl~uAw@S1WvmFhL*#-eX6ki-XpjSk%6kyR zSB#b?57LtbVZ!LzvJoA7LU!~I{rkEv^&yot?G#1jCw+8J_+gSRJcwWr zzfT>Mun$c>69ojz!Ao3u0D7J+<_iRqmrL=I2)R)Yctb4Tw|M46cxU{aUgxV3b&Yuq zCnZ}xDLwQOr$vJxXz}0{O0kIEcM6Np5D)9&FbD;@sngra=U;_&h4_|W=p)6 zvErb4Joh4a=l%NWK$>0eMafXn(FR_+`Xmx?rzVL}Y~fXc0nZsXQ1QgD6etiA~2zmr?w+U&TWZ z8X5M0ETNQBbire}C`@PtyD#th9=%omeam7l6K}X_CoC2p`Ddy^P8$IFwRC%-r_klg zI3SY80`(6A2>2=q11RzU&T;7a6{|TtW>kBztS^h4+qk*v(gkNcX=HctbpE5_hjr8h z0wK`j!L5X3FqMpm3$SGA9Jk!7j-mna6%7a%=$t74@xbd2RQzNv(P8QkVo(ONSsEV$ zHqU-@6vPubDKyS_!C!oC(cuQxAH+bMDhM%M|5<4w@>kS=b;Ikodr8H-sYw) zBkN;98DK%cB*McESsXBkpo87w1Ako;y6Pa#up8wYP*4A^a2VYI$;TQGk9Bw0%BK>i z)h_+?SZA8z_?LV_a@vvM>VbrKc?_GjIBY2r_dPg55W+gEFe?~(!aooyOD1AuOpA_1 z)nMz9^ha3v`66NKm<^VoeNtP5*Yd5+6w87yb-~Tyb!yXRep0*02bcB`+wd_t@Xi+Z zMEI)s06VFaLQfV6$vc40_!gfO9c3sU`wLEd-Zddlyy^mRV3Z*Ucoaky`d%<|aS#tg zdD4WPx8v91(Y5GNPkAeVk|>J2(yZogzH1o($7dFFOz`9A;Ds}<8GeZ-ivygNrQ|L}c2xIuf!z99YlERNOb4PQ1i;wolgv=wrEO1zb zvpZ#1;z>cOiC@%&0w4Dp_^*q=z28~?{7ZGvfrg?zsbFpJVI@5%!>vXHVGX>fpr z6q?DH<6R;L_vOmY78a+}ec8w-j-t+LknZ=mu?}U83N`8CC6$g~` zW4@()pq1t^Xde6B1s9Zm?n&@e*K5xm_&0o&4)kR}Dieb-6K+;?Ok!Tqu@V%Z=alYi z@hK1{2zDT}Ki}t&?Hlh@S~!k$_#_DWvkRo&zWzTD&ppC3XauB_W600^^CKn?@%vbW zJm}}+$mpmrN0p;uMh3;8IG>6+-Rg0W70KW@a7}l|^*Ai!=_2LX?M>z3Hn*5uCT``? z`d#>qUdliZC?3)#D;<Mz(aKTlHT^>toE3|JGkx!%NbvTyR7{KfUAO zHhC;)_d^z;pZ>>c?~fL;2h!m-P_{cMx{ZSm9@=4;(sn`A(!%e@uoey~71$gv25 zKleX)%88Codt|}G(VHg|1PiFwb5Cn`{fi3E2D>Muj0C=CvP8#~2 z%?}@uq8X=4sYuZn?f#^UvwLSEw*QhFyAflr~yZ}%0 zM4k_y9XWw4V*9Tvg=BlO3F)ryYP*gd`SvH$wXJvKENe`Zta9RSR=wt#^rW$6VhNd$ z!N&t;4N&y@F?q;G7fqE<{03R5E&6C+DUldb+K-lMf<{LgaoBnY&2((kk0;Vzt-(AE znWL%`OdJZG50oIQfR`7kTdxAaH=wON^urA?MX~Ak3Q$xNz+e##1I`0T;sp4)B#omk z5Fa?j&uMbt6DvIFMqgY5zs)Wo@{bMLrWMH#{#)cN?^Sa0iN(%yf2hIW5xJ`}VsaVx zo0<_OBJNx9k-eqTr0+eAp`u^-Ek$sC7l`Ib4LW@NSIHR%YhX<^{p`H%@o;SC_DjJ9 z5a{W`yNp#9On7_^fY4tZm4@D*E-JSY;wh$tnCkH|z0}X5_Q19B(eys98g;&3N8LQ}uk<9{w=5GhrxrXM6L6bQd+1|8Xoo`bfss9seAzGfTHY>QPc!M{XQf_Be0N0p?Sy{Ja#8+XwwT|UkcjT_jP9@#ekcBL@KJ0g5(la~wU zK_PY+0Q16O8sI2YDWTEfZ*~^&xM5KFEl4bq^=qj+9^Y6-oX zogI-pdA#)@3GD#>L!2ib?9cMZ-~+Z4DyR#Q0`ST!WpRzl6?O)7c6F39pW4}~n-cQ? z5t_no``(YK>@@LoIqdVb*C&5zQILl%ZhcT+I(S0uUz0U}-uM1(EmH2&y|+j81kW!o zgDs9RAODEF^#RXD1k} zs7Fp7$TvH)OIi^6E6k#?LvsBiQ1+wK`U>3#!D7RL!RZOvam4LU@ngq*k93n`G3I)& zwqTcZ@dFp-A7#$HQh;~4_{UM!p|Tz}(Ql5+zffM=&K~GEW% zNyICcMWqXRt5A>Ud`zu|TOCpycYL!t@B8Gp21Xb3EG3(Cg0p{*(Oy*m03ZNKL_t)r z5OBc*7G=P1_DKy57$nh&Z^4XEnj;oET8>)06Jci)!HT%^5!Wv?hq_37K}LUYN|#&F z=5XX=3tI`vjI1@a?cVC4VTyPYg3U&$l?BrG>S z8)+-b(c$|vdGO&r{J8yt8fZ1?oc*_AQ(4Rl7w@>i(-p~FfJ(-vjw>I*JKE9_yPS}P z5HC;Cr}sfl3{I+D@q-mf@2I)c>_+XoL_uI2^gt|qCtNvV1MImjCVz5IPl9P;mEW5Jap0uqQ;5B zA0WHZJ@G9?#kYo=RUC&$RX>ZZr%_grRR*8jCesx7+$qee+<);iT6t;}#_ogjWeS2u zd%Ze3=hO3(H@w%tWb?KhW0k*b{rOLWykU-RS4Pniu=;)M=X4gXP9M5g5G~)vj~ZPh zNs@ODWa;ox3a#WvIaQiT)GIv6cwn9Nk}h0G4t2rIfDl2TyXe_fgwJ)9#7dZK@*>qW zoQtbY88G?(BupMxYk|P(%?(`g)DLwB50kF*86{o6a2)$l{wdc^PTV^kCD5ODXx7x3 zpFB4r6EKrlCMfcNPdrt`WWZoSwTsQri>y#1;A4h-dBANoSP5{Sg#Y)jc1#tvTO`ZB zG~hdG*o}|Z%KrE-c+Ky~`F#`c`NcufmDdbv7S|o)EUQ#S%FbxX;PQJdJp* z`~xmMD|?h-jH-SD0~f?)gdQ*8?@p4Ao#3%8o0OGF!e{pZdw_A)JQ^z)GyTFc0?`L! z;^cAW)+_`jS7$^|G`K!ie zkPa$u-o+I4Ed}_+JpeweNXJem+)^eURwnF2|g7BMJiTD8?I}Oq)ywg#+Z-L}PXL9B1 zx$HdnQtJuoMgztPm5=Qsh;G@k&sAQY3~_9-3%kox!TbM?Q#&s%Z`c`(w6HLgKFSn` zpG#`Fl6@wB1~Ed~87pB1df$H#{W|g^U94Zk=JHoy82M7_UEiv9qD4k;C(zG7t)q_L zD1jZp&1dw8vUVE&Hd!kNCfb)itNVYCE`lbJAGMVLM=5C((6LEg$(w=ruJR4fF+%j& z{=~~EfeB$yIBY|b5N(4t!R{lwO(tmCZ|cYSP?~|yWr!ZtiEYA%E^ycfX#|PGKp8;h z=n?z=6&o}!Vh@WA43izc@#W{!AJXp|wP?LxdenCD_a)uGdg>o4EH`rPk`uiHmqoF$ar zt(9f>W%dKv%Z1oJEH{rR#nByzP#jj;Nbm9PH^5(V5rax^49P4M(@ONHn>uKJSFytU0lCh|H|p6pH= z2wbjsMtzkj;7O%R8uVC2 z@|dnCk+OlGSrIZC^W|I$331myx+Y)&K}Wdd{S#qIGPwclKpCV^g`d&QS7`lzE94vR zE*S62GI^Z5Wtlvv)AMK5@g70}8ij9usaly6w*cSo`R=+e)_7@${EzIjf4s%MmEc|) z69+F?_C7$nWX1S|b}i3pumX}F1~=dHB7gFi$E`cyg4;F7<`1iXmQO&lo|b$!YH`@0p&~W{fYlc`OShQ zM8d|qm4Va1bE_;1ucD%e|^EL0qEfi;8!z7F&vAR zeE$Cv3FhcdoDfL3q_+8>(J(qhzT@`Aqd)c+UOYYmBG}lfJnSS5t9Kr=Q5XP>ijSRz z(q5qmJ&v!6jYjhF6B3y-DtZcM%M~TuDX~#N8sO`>@A|f-@ke%{NI(3t!4ns(rg--t zfNfS*H)`h+Tjr0ALLSO*6hx@f_+#D)kIwjRQs@qkx^Ti0`+SQZ$h*WlIi?D=b{8@j`(%cfJ@JiCx%2ip zyjw7s8&)_U$!Rbg%EFhhu_v0mCj?I%V6vuPlK1PH4n8Nt5#DL7lCx8y&$81zE&Iqb zd2nRN$%Jy-_bN}KKlQ(;EYz0Ww&BAk<##~ofW8Irfg|j&3nv~Q3oE3Y z@PYC}2NU97xGA!rlq zHt+Z*@s{1eH$^TmVF~ygHoBRh@Qb6)d@_VViH^-A=kwqic&SqcH`)$9-TVNW4j}%6 zA+%$CeoH%#3>~WHyY1$Px-4G`qP0K^DU8M)9C&Tb}S0LgP(&KFt!k+qe1&6Sr5s zlEnppmw_4mdEqiZJ@QV4`+yjEvX8j4D5WQfONIw$Fhc#225eK8=qH`Nl=ePoCR)sw z(f$j?LgBi1FO$Wo56F-A$baQ4FVBt)9;i5o$;fMJU;gf#^2h*w%STn;Pw0r~=N2~1 zTSv9mjBE2TvokaKdSGZJMh3<21?pM(t1-sqjvW;ulZ5kH1;Or!#SP`o{YcvQfZ6Vx z9*jF8@OPOM{tot4^ntu;WDQ{01yvX!(`nrxN@jE_rHS*n;Aw5$=;Qzm>w+3u{3hh+ zXuRodE?uH8X~M#F)EtK;=d__waXfy>e;4CPn$TTo^a3iffI)yC9cVOQDLsbisBqX+ z4*WR26UO>8MQ7bBX3<<|0rM#_8 zCM+9Th3R;XTKr#x|k)15|{rqi-Z^=CvBcX=q>Ql$iV_|opEyZ&s5$Oke? zu$sH+Ax#3`AX_wl6bg@?bI<5V^EZ^<0ZcmoKX-2$v)OUo`MvCw-E20yn>)Knc2gup zEha^+-Yv@>uSv#923Y|klguQ83@{0hK>{TCpa2OHBnXfRFvy32F~DFF3<3oC5DZ{s zvB#cq?8uTViIzl(6xkHl=F(i7?3JD0?|mI(JPK-`#ohWwVs@OaZ>XkRr%|HadWuWpPTK=kTf*a2ktIKS7ZQg~_1&>jCKk=#@ z-RtlOuCqDYqG^g-v>NFs*z$|X-{|g%OS?rf+zz?YvM$DJ%ZqT2i#>6Qc4MSuKBz5G zY3)5mAM!BIgOuw{biT}*l6W!DXm4tOyNmqSAq{c8TkOcMQ}2&4yM26P?2@U0*%sdT zimUOx5VH^O1Mqiw_6+jj5|y8ZwocD8ULUIa8w@n$*W6Cz8ts=4xu+Hf( zwzxI>@0}YhfIs5BKK_wT!_UD4+;-|JGwabMHD~D7T~5-`7L|8rdKsB_-9hnD?3hmF zqx|$LFllFt?$umoX~w(61aS=uw20*wlfdR(STT1o=u~MqOK{ea8wy533#eOi^fN0X z?k1f({#_2z{FlfIGqqW;aTSw24=I#M48sd|5|ks(l=rL1neyaJI%fB}lt}-!#PlH&SyX<9(qEOf7TcRL*5%?Czb?ig8 ztt$_4e39@?3M1drMtDm|6Tkji{ALWky+eB>uOc+Io4+)zC|?q?(b$mPq!Q8@w#pqx z7y1*|&Q!WK0^dee0lDscr5Ev}JC>U~2xShg{5y&;jXLo$1~q<+Q&aj1ODCX1dWBbk zWfJCcg*eH_U|p{Z!^Q2wLywNu{RD6Rjk|C#P0Hnse#TU{-kzcUEYngTMiWeXp+1x7 zFwz<@uJBKyzAsS_dN?4vPFF`kZ^uu5vN>JhW&#{fm8m%LjS=MGrq5Fcd+;zEa3vWLD)w>EfuCe4JDwx{6#?!ZlIw2sE>Ao?2z7J3g?K&QA(iV z6vNV~hST{q><~&6aC$)>d1`S|Ic)?~Nk}7_zW3116Iu!lbp4={h5Fi)D8S<_OuXU; z>t-PPf;7i6(QZ-8x9L$9)j5ak7U+k#_zkkwjoY;JPWi<`8qME)JK_#M4bMFTulO)u zIcH9tID&WNs1gmGAvh^jRXe4wu(8~O(dZk;{1L%ZO5+T*;gnJ3uYD{t@$}GWrgp?KdsohW4m?DA`x0e+Cpaqj4;b8x z-%UNcC$ch_msSP~ahkvF#79~25prMyyC~L6%0ryi4t68MSvire@hBwsX+vi&Es6H9 zjHe!FnZ4p_7HpPgKLZ)#l%<(th2xHwe>~$^r7LG3>3muo z!)?%ZO10#XApYb#o1;pZfM10v^!cVZ4ctx7C?q1(ZI+^!uqXdSbX4S3CT~4M7?qU@ z4MDMS^DL~}66W<39vih|ZS^1Ag}y27Gm-p|Rfit( zNl#B1OD5ty{$Ij54^c3><%zr&y_5;~NnV10 z4Zw}=4GbrA_$zjA`{|Z$7gkp5$8^q>0zrZ2E$4<1ezB(>!5c^GMWFE$C;4@6V*|7d zNaGUt;<$99{HQ!$`r2S_h=+%AdHYY&A+qE(&8zgJ(~sOOBW=E@{j%3QC%r0V1x;6J0+$^K4H}@D0esAyjD*ISZAnI4V zn19`g--zs@P452`isOsO6>Zac`B8z(r{|tqF?BN~w0w-29DIj=>MeOT-{i}@D;ELm zkqzZS5C5cznOT>9f^lpg&VWYFr8r@s57*_~mn48mr6LCbUi1BEC z%^suS1WlnfQx&I~8g?)TZ>1mx(qTl!p#l*cp}2HnnkpgJq<4YuC@`a2{3A%3G{AT5 ztN>}}Pk(3|*R(R?!OtU}{h50C^EwHYh5pi#CmW7$|Jng$2qa+&E9KQH+F63iL>zfF z(0h?wmQW~EUOD1uTmjSK7|TOD5XI5TN?M*Ia&&5k;wdp{`GRGE-%t1L?`Z?B@G%`c zEWbR>o-orY|7M1#jz6p*kv5NeQ{pSw@{)Vbf-vyVtj0(j4Ucz<>n6G}$Z_2*@;T0Z|myYIw)qEBZNARAl4bZ~+ zVo_#bDbV}tq5Bene#hJ=0B=1nb23+`IUQ*pjM&m1h-`4iL-}^8_B;fvgFYRj?_eoy z|EK9Eet|M}c2|rS(I0{N$hVMx^H`al<3Z-9;pJCmi)Vc+N49&*K>NX?9Z|wnBKA#g znoC!?a!^wJMh4#WYw@={kv#{ry8Vb;e;^?B((^XqXG3_$%BrSUn=^ zuiMDYKW1}lL{U-?zJcx~gq0C_s66Q%8ki&C;TQ7kC@ix#o*qMDF}}PUyl2tBcU7I% z5njKeUPr16&ve6Md8BY~Oc;_@)m`yjQDTN6_{F?LI_Ec09^xPU;vj2@+y1OW-wiS8 z!ze~)r9Qr}ssahG(66Nkqj@q*xf=l_@d`>F%ALRv8ho@G-?m~{jqZy^mEn;15T|9e zZvtxKbRg={*SD#`uv*qnY*)eU#y`oEtO6Q}Rn19@Uq>e*Z){+y8J= z9LUd)a>g;_cKH9=pVAlo4*V$WTY)N+nK)H;kxR-x1KkeqwN3^v)3s(e^Yav4!xKlf<`lSZ?GGtzk*m$ z_|1Lz7y@!=J#I884XII8t{;*haP9f#PP9!f!nOBDv4f!h+K*zbtrx!4Dk{fItrenBWb&Y z<)9#W#NC78C8HHra)NQRXG$&K4dO?bUwT{yC0})^=EYZMFd;N5bD67zMQ!%Vn*)f= zK(V#FL&mrrty1<5PLBRO`RWEhMo?y7{OVBe=G6lh4rWZ-derUlU9X_%>$#V+kvG$A z1s&d-y%_^r4M+Jhy^&Qaqm;-mHozCLZ#g^?SlL@I!d+Nh6J7+&zx{KS4Qtk+w}AkpnA@?vL7dgnHfgKf*<2R4e>? z3xn-q16V#C?m~DM<{;60I#{-k=<~dwJfNlAdEL@pWXU>@JX(%zMqXrh+ny*_XTkQ7 zc^}Gh77A%Idk`moeY{D~f>XSWKn~5Q0sb|lYLsQ_pJ0U<{5d#q6B?9RgdMd)>62?Q z=%mW6>0ZPtU_n|)erF zb6`h49wIPd;#^>=z5!Z#lVsP?`T)~h4;gKiN$$eJJWpCC7sXw1TRo@@Z~fe&^01Eb ziR3>S$)(=?4#*y4$owf+DiB{#bvZVJ3(BO2mPGHhZkG=bik&e450^^g-vY~CW@H41 zZk0q{I>Ww`Oq!+m5ZdSw`N*Q5bz3r5(Jx zB5z{0^sERK);Xn^Mi4sKQ#lBu6|(@ut3uXa_JmR%x<#>Jx|aCbNgP52VC_kiz4ASx z8PLFGF(Ei0xT&u&c#)&ZB@MCg3HM}@LKQ$@u6c;(eq6*^L+I9SBhEj=G_e^-I+RH% zk95S)_sv$5$;c-b9RmS^VsFkNyEv+D#0w5+7WD$2aRJ$}W2p`$p8UP#(wq(>X~EQb z(`PWX%zz_c`L=A_$TyzXm`owj`CBN%DH86aV`HN{r(iklX=QUQWqg73&dH}w2T_7m z2>9!EY3ijv>yVn&51)C-qAwO&-VR87N5rpJ)}BWn%X}mcmJ-5XJ2kjNt*( zrVji%qj}v)2YK-4D5HnLr^8!ds73iv8gJ1zo&TR3Tkw7v*}3^Y=6gXXJmKKy$;U{nR-7g2>O;&scQ zgoe-_Vf1MkTN2ixZOa;l6VoY0OG{7f6H~PETP6fI--p0-jn@KrjYj53&vz+mNgy4$ z^b5w4DUWqiG^gCTRTVaKG?&>(fep3fI(~^zpV4o zyR(Lz9S^^p@vhNC5(Lrwk25d?>6)MBxeH`7!n8D}rA}Z{W|tqqB#w>MWaUZIzxZhq z&nIDq`$)?$ae>N9BFlp~_`5{mEG*Yj1aru*@#J3|0kj2s(G@3$5TvOcu#5x^NAqKV zo-^Qwq_V7p=@OQ_DJ!+~Q=M+npCK`L!Goh-zm{2pg~DycQO+pd(NPu>u&z>fDk9vk z(s^vQ(e5&Ymnh1wWq$BD1Ei;iJV>^9*Djbh{mhGHx^B?{5MWpj^5cHr7*+@pX!i1| zc+NVM374`;c0_mYL*=645UjrobYgo@A|+4aDHoQRpnvL_zvKtErZb)3n7EO6rC6&6EYexuL{B>Y@tCpR9PKm79Aw0NEkd3+gezcgF$#I}`GyRw zbO`wSIZsKCJm?V0qq)mF1x#3$i)`3{h3|5MQ^7TsvH~5^BGp1R&{ojjdXCC*`bRwR zi}x{3vn=y3yu>XBW*V6$Y2^gOq5Oh3cxA)e zm(iqI;ApgP58PS48%;YnA+rxmM_!j`&_XFd37K99c4>?W1lhjmBTf6U{{EGAZ!Gy z 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%0D$ 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 z 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 O0000 Date: Thu, 5 Sep 2024 21:21:25 +0200 Subject: [PATCH 07/62] Succesfully Ported to 1.21 NeoForge --- .../bluelib/example/entity/rex/RexEntity.java | 2 +- NeoForge/build.gradle | 109 +++++++++++------- NeoForge/gradle.properties | 30 ++--- .../main/java/software/bluelib/BlueLib.java | 13 ++- .../bluelib/event/ReloadEventHandler.java | 4 +- .../example/entity/dragon/DragonEntity.java | 25 ++-- .../example/entity/dragon/DragonModel.java | 4 +- .../bluelib/example/entity/rex/RexEntity.java | 41 ++++--- .../bluelib/example/entity/rex/RexModel.java | 4 +- .../bluelib/example/event/ReloadHandler.java | 4 +- .../variant/base/IVariantEntityBase.java | 2 +- .../{mods.toml => neoforge.mods.toml} | 8 +- NeoForge/src/main/resources/pack.mcmeta | 2 +- 13 files changed, 145 insertions(+), 103 deletions(-) rename NeoForge/src/main/resources/META-INF/{mods.toml => neoforge.mods.toml} (89%) diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index 1823e889..fdd27cb4 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -63,7 +63,7 @@ public class RexEntity extends TamableAnimal implements IVariantEntity, GeoEntit * @Co-author MeAlam, Dan * @since 1.0.0 */ - protected final String entityName = "Rex"; + protected final String entityName = "rex"; /** * Constructs a new {@link RexEntity} instance with the specified entity type and level. diff --git a/NeoForge/build.gradle b/NeoForge/build.gradle index 158ee7ed..844cf406 100644 --- a/NeoForge/build.gradle +++ b/NeoForge/build.gradle @@ -1,20 +1,24 @@ - plugins { +plugins { id 'java-library' id 'eclipse' id 'idea' id 'maven-publish' - id 'net.neoforged.gradle.userdev' version '7.0.97' + id 'net.neoforged.moddev' version '1.0.19' +} + +tasks.named('wrapper', Wrapper).configure { + distributionType = Wrapper.DistributionType.BIN } version = mod_version group = mod_group_id repositories { + mavenLocal() maven { url "https://cursemaven.com" } mavenCentral() - mavenLocal() } base { @@ -23,34 +27,55 @@ base { java.toolchain.languageVersion = JavaLanguageVersion.of(java_version) -//minecraft.accessTransformers.file rootProject.file('src/main/resources/META-INF/accesstransformer.cfg') -//minecraft.accessTransformers.entry public net.minecraft.client.Minecraft textureManager # textureManager +neoForge { + version = project.neo_version + + parchment { + mappingsVersion = project.parchment_mappings_version + minecraftVersion = project.parchment_minecraft_version + } -runs { - configureEach { - systemProperty 'forge.logging.markers', 'REGISTRIES' + runs { + client { + client() - // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels - systemProperty 'forge.logging.console.level', 'debug' + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + } - modSource project.sourceSets.main - } + server { + server() + programArgument '--nogui' + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + } - client { - systemProperty 'forge.enabledGameTestNamespaces', project.mod_id - } + gameTestServer { + type = "gameTestServer" + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + } - server { - systemProperty 'forge.enabledGameTestNamespaces', project.mod_id - programArgument '--nogui' - } + data { + data() + + programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() + } - gameTestServer { - systemProperty 'forge.enabledGameTestNamespaces', project.mod_id + + configureEach { + + systemProperty 'forge.logging.markers', 'REGISTRIES' + + // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels + logLevel = org.slf4j.event.Level.DEBUG + } } - data { - programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() + mods { + "${mod_id}" { + sourceSet(sourceSets.main) + } + "geckolib" { + sourceSet(sourceSets.main) + } } } @@ -61,27 +86,11 @@ configurations { } dependencies { - implementation "net.neoforged:neoforge:${neo_version}" runtimeOnly "curse.maven:geckolib-388172:${geckolib_file}" compileOnly "curse.maven:geckolib-388172:${geckolib_file}" } -jar { - manifest { - attributes([ - "Specification-Title" : mod_name, - "Specification-Vendor" : mod_authors, - "Specification-Version" : mod_version, - "Implementation-Title" : mod_name, - "Implementation-Version" : mod_version, - "Implementation-Vendor" : mod_authors, - "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), - ]) - } -} - -// See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html -tasks.withType(ProcessResources).configureEach { +var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) { var replaceProperties = [ minecraft_version : minecraft_version, minecraft_version_range: minecraft_version_range, @@ -96,9 +105,23 @@ tasks.withType(ProcessResources).configureEach { mod_description : mod_description ] inputs.properties replaceProperties - - filesMatching(['META-INF/mods.toml']) { - expand replaceProperties + expand replaceProperties + from "src/main/templates" + into "build/generated/sources/modMetadata" +} +sourceSets.main.resources.srcDir generateModMetadata +neoForge.ideSyncTask generateModMetadata + +publishing { + publications { + register('mavenJava', MavenPublication) { + from components.java + } + } + repositories { + maven { + url "file://${project.projectDir}/repo" + } } } diff --git a/NeoForge/gradle.properties b/NeoForge/gradle.properties index 979cf055..47185ef7 100644 --- a/NeoForge/gradle.properties +++ b/NeoForge/gradle.properties @@ -1,21 +1,25 @@ -#org.gradle.jvmargs= -org.gradle.daemon=false -org.gradle.debug=false +# Sets default memory used for gradle commands. Can be overridden by user or command line properties. +org.gradle.jvmargs=-Xmx1G +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.configuration-cache=true -neogradle.subsystems.parchment.minecraftVersion=1.20.3 -neogradle.subsystems.parchment.mappingsVersion=2023.12.31 -minecraft_version=1.20.4 -minecraft_version_range=[1.20.2,1.21) -neo_version=20.4.237 -neo_version_range=[20.4,) -loader_version_range=[2,) -## geckolib_file is the cursemaven file you get from curseforge -geckolib_file=5188406 -java_version=17 +parchment_minecraft_version=1.21 +parchment_mappings_version=2024.07.28 +minecraft_version=1.21 +minecraft_version_range=[1.21,1.21.1) +neo_version=21.0.167 +neo_version_range=[21.0.0-beta,) +loader_version_range=[4,) + +geckolib_file=5679344 +java_version=21 ## Mod Properties + mod_id=bluelib mod_name=BlueLib mod_license=MIT License diff --git a/NeoForge/src/main/java/software/bluelib/BlueLib.java b/NeoForge/src/main/java/software/bluelib/BlueLib.java index e73d1c98..99d1bc8d 100644 --- a/NeoForge/src/main/java/software/bluelib/BlueLib.java +++ b/NeoForge/src/main/java/software/bluelib/BlueLib.java @@ -4,9 +4,11 @@ import net.neoforged.bus.api.IEventBus; import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLLoadCompleteEvent; import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.neoforge.common.NeoForge; import software.bluelib.example.event.ClientEvents; import software.bluelib.example.init.ModEntities; @@ -24,7 +26,7 @@ *

* Key Methods: *

    - *
  • {@link #BlueLib(IEventBus)} - Constructs the {@link BlueLib} instance and registers the mod event bus.
  • + *
  • {@link #BlueLib(IEventBus, ModContainer)} - Constructs the {@link BlueLib} instance and registers the mod event bus.
  • *
  • {@link #onLoadComplete(FMLLoadCompleteEvent)} - Handles the event when the mod loading is complete and prints a thank-you message if in developer mode.
  • *
  • {@link #isDeveloperMode()} - Determines if the mod is running in developer mode.
  • *
@@ -61,17 +63,20 @@ public class BlueLib { * Constructs a new {@link BlueLib} instance and registers the mod event bus. * * @param pModEventBus {@link IEventBus} - The event bus to which the mod will register its event handlers. + * @param pModContainer {@link ModContainer} - The mod container for the mod instance. * @author MeAlam * @Co-author Dan * @since 1.0.0 */ - public BlueLib(IEventBus pModEventBus) { + public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { pModEventBus.register(this); if (isDeveloperMode()) { ModEntities.REGISTRY.register(pModEventBus); - pModEventBus.addListener(ClientEvents::registerAttributes); - pModEventBus.addListener(ClientEvents::registerRenderers); + if (FMLEnvironment.dist.isClient()) { + pModEventBus.addListener(ClientEvents::registerAttributes); + pModEventBus.addListener(ClientEvents::registerRenderers); + } } } diff --git a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java index 9a095c52..9da36f9a 100644 --- a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -65,8 +65,8 @@ public class ReloadEventHandler { * @since 1.0.0 */ protected static void registerEntityVariants(MinecraftServer pServer, String pEntityName, String pModID, String pModPathLocation, String pDataPathLocation) { - ResourceLocation modLocation = new ResourceLocation(pModID, pModPathLocation); - ResourceLocation dataLocation = new ResourceLocation(pModID, pDataPathLocation); + ResourceLocation modLocation = ResourceLocation.fromNamespaceAndPath(pModID, pModPathLocation); + ResourceLocation dataLocation = ResourceLocation.fromNamespaceAndPath(pModID, pDataPathLocation); try { VariantLoader.loadVariants(modLocation, dataLocation, pServer, pEntityName); } catch (JsonParseException pException) { diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 00e15560..56a55393 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -11,13 +11,14 @@ import net.minecraft.world.entity.*; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import software.bernie.geckolib.animatable.GeoEntity; -import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; -import software.bernie.geckolib.core.animation.AnimatableManager; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.util.GeckoLibUtil; import software.bluelib.interfaces.variant.IVariantEntity; import software.bluelib.utils.ParameterUtils; @@ -33,10 +34,10 @@ *

* Key Methods: *

    - *
  • {@link #defineSynchedData()} - Defines the synchronized data for the dragon entity, including its variant.
  • + *
  • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
  • *
  • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
  • *
  • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
  • - *
  • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData, CompoundTag)} - Finalizes the spawning process and sets up parameters.
  • + *
  • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
  • *
  • {@link #setVariantName(String)} - Sets the variant name of the dragon.
  • *
  • {@link #getVariantName()} - Retrieves the current variant name of the dragon.
  • *
@@ -89,9 +90,9 @@ public DragonEntity(EntityType pEntityType, Level pLeve * @Co-author Dan */ @Override - protected void defineSynchedData() { - super.defineSynchedData(); - this.entityData.define(VARIANT, "normal"); + protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder) { + super.defineSynchedData(pBuilder); + pBuilder.define(VARIANT, "normal"); } /** @@ -140,7 +141,6 @@ public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. * @param pReason {@link MobSpawnType} - The reason for spawning the entity. * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. - * @param pDataTag {@link CompoundTag} - Additional data for spawning. * @return {@link SpawnGroupData} - Updated spawn data. * * @since 1.0.0 @@ -148,7 +148,7 @@ public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { * @Co-author Dan */ @Override - public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData, @Nullable CompoundTag pDataTag) { + public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { if (getVariantName() == null || getVariantName().isEmpty()) { this.setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); ParameterUtils.ParameterBuilder.forVariant(entityName,this.getVariantName()) @@ -158,7 +158,7 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul .withParameter("array") .connect(); } - return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData, pDataTag); + return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } /** @@ -217,4 +217,9 @@ public AnimatableInstanceCache getAnimatableInstanceCache() { public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { return null; } + + @Override + public boolean isFood(@NotNull ItemStack pItemStack) { + return false; + } } diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java index 67091901..49db6249 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java @@ -12,7 +12,7 @@ public class DragonModel extends GeoModel { // Get the Model Location @Override public ResourceLocation getModelResource(DragonEntity pObject) { - return new ResourceLocation(BlueLib.MODID, "geo/dragon.geo.json"); + return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "geo/dragon.geo.json"); } // Get the Texture Location @@ -24,6 +24,6 @@ public ResourceLocation getTextureResource(DragonEntity pObject) { // Get the Animation Location @Override public ResourceLocation getAnimationResource(DragonEntity pAnimatable) { - return new ResourceLocation(BlueLib.MODID, "animations/dragon.animation.json"); + return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "animations/dragon.animation.json"); } } diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index fcb85a52..fdd27cb4 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -11,13 +11,14 @@ import net.minecraft.world.entity.*; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import software.bernie.geckolib.animatable.GeoEntity; -import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; -import software.bernie.geckolib.core.animation.AnimatableManager; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.util.GeckoLibUtil; import software.bluelib.interfaces.variant.IVariantEntity; import software.bluelib.utils.ParameterUtils; @@ -26,19 +27,19 @@ * A {@code RexEntity} class representing a Rex entity in the game, which extends {@link TamableAnimal} * and implements {@link IVariantEntity} and {@link GeoEntity}. *

- * This class manages the rex's variant system, its data synchronization, and integrates with the GeckoLib + * This class manages the Rex's variant system, its data synchronization, and integrates with the GeckoLib * animation system. *

* *

* Key Methods: *

    - *
  • {@link #defineSynchedData()} - Defines the synchronized data for the rex entity, including its variant.
  • + *
  • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
  • *
  • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
  • *
  • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
  • - *
  • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData, CompoundTag)} - Finalizes the spawning process and sets up parameters.
  • - *
  • {@link #setVariantName(String)} - Sets the variant name of the rex.
  • - *
  • {@link #getVariantName()} - Retrieves the current variant name of the rex.
  • + *
  • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
  • + *
  • {@link #setVariantName(String)} - Sets the variant name of the Rex.
  • + *
  • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
  • *
*

* @@ -48,7 +49,7 @@ */ public class RexEntity extends TamableAnimal implements IVariantEntity, GeoEntity { /** - * Entity data accessor for the variant of the rex. + * Entity data accessor for the variant of the Rex. *

* This is used to store and retrieve the variant data for synchronization between server and client. *

@@ -79,7 +80,7 @@ public RexEntity(EntityType pEntityType, Level pLevel) } /** - * Defines the synchronized data for this rex entity, including the variant. + * Defines the synchronized data for this Rex entity, including the variant. *

* This method initializes the {@link EntityDataAccessor} to handle the variant data. *

@@ -89,9 +90,9 @@ public RexEntity(EntityType pEntityType, Level pLevel) * @Co-author Dan */ @Override - protected void defineSynchedData() { - super.defineSynchedData(); - this.entityData.define(VARIANT, "normal"); + protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder) { + super.defineSynchedData(pBuilder); + pBuilder.define(VARIANT, "normal"); } /** @@ -131,7 +132,7 @@ public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { } /** - * Finalizes the spawning of the rex entity. + * Finalizes the spawning of the Rex entity. *

* This method sets up the variant for the entity and connects parameters if needed. *

@@ -140,7 +141,6 @@ public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. * @param pReason {@link MobSpawnType} - The reason for spawning the entity. * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. - * @param pDataTag {@link CompoundTag} - Additional data for spawning. * @return {@link SpawnGroupData} - Updated spawn data. * * @since 1.0.0 @@ -148,7 +148,7 @@ public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { * @Co-author Dan */ @Override - public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData, @Nullable CompoundTag pDataTag) { + public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { if (getVariantName() == null || getVariantName().isEmpty()) { this.setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); ParameterUtils.ParameterBuilder.forVariant(entityName,this.getVariantName()) @@ -158,11 +158,11 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul .withParameter("array") .connect(); } - return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData, pDataTag); + return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } /** - * Sets the variant name for the rex entity. + * Sets the variant name for the Rex entity. * * @param pName {@link String} - The name of the variant to set. * @@ -175,7 +175,7 @@ public void setVariantName(String pName) { } /** - * Retrieves the current variant name of the rex entity. + * Retrieves the current variant name of the Rex entity. * * @return {@link String} - The current variant name. * @@ -217,4 +217,9 @@ public AnimatableInstanceCache getAnimatableInstanceCache() { public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { return null; } + + @Override + public boolean isFood(@NotNull ItemStack pItemStack) { + return false; + } } diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java index 6084892c..1e0f85e3 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java @@ -12,7 +12,7 @@ public class RexModel extends GeoModel { // Get the Model Location @Override public ResourceLocation getModelResource(RexEntity pObject) { - return new ResourceLocation(BlueLib.MODID, "geo/rex.geo.json"); + return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "geo/rex.geo.json"); } // Get the Texture Location @@ -24,6 +24,6 @@ public ResourceLocation getTextureResource(RexEntity pObject) { // Get the Animation Location @Override public ResourceLocation getAnimationResource(RexEntity pAnimatable) { - return new ResourceLocation(BlueLib.MODID, "animations/rex.animation.json"); + return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "animations/rex.animation.json"); } } diff --git a/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java b/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java index 5c6bacca..4d36d784 100644 --- a/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java +++ b/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java @@ -4,7 +4,7 @@ import net.minecraft.server.MinecraftServer; import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; +import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.event.AddReloadListenerEvent; import net.neoforged.neoforge.event.server.ServerStartingEvent; import software.bluelib.BlueLib; @@ -36,7 +36,7 @@ * @author MeAlam * @Co-author Dan */ -@Mod.EventBusSubscriber +@EventBusSubscriber public class ReloadHandler extends ReloadEventHandler { /** diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index 3b905d28..baecfe62 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -41,7 +41,7 @@ public interface IVariantEntityBase { * @since 1.0.0 */ default ResourceLocation getTextureLocation(String pModId, String pPath) { - return new ResourceLocation(pModId, pPath); + return ResourceLocation.fromNamespaceAndPath(pModId, pPath); } /** diff --git a/NeoForge/src/main/resources/META-INF/mods.toml b/NeoForge/src/main/resources/META-INF/neoforge.mods.toml similarity index 89% rename from NeoForge/src/main/resources/META-INF/mods.toml rename to NeoForge/src/main/resources/META-INF/neoforge.mods.toml index d63059f6..711284af 100644 --- a/NeoForge/src/main/resources/META-INF/mods.toml +++ b/NeoForge/src/main/resources/META-INF/neoforge.mods.toml @@ -3,8 +3,8 @@ loaderVersion="${loader_version_range}" license="${mod_license}" issueTrackerURL="https://github.com/MeAlam1/BlueLib/issues" [[mods]] -modId="${mod_id}" -version="${mod_version}" +modId="bluelib" +version="1.0.0" displayName="${mod_name}" # A URL to query for updates for this mod. See the JSON update specification https://docs.neoforged.net/docs/misc/updatechecker/ @@ -16,14 +16,14 @@ authors="${mod_authors}" description='''${mod_description}''' -[[dependencies.${mod_id}]] +[[dependencies.bluelib]] modId="neoforge" type="required" versionRange="${neo_version_range}" ordering="NONE" side="BOTH" -[[dependencies.${mod_id}]] +[[dependencies.bluelib]] modId="minecraft" type="required" versionRange="${minecraft_version_range}" diff --git a/NeoForge/src/main/resources/pack.mcmeta b/NeoForge/src/main/resources/pack.mcmeta index 325d954f..4830e6d5 100644 --- a/NeoForge/src/main/resources/pack.mcmeta +++ b/NeoForge/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { - "pack_format": 9, + "pack_format": 34, "description": "bluelib" } } \ No newline at end of file From f4fc518941a4fd827713f2c5f4b33412eb2be3c2 Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 5 Sep 2024 21:36:26 +0200 Subject: [PATCH 08/62] Fixed Forge not building properly --- Forge/build.gradle | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/Forge/build.gradle b/Forge/build.gradle index 2225558a..a60227c4 100644 --- a/Forge/build.gradle +++ b/Forge/build.gradle @@ -10,19 +10,11 @@ version = mod_version group = mod_group_id repositories { - maven { - name = 'GeckoLib' - url 'https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/' - content { - includeGroupByRegex("software\\.bernie.*") - includeGroup("com.eliotlash.mclib") - } - } + mavenLocal() maven { url "https://cursemaven.com" } mavenCentral() - mavenLocal() } base { @@ -115,8 +107,6 @@ tasks.named('jar', Jar).configure { 'Implementation-Vendor' : mod_authors ]) } - - finalizedBy 'reobfJar' } tasks.withType(JavaCompile).configureEach { From 8b11d0a502a2b713af81cc04e1ab6f4c0f862321 Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 12 Sep 2024 19:08:35 +0200 Subject: [PATCH 09/62] Added all Math Utils that anyone can ever think of that improve Math in Code * Still a WIP, Only for NeoForge --- .../example/entity/dragon/DragonEntity.java | 2 +- .../bluelib/example/entity/rex/RexEntity.java | 2 +- .../bluelib/utils/math/AlgebraicUtils.java | 95 ++++++++++ .../bluelib/utils/math/ConversionUtils.java | 65 +++++++ .../bluelib/utils/math/GeometricUtils.java | 169 ++++++++++++++++++ .../bluelib/utils/math/MatrixUtils.java | 98 ++++++++++ .../bluelib/utils/math/MiscUtils.java | 89 +++++++++ .../bluelib/utils/math/RandomGenUtils.java | 120 +++++++++++++ .../bluelib/utils/math/StatisticalUtils.java | 135 ++++++++++++++ .../utils/{ => variant}/ParameterUtils.java | 2 +- 10 files changed, 774 insertions(+), 3 deletions(-) create mode 100644 NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java create mode 100644 NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java create mode 100644 NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java create mode 100644 NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java create mode 100644 NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java create mode 100644 NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java create mode 100644 NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java rename NeoForge/src/main/java/software/bluelib/utils/{ => variant}/ParameterUtils.java (99%) diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 56a55393..081eff31 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -21,7 +21,7 @@ import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.util.GeckoLibUtil; import software.bluelib.interfaces.variant.IVariantEntity; -import software.bluelib.utils.ParameterUtils; +import software.bluelib.utils.variant.ParameterUtils; /** * A {@code DragonEntity} class representing a dragon entity in the game, which extends {@link TamableAnimal} diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index fdd27cb4..bacb1762 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -21,7 +21,7 @@ import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.util.GeckoLibUtil; import software.bluelib.interfaces.variant.IVariantEntity; -import software.bluelib.utils.ParameterUtils; +import software.bluelib.utils.variant.ParameterUtils; /** * A {@code RexEntity} class representing a Rex entity in the game, which extends {@link TamableAnimal} diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java new file mode 100644 index 00000000..9e74cdf4 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java @@ -0,0 +1,95 @@ +package software.bluelib.utils.math; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class AlgebraicUtils { + + /** + * A {@code double[]} that solves the quadratic equation {@code ax^2 + bx + c = 0} + * using the quadratic formula. + * + * @param pA {@link double} - The coefficient a of the quadratic equation. + * @param pB {@link double} - The coefficient b of the quadratic equation. + * @param pC {@link double} - The coefficient c of the quadratic equation. + * @return An array of roots of the quadratic equation. The array may be empty if there are no real roots. + * @author MeAlam + * @since 1.0.0 + */ + public static double[] solveQuadraticEquation(double pA, double pB, double pC) { + double discriminant = pB * pB - 4 * pA * pC; + if (discriminant < 0) { + return new double[0]; + } + double sqrtDiscriminant = Math.sqrt(discriminant); + double root1 = (-pB + sqrtDiscriminant) / (2 * pA); + double root2 = (-pB - sqrtDiscriminant) / (2 * pA); + return new double[] { root1, root2 }; + } + + /** + * A {@code long} that calculates the factorial of a non-negative integer. + * + * @param pNumber {@link int} - The non-negative integer. + * @return The factorial of the integer. + * @throws IllegalArgumentException if {@code pNumber} is negative. + * @author MeAlam + * @since 1.0.0 + */ + public static long factorial(int pNumber) { + if (pNumber < 0) { + throw new IllegalArgumentException("Number must be non-negative."); + } + long result = 1; + for (int i = 1; i <= pNumber; i++) { + result *= i; + } + return result; + } + + /** + * A {@code int} that calculates the greatest common divisor of two integers using the Euclidean algorithm. + * + * @param pA {@link int} - The first integer. + * @param pB {@link int} - The second integer. + * @return The greatest common divisor of {@code pA} and {@code pB}. + * @author MeAlam + * @since 1.0.0 + */ + public static int calculateGCD(int pA, int pB) { + while (pB != 0) { + int temp = pB; + pB = pA % pB; + pA = temp; + } + return pA; + } + + /** + * A {@code List>} that generates the power set (all subsets) of a given set. + * + * @param pSet {@link Set} - The input set. + * @param The type of elements in the set. + * @return A list of all subsets of the input set. + * @author MeAlam + * @since 1.0.0 + */ + public static List> generatePowerSet(Set pSet) { + List> powerSet = new ArrayList<>(); + powerSet.add(new HashSet<>()); + for (T element : pSet) { + List> newSubsets = new ArrayList<>(); + for (Set subset : powerSet) { + Set newSubset = new HashSet<>(subset); + newSubset.add(element); + newSubsets.add(newSubset); + } + powerSet.addAll(newSubsets); + } + return powerSet; + } + + +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java new file mode 100644 index 00000000..c142bf7c --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java @@ -0,0 +1,65 @@ +package software.bluelib.utils.math; + +public class ConversionUtils { + + /** + * A {@code double} that converts a length from inches to centimeters. + * + * @param pInches {@link double} - The length in inches. + * @return The length in centimeters. + * @author MeAlam + * @since 1.0.0 + */ + public static double inchesToCentimeters(double pInches) { + return pInches * 2.54; + } + + /** + * A {@code double} that converts a length from centimeters to inches. + * + * @param pCentimeters {@link double} - The length in centimeters. + * @return The length in inches. + * @since 1.0.0 + */ + public static double centimetersToInches(double pCentimeters) { + return pCentimeters / 2.54; + } + + + /** + * A {@code double} that converts a temperature from Celsius to Fahrenheit. + * + * @param pCelsius {@link double} - The temperature in Celsius. + * @return The temperature in Fahrenheit. + * @author MeAlam + * @since 1.0.0 + */ + public static double celsiusToFahrenheit(double pCelsius) { + return pCelsius * 9 / 5 + 32; + } + + /** + * A {@code double} that converts a temperature from Fahrenheit to Celsius. + * + * @param pFahrenheit {@link double} - The temperature in Fahrenheit. + * @return The temperature in Celsius. + * @since 1.0.0 + */ + public static double fahrenheitToCelsius(double pFahrenheit) { + return (pFahrenheit - 32) * 5 / 9; + } + + /** + * A {@code double} that converts a distance from kilometers to miles. + * + * @param pKilometers {@link double} - The distance in kilometers. + * @return The distance in miles. + * @author MeAlam + * @since 1.0.0 + */ + public static double kilometersToMiles(double pKilometers) { + return pKilometers * 0.621371; + } + + +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java new file mode 100644 index 00000000..3e428b50 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java @@ -0,0 +1,169 @@ +package software.bluelib.utils.math; + +public class GeometricUtils { + + /** + * A {@code double} that calculates the Euclidean distance between two points in 2D space. + * + * @param pX1 {@link double} - The x-coordinate of the first point. + * @param pY1 {@link double} - The y-coordinate of the first point. + * @param pX2 {@link double} - The x-coordinate of the second point. + * @param pY2 {@link double} - The y-coordinate of the second point. + * @return The distance between the two points. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateDistance2D(double pX1, double pY1, double pX2, double pY2) { + double dx = pX2 - pX1; + double dy = pY2 - pY1; + return Math.sqrt(dx * dx + dy * dy); + } + + /** + * A {@code double} that calculates the Euclidean distance between two points in 3D space. + * + * @param pX1 {@link double} - The x-coordinate of the first point. + * @param pY1 {@link double} - The y-coordinate of the first point. + * @param pZ1 {@link double} - The z-coordinate of the first point. + * @param pX2 {@link double} - The x-coordinate of the second point. + * @param pY2 {@link double} - The y-coordinate of the second point. + * @param pZ2 {@link double} - The z-coordinate of the second point. + * @return The distance between the two points in 3D space. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateDistance3D(double pX1, double pY1, double pZ1, double pX2, double pY2, double pZ2) { + double dx = pX2 - pX1; + double dy = pY2 - pY1; + double dz = pZ2 - pZ1; + return Math.sqrt(dx * dx + dy * dy + dz * dz); + } + + /** + * A {@code double} that calculates the area of a circle given its radius. + * + * @param pRadius {@link double} - The radius of the circle. + * @return The area of the circle. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateCircleArea(double pRadius) { + return Math.PI * pRadius * pRadius; + } + + /** + * A {@code double} that calculates the circumference of a circle given its radius. + * + * @param pRadius {@link double} - The radius of the circle. + * @return The circumference of the circle. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateCircleCircumference(double pRadius) { + return 2 * Math.PI * pRadius; + } + + /** + * A {@code double} that calculates the area of a rectangle given its width and height. + * + * @param pWidth {@link double} - The width of the rectangle. + * @param pHeight {@link double} - The height of the rectangle. + * @return The area of the rectangle. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateRectangleArea(double pWidth, double pHeight) { + return pWidth * pHeight; + } + + /** + * A {@code double} that calculates the perimeter of a rectangle given its width and height. + * + * @param pWidth {@link double} - The width of the rectangle. + * @param pHeight {@link double} - The height of the rectangle. + * @return The perimeter of the rectangle. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateRectanglePerimeter(double pWidth, double pHeight) { + return 2 * (pWidth + pHeight); + } + + /** + * A {@code double} that calculates the area of a triangle given its base and height. + * + * @param pBase {@link double} - The base of the triangle. + * @param pHeight {@link double} - The height of the triangle. + * @return The area of the triangle. + * @since 1.0.0 + */ + public static double calculateTriangleArea(double pBase, double pHeight) { + return 0.5 * pBase * pHeight; + } + + /** + * A {@code double} that calculates the perimeter of a triangle given its three sides. + * + * @param pSide1 {@link double} - The first side of the triangle. + * @param pSide2 {@link double} - The second side of the triangle. + * @param pSide3 {@link double} - The third side of the triangle. + * @return The perimeter of the triangle. + * @since 1.0.0 + */ + public static double calculateTrianglePerimeter(double pSide1, double pSide2, double pSide3) { + return pSide1 + pSide2 + pSide3; + } + + /** + * A {@code double} that calculates the volume of a sphere given its radius. + * + * @param pRadius {@link double} - The radius of the sphere. + * @return The volume of the sphere. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateSphereVolume(double pRadius) { + return (4.0 / 3.0) * Math.PI * Math.pow(pRadius, 3); + } + + /** + * A {@code double} that calculates the surface area of a cube given its side length. + * + * @param pSideLength {@link double} - The length of a side of the cube. + * @return The surface area of the cube. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateCubeSurfaceArea(double pSideLength) { + return 6 * Math.pow(pSideLength, 2); + } + + /** + * A {@code double} that calculates the volume of a cylinder given its radius and height. + * + * @param pRadius {@link double} - The radius of the cylinder's base. + * @param pHeight {@link double} - The height of the cylinder. + * @return The volume of the cylinder. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateCylinderVolume(double pRadius, double pHeight) { + return Math.PI * Math.pow(pRadius, 2) * pHeight; + } + + + /** + * A {@code double} that calculates the surface area of a cone given its radius and slant height. + * + * @param pRadius {@link double} - The radius of the base of the cone. + * @param pSlantHeight {@link double} - The slant height of the cone. + * @return The surface area of the cone. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateConeSurfaceArea(double pRadius, double pSlantHeight) { + return Math.PI * pRadius * (pRadius + pSlantHeight); + } + + +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java new file mode 100644 index 00000000..b6f338a9 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java @@ -0,0 +1,98 @@ +package software.bluelib.utils.math; + +public class MatrixUtils { + + /** + * A {@code double[][]} that performs matrix multiplication on two matrices. + * + * @param pMatrixA {@link double[][]} - The first matrix to be multiplied. + * @param pMatrixB {@link double[][]} - The second matrix to be multiplied. + * @return The product of the two matrices. + * @throws IllegalArgumentException if the number of columns in the first matrix does not match the number of rows in the second matrix. + * @author MeAlam + * @since 1.0.0 + */ + public static double[][] multiplyMatrices(double[][] pMatrixA, double[][] pMatrixB) { + int rowsA = pMatrixA.length; + int colsA = pMatrixA[0].length; + int colsB = pMatrixB[0].length; + if (colsA != pMatrixB.length) { + throw new IllegalArgumentException("Number of columns in the first matrix must be equal to the number of rows in the second matrix."); + } + double[][] result = new double[rowsA][colsB]; + for (int i = 0; i < rowsA; i++) { + for (int j = 0; j < colsB; j++) { + for (int k = 0; k < colsA; k++) { + result[i][j] += pMatrixA[i][k] * pMatrixB[k][j]; + } + } + } + return result; + } + + + /** + * A {@code double[][]} that computes the transpose of a matrix. + * + * @param pMatrix {@link double[][]} - The matrix to be transposed. + * @return The transposed matrix. + * @author MeAlam + * @since 1.0.0 + */ + public static double[][] transposeMatrix(double[][] pMatrix) { + int rows = pMatrix.length; + int cols = pMatrix[0].length; + double[][] transposed = new double[cols][rows]; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + transposed[j][i] = pMatrix[i][j]; + } + } + return transposed; + } + + /** + * A {@code double} that calculates the determinant of a 2x2 matrix. + * + * @param pMatrix {@link double[][]} - The 2x2 matrix. + * @return The determinant of the matrix. + * @throws IllegalArgumentException if the matrix is not 2x2. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { + if (pMatrix.length != 2 || pMatrix[0].length != 2) { + throw new IllegalArgumentException("Matrix must be 2x2."); + } + return pMatrix[0][0] * pMatrix[1][1] - pMatrix[0][1] * pMatrix[1][0]; + } + + + /** + * A {@code double[][]} that calculates the inverse of a 2x2 matrix. + * + * @param pMatrix {@link double[][]} - The 2x2 matrix. + * @return The inverse of the matrix. + * @throws IllegalArgumentException if the matrix is not invertible or not 2x2. + * @author MeAlam + * @since 1.0.0 + */ + public static double[][] invert2x2Matrix(double[][] pMatrix) { + if (pMatrix.length != 2 || pMatrix[0].length != 2) { + throw new IllegalArgumentException("Matrix must be 2x2."); + } + double determinant = calculate2x2MatrixDeterminant(pMatrix); + if (determinant == 0) { + throw new IllegalArgumentException("Matrix is not invertible."); + } + double[][] inverse = new double[2][2]; + inverse[0][0] = pMatrix[1][1] / determinant; + inverse[0][1] = -pMatrix[0][1] / determinant; + inverse[1][0] = -pMatrix[1][0] / determinant; + inverse[1][1] = pMatrix[0][0] / determinant; + return inverse; + } + + + +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java new file mode 100644 index 00000000..3ac038d7 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java @@ -0,0 +1,89 @@ +package software.bluelib.utils.math; + +public class MiscUtils { + + /** + * A {@code boolean} that checks if a string is a valid email address. + * + * @param pEmail {@link String} - The string to be checked. + * @return {@code true} if the string is a valid email address, {@code false} otherwise. + * @author MeAlam + * @since 1.0.0 + */ + public static boolean isValidEmail(String pEmail) { + String emailRegex = "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"; + return pEmail != null && pEmail.matches(emailRegex); + } + + + /** + * A {@code int} that converts a string to an integer, returning a default value if the string is not a valid integer. + * + * @param pString {@link String} - The string to be converted. + * @param pDefaultValue {@link int} - The default value to return if the string is not a valid integer. + * @return The integer value of the string, or {@code pDefaultValue} if the string is not a valid integer. + * @author MeAlam + * @since 1.0.0 + */ + public static int stringToIntWithDefault(String pString, int pDefaultValue) { + try { + return Integer.parseInt(pString); + } catch (NumberFormatException e) { + return pDefaultValue; + } + } + + /** + * A {@code int} that calculates the Levenshtein distance between two strings. + * + * @param pStr1 {@link String} - The first string. + * @param pStr2 {@link String} - The second string. + * @return The Levenshtein distance between the two strings. + * @author MeAlam + * @since 1.0.0 + */ + public static int calculateLevenshteinDistance(String pStr1, String pStr2) { + int[][] dp = new int[pStr1.length() + 1][pStr2.length() + 1]; + for (int i = 0; i <= pStr1.length(); i++) { + for (int j = 0; j <= pStr2.length(); j++) { + if (i == 0) { + dp[i][j] = j; + } else if (j == 0) { + dp[i][j] = i; + } else { + int cost = (pStr1.charAt(i - 1) == pStr2.charAt(j - 1)) ? 0 : 1; + dp[i][j] = Math.min( + Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1), + dp[i - 1][j - 1] + cost + ); + } + } + } + return dp[pStr1.length()][pStr2.length()]; + } + + /** + * A {@code int[]} that converts a hexadecimal color code to an RGB array. + * + * @param pHex {@link String} - The hexadecimal color code (e.g., "#FFFFFF"). + * @return An array containing the RGB values. + * @throws IllegalArgumentException if the hexadecimal color code is invalid. + * @author MeAlam + * @since 1.0.0 + */ + public static int[] hexToRGB(String pHex) { + if (pHex.charAt(0) == '#') { + pHex = pHex.substring(1); + } + if (pHex.length() != 6) { + throw new IllegalArgumentException("Invalid hex color code."); + } + int r = Integer.parseInt(pHex.substring(0, 2), 16); + int g = Integer.parseInt(pHex.substring(2, 4), 16); + int b = Integer.parseInt(pHex.substring(4, 6), 16); + return new int[]{r, g, b}; + } + + + +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java new file mode 100644 index 00000000..2dc7bb70 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java @@ -0,0 +1,120 @@ +package software.bluelib.utils.math; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class RandomGenUtils { + + /** + * A {@code int} that generates a random integer between a specified minimum and maximum value (inclusive). + * + * @param pMin {@link int} - The minimum value (inclusive). + * @param pMax {@link int} - The maximum value (inclusive). + * @return A random integer between {@code pMin} and {@code pMax}. + * @author MeAlam + * @since 1.0.0 + */ + public static int generateRandomInt(int pMin, int pMax) { + if (pMin > pMax) { + throw new IllegalArgumentException("Minimum value must not be greater than maximum value."); + } + return pMin + (int)(Math.random() * (pMax - pMin + 1)); + } + + /** + * A {@code double} that generates a random double between a specified minimum and maximum value (inclusive). + * + * @param pMin {@link double} - The minimum value (inclusive). + * @param pMax {@link double} - The maximum value (inclusive). + * @return A random double between {@code pMin} and {@code pMax}. + * @author MeAlam + * @since 1.0.0 + */ + public static double generateRandomDouble(double pMin, double pMax) { + if (pMin > pMax) { + throw new IllegalArgumentException("Minimum value must not be greater than maximum value."); + } + return pMin + Math.random() * (pMax - pMin); + } + + /** + * A {@code boolean} that generates a random boolean value. + * + * @return A random boolean value. + * @author MeAlam + * @since 1.0.0 + */ + public static boolean generateRandomBoolean() { + return Math.random() < 0.5; + } + + /** + * A {@code String} that generates a random alphanumeric string of a specified length. + * + * @param pLength {@link int} - The length of the string to be generated. + * @return A random alphanumeric string of the specified length. + * @throws IllegalArgumentException if {@code pLength} is negative. + * @author MeAlam + * @since 1.0.0 + */ + public static String generateRandomString(int pLength) { + if (pLength < 0) { + throw new IllegalArgumentException("Length must be non-negative."); + } + String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + StringBuilder sb = new StringBuilder(pLength); + for (int i = 0; i < pLength; i++) { + int index = (int) (Math.random() * characters.length()); + sb.append(characters.charAt(index)); + } + return sb.toString(); + } + + /** + * A {@code String} that generates a random alphanumeric string of a specified length with a specified prefix. + * + * @param pPrefix {@link String} - The prefix of the string. + * @param pLength {@link int} - The length of the string to be generated. + * @return A random alphanumeric string of the specified length with the specified prefix. + * @throws IllegalArgumentException if {@code pLength} is negative. + * @since 1.0.0 + */ + public static String generateRandomStringWithPrefix(String pPrefix, int pLength) { + if (pLength < 0) { + throw new IllegalArgumentException("Length must be non-negative."); + } + return pPrefix + generateRandomString(pLength - pPrefix.length()); + } + + /** + * A {@code Date} that converts a string to a {@link Date} object. + * + * @param pDateStr {@link String} - The date in string format (e.g., "yyyy-MM-dd"). + * @param pFormat {@link String} - The format of the input date string. + * @return The corresponding {@code Date} object. + * @throws ParseException if the string cannot be parsed. + * @author MeAlam + * @since 1.0.0 + */ + public static Date stringToDate(String pDateStr, String pFormat) throws ParseException { + SimpleDateFormat formatter = new SimpleDateFormat(pFormat); + return formatter.parse(pDateStr); + } + + /** + * A {@code String} that converts a {@link Date} object to a string in a specified format. + * + * @param pDate {@link Date} - The date to be converted. + * @param pFormat {@link String} - The desired date format (e.g., "yyyy-MM-dd"). + * @return The date as a string in the specified format. + * @author MeAlam + * @since 1.0.0 + */ + public static String dateToString(Date pDate, String pFormat) { + SimpleDateFormat formatter = new SimpleDateFormat(pFormat); + return formatter.format(pDate); + } + + +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java new file mode 100644 index 00000000..405b9363 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java @@ -0,0 +1,135 @@ +package software.bluelib.utils.math; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +public class StatisticalUtils { + + /** + * A {@code double} that calculates the mean (average) of an array of values. + * + * @param pValues {@link double[]} - The array of values. + * @return The mean of the values. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateMean(double[] pValues) { + double sum = 0; + for (double value : pValues) { + sum += value; + } + return sum / pValues.length; + } + + /** + * A {@code double} that calculates the median of an array of values. + * + * @param pValues {@link double[]} - The array of values. + * @return The median of the values. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateMedian(double[] pValues) { + double[] sorted = pValues.clone(); + Arrays.sort(sorted); + int middle = sorted.length / 2; + if (sorted.length % 2 == 0) { + return (sorted[middle - 1] + sorted[middle]) / 2.0; + } else { + return sorted[middle]; + } + } + + /** + * A {@code double} that calculates the mode (most frequent value) of an array of values. + * + * @param pValues {@link double[]} - The array of values. + * @return The mode of the values. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateMode(double[] pValues) { + Map frequencyMap = new HashMap<>(); + for (double value : pValues) { + frequencyMap.put(value, frequencyMap.getOrDefault(value, 0) + 1); + } + double mode = pValues[0]; + int maxCount = 0; + for (Map.Entry entry : frequencyMap.entrySet()) { + if (entry.getValue() > maxCount) { + maxCount = entry.getValue(); + mode = entry.getKey(); + } + } + return mode; + } + + /** + * A {@code double} that calculates the standard deviation of an array of values. + * + * @param pValues {@link double[]} - The array of values. + * @return The standard deviation of the values. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateStandardDeviation(double[] pValues) { + double mean = calculateMean(pValues); + double sumSquaredDifferences = 0; + for (double value : pValues) { + sumSquaredDifferences += Math.pow(value - mean, 2); + } + return Math.sqrt(sumSquaredDifferences / pValues.length); + } + + + /** + * A {@code double} that calculates the variance of an array of values. + * + * @param pValues {@link double[]} - The array of values. + * @return The variance of the values. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateVariance(double[] pValues) { + double mean = calculateMean(pValues); + double sumSquaredDifferences = 0; + for (double value : pValues) { + sumSquaredDifferences += Math.pow(value - mean, 2); + } + return sumSquaredDifferences / pValues.length; + } + + /** + * A {@code double} that calculates the range (difference between maximum and minimum) of an array of values. + * + * @param pValues {@link double[]} - The array of values. + * @return The range of the values. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateRange(double[] pValues) { + double max = Arrays.stream(pValues).max().orElseThrow(); + double min = Arrays.stream(pValues).min().orElseThrow(); + return max - min; + } + + /** + * A {@code double} that calculates the coefficient of variation of an array of values. + * + * @param pValues {@link double[]} - The array of values. + * @return The coefficient of variation of the values. + * @author MeAlam + * @since 1.0.0 + */ + public static double calculateCoefficientOfVariation(double[] pValues) { + double mean = calculateMean(pValues); + double stdDev = calculateStandardDeviation(pValues); + return (stdDev / mean) * 100; + } + + + + + +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/ParameterUtils.java b/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java similarity index 99% rename from NeoForge/src/main/java/software/bluelib/utils/ParameterUtils.java rename to NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java index 3994cdf5..160bba35 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/ParameterUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java @@ -1,6 +1,6 @@ // Copyright (c) BlueLib. Licensed under the MIT License. -package software.bluelib.utils; +package software.bluelib.utils.variant; import software.bluelib.entity.variant.VariantParameter; import software.bluelib.entity.variant.VariantLoader; From 97b8c67eac2543ca910f0feb32c7e23193c07865 Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 12 Sep 2024 19:12:55 +0200 Subject: [PATCH 10/62] Forgot Miles to Kilometers --- .../software/bluelib/utils/math/ConversionUtils.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java index c142bf7c..e551be0d 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java @@ -61,5 +61,15 @@ public static double kilometersToMiles(double pKilometers) { return pKilometers * 0.621371; } + /** + * A {@code double} that converts a distance from miles to kilometers. + * + * @param pMiles {@link double} - The distance in miles. + * @return The distance in kilometers. + * @since 1.0.0 + */ + public static double milesToKilometers(double pMiles) { + return pMiles / 0.621371; + } } From 2048a25cbed0792927d46577b8f313d500d954cb Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 12 Sep 2024 19:15:14 +0200 Subject: [PATCH 11/62] Moved some code around --- .../bluelib/utils/math/ConversionUtils.java | 33 +++++++++++++++++++ .../bluelib/utils/math/RandomGenUtils.java | 29 ---------------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java index e551be0d..87c610fc 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java @@ -1,5 +1,9 @@ package software.bluelib.utils.math; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + public class ConversionUtils { /** @@ -72,4 +76,33 @@ public static double milesToKilometers(double pMiles) { return pMiles / 0.621371; } + /** + * A {@code Date} that converts a string to a {@link Date} object. + * + * @param pDateStr {@link String} - The date in string format (e.g., "yyyy-MM-dd"). + * @param pFormat {@link String} - The format of the input date string. + * @return The corresponding {@code Date} object. + * @throws ParseException if the string cannot be parsed. + * @author MeAlam + * @since 1.0.0 + */ + public static Date stringToDate(String pDateStr, String pFormat) throws ParseException { + SimpleDateFormat formatter = new SimpleDateFormat(pFormat); + return formatter.parse(pDateStr); + } + + /** + * A {@code String} that converts a {@link Date} object to a string in a specified format. + * + * @param pDate {@link Date} - The date to be converted. + * @param pFormat {@link String} - The desired date format (e.g., "yyyy-MM-dd"). + * @return The date as a string in the specified format. + * @author MeAlam + * @since 1.0.0 + */ + public static String dateToString(Date pDate, String pFormat) { + SimpleDateFormat formatter = new SimpleDateFormat(pFormat); + return formatter.format(pDate); + } + } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java index 2dc7bb70..8593475b 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java @@ -87,34 +87,5 @@ public static String generateRandomStringWithPrefix(String pPrefix, int pLength) return pPrefix + generateRandomString(pLength - pPrefix.length()); } - /** - * A {@code Date} that converts a string to a {@link Date} object. - * - * @param pDateStr {@link String} - The date in string format (e.g., "yyyy-MM-dd"). - * @param pFormat {@link String} - The format of the input date string. - * @return The corresponding {@code Date} object. - * @throws ParseException if the string cannot be parsed. - * @author MeAlam - * @since 1.0.0 - */ - public static Date stringToDate(String pDateStr, String pFormat) throws ParseException { - SimpleDateFormat formatter = new SimpleDateFormat(pFormat); - return formatter.parse(pDateStr); - } - - /** - * A {@code String} that converts a {@link Date} object to a string in a specified format. - * - * @param pDate {@link Date} - The date to be converted. - * @param pFormat {@link String} - The desired date format (e.g., "yyyy-MM-dd"). - * @return The date as a string in the specified format. - * @author MeAlam - * @since 1.0.0 - */ - public static String dateToString(Date pDate, String pFormat) { - SimpleDateFormat formatter = new SimpleDateFormat(pFormat); - return formatter.format(pDate); - } - } From f708b04d5dabab89f483e7fc1b476b3696b0addf Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 12 Sep 2024 20:52:10 +0200 Subject: [PATCH 12/62] Cleaned up --- .../java/software/bluelib/utils/math/StatisticalUtils.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java index 405b9363..1e7e906e 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java @@ -127,9 +127,4 @@ public static double calculateCoefficientOfVariation(double[] pValues) { double stdDev = calculateStandardDeviation(pValues); return (stdDev / mean) * 100; } - - - - - } From 36c00f8ff4cb30810fd3993dd21912d3d4df38ee Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 12 Sep 2024 23:23:31 +0200 Subject: [PATCH 13/62] Finished ChunkUtils * Only isChunkLoaded is broken --- .../example/entity/dragon/DragonEntity.java | 8 + .../bluelib/utils/math/AlgebraicUtils.java | 2 + .../bluelib/utils/math/ConversionUtils.java | 2 + .../bluelib/utils/math/GeometricUtils.java | 2 + .../bluelib/utils/math/MatrixUtils.java | 2 + .../bluelib/utils/math/MiscUtils.java | 2 + .../bluelib/utils/math/RandomGenUtils.java | 6 +- .../bluelib/utils/math/StatisticalUtils.java | 2 + .../bluelib/utils/minecraft/ChunkUtils.java | 177 ++++++++++++++++++ 9 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 081eff31..e8edac91 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -12,8 +12,10 @@ import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import software.bernie.geckolib.animatable.GeoEntity; @@ -21,8 +23,12 @@ import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.util.GeckoLibUtil; import software.bluelib.interfaces.variant.IVariantEntity; +import software.bluelib.utils.minecraft.ChunkUtils; import software.bluelib.utils.variant.ParameterUtils; +import java.util.Arrays; +import java.util.Collection; + /** * A {@code DragonEntity} class representing a dragon entity in the game, which extends {@link TamableAnimal} * and implements {@link IVariantEntity} and {@link GeoEntity}. @@ -158,6 +164,8 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul .withParameter("array") .connect(); } + int Check = ChunkUtils.getChunkBlockCount(pLevel.getLevel(), new ChunkPos(this.blockPosition())); + System.out.println(Check); return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java index 9e74cdf4..79a37df5 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.utils.math; import java.util.ArrayList; diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java index 87c610fc..6c4a7c22 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.utils.math; import java.text.ParseException; diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java index 3e428b50..8d219116 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.utils.math; public class GeometricUtils { diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java index b6f338a9..07c4ea5f 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.utils.math; public class MatrixUtils { diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java index 3ac038d7..6640780d 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.utils.math; public class MiscUtils { diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java index 8593475b..767996ae 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java @@ -1,8 +1,6 @@ -package software.bluelib.utils.math; +// Copyright (c) BlueLib. Licensed under the MIT License. -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; +package software.bluelib.utils.math; public class RandomGenUtils { diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java index 1e7e906e..98364748 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.utils.math; import java.util.Arrays; diff --git a/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java b/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java new file mode 100644 index 00000000..05bbfb12 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java @@ -0,0 +1,177 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.utils.minecraft; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * A {@code ChunkUtils} class providing utility methods for interacting with Minecraft chunks, + * specifically focusing on retrieving biome and tile entity information. + * + * Key Methods: + *
    + *
  • {@link #getBiomeOfChunk(Level, ChunkPos)} - Returns the {@link Biome} of the chunk.
  • + *
  • {@link #getBiomeRegistryNameOfChunk(Level, ChunkPos)} - Retrieves the biome registry name of the chunk.
  • + *
  • {@link #getChunkTileEntities(Level, ChunkPos)} - Gets the tile entities within the chunk.
  • + *
+ * @author MeAlam + * @since 1.0.0 + */ +public class ChunkUtils { + + /** + * A {@link Biome} that retrieves the biome of a chunk. + * + * @param pLevel {@link Level} - The game world level. + * @param pChunkPos {@link ChunkPos} - The position of the chunk. + * @return The {@link Biome} associated with the specified chunk. + */ + public static Biome getBiomeOfChunk(Level pLevel, ChunkPos pChunkPos) { + return Objects.requireNonNull(pLevel.getBiome(pChunkPos.getWorldPosition()).value()); + } + + /** + * A {@link String} representing the registry name of the biome of a chunk. + * Example: "minecraft:plains", "minecraft:desert" + * + * @param pLevel {@link Level} - The game world level. + * @param pChunkPos {@link ChunkPos} - The position of the chunk. + * @return The registry name of the chunk's biome as a {@link String}. + */ + public static String getBiomeRegistryNameOfChunk(Level pLevel, ChunkPos pChunkPos) { + return Objects.requireNonNull(pLevel.registryAccess() + .registryOrThrow(Registries.BIOME) + .getKey(pLevel.getBiome(pChunkPos.getWorldPosition()).value())).toString(); + } + + /** + * A {@link String} that retrieves the simple name of the biome in the chunk. + * Example: "plains", "desert" + * + * @param pLevel {@link Level} - The game world level. + * @param pChunkPos {@link ChunkPos} - The position of the chunk. + * @return The simple name of the chunk's biome. + */ + public static String getBiomeSimpleNameOfChunk(Level pLevel, ChunkPos pChunkPos) { + String registryName = getBiomeRegistryNameOfChunk(pLevel, pChunkPos); + return registryName.contains(":") ? registryName.split(":")[1] : registryName; + } + + /** + * A {@link Collection} of {@link BlockEntity} that retrieves the tile entities in a chunk. + * + * @param pLevel {@link Level} - The game world level. + * @param pChunkPos {@link ChunkPos} - The position of the chunk. + * @return A collection of tile entities present in the specified chunk. + */ + public static Collection getChunkTileEntities(Level pLevel, ChunkPos pChunkPos) { + LevelChunk chunk = pLevel.getChunk(pChunkPos.x, pChunkPos.z); + return chunk.getBlockEntities().values(); + } + + /** + * A {@link String} that retrieves the registry names of tile entities in a chunk. + * Example: "minecraft:chest, minecraft:furnace" + * + * @param pLevel {@link Level} - The game world level. + * @param pChunkPos {@link ChunkPos} - The position of the chunk. + * @return A comma-separated string of tile entity registry names in the chunk. + */ + public static String getChunkTileEntitiesRegistryNames(Level pLevel, ChunkPos pChunkPos) { + Collection blockEntities = getChunkTileEntities(pLevel, pChunkPos); + + return blockEntities.stream() + .map(blockEntity -> { + ResourceLocation key = pLevel.registryAccess() + .registryOrThrow(Registries.BLOCK_ENTITY_TYPE) + .getKey(blockEntity.getType()); + + return key != null ? key.toString() : "unknown"; + }) + .collect(Collectors.joining(", ")); + } + + /** + * A {@link String} that retrieves the simple names of tile entities in a chunk. + * Example: "chest, furnace" + * + * @param pLevel {@link Level} - The game world level. + * @param pChunkPos {@link ChunkPos} - The position of the chunk. + * @return A comma-separated string of tile entity simple names in the chunk. + */ + public static String getChunkTileEntitiesSimpleNames(Level pLevel, ChunkPos pChunkPos) { + String registryNames = getChunkTileEntitiesRegistryNames(pLevel, pChunkPos); + + return Arrays.stream(registryNames.split(", ")) + .map(fullName -> fullName.contains(":") ? fullName.split(":")[1] : fullName) + .collect(Collectors.joining(", ")); + } + + /** + * An {@code int} that counts the number of non-air blocks in the chunk. + * + * @param pLevel {@link Level} - The game world level. + * @param pChunkPos {@link ChunkPos} - The position of the chunk. + * @return The number of non-air blocks in the specified chunk. + */ + public static int getChunkBlockCount(Level pLevel, ChunkPos pChunkPos) { + LevelChunk chunk = pLevel.getChunk(pChunkPos.x, pChunkPos.z); + int blockCount = 0; + + for (int x = 0; x < 16; x++) { + for (int y = pLevel.getMinBuildHeight(); y < pLevel.getHeight(); y++) { + for (int z = 0; z < 16; z++) { + BlockPos worldPos = new BlockPos(pChunkPos.getMinBlockX() + x, y, pChunkPos.getMinBlockZ() + z); + if (!chunk.getBlockState(worldPos).isAir()) { + blockCount++; + } + } + } + } + return blockCount; + } + +//FIXME: This method is not working as expected, Only returns true in SpawnChunks in stead of all loaded chunks. + /** + public static boolean isChunkLoaded(final LevelAccessor world, final int x, final int z) { + if (world.getChunkSource() instanceof ServerChunkCache chunkCache) { + final CompletableFuture> future = chunkCache.getChunkFuture(x, z, ChunkStatus.FULL, false); + + try { + boolean isFutureDone = future.isDone(); + ChunkResult chunkResult = future.getNow(ChunkHolder.UNLOADED_CHUNK); + + if (chunkResult instanceof ChunkResult.Fail) { + System.out.println("Chunk at (" + x + ", " + z + ") failed to load with error: " + chunkResult); + return false; + } + + boolean isChunkLoaded = chunkResult != ChunkHolder.UNLOADED_CHUNK && chunkResult.isSuccess(); + System.out.println("Chunk at (" + x + ", " + z + ") future done: " + isFutureDone); + System.out.println("Chunk at (" + x + ", " + z + ") loaded: " + isChunkLoaded); + + return isChunkLoaded; + } catch (Exception e) { + e.printStackTrace(); + System.out.println("Error checking chunk loading status at (" + x + ", " + z + "): " + e.getMessage()); + return false; + } + } + boolean isLoaded = world.getChunk(x, z, ChunkStatus.FULL, false) != null; + System.out.println("Chunk at (" + x + ", " + z + ") loaded: " + isLoaded); + return isLoaded; + }*/ + +} From 29eb663693bc12e78bb5ab986c78d48c93a14274 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 18 Sep 2024 20:41:36 +0200 Subject: [PATCH 14/62] Added Custom Logging and Exceptions * Still Need to Update Comments --- .../main/java/software/bluelib/BlueLib.java | 32 ++-- .../bluelib/entity/variant/VariantLoader.java | 59 +++----- .../entity/variant/VariantParameter.java | 25 +++- .../entity/variant/base/ParameterBase.java | 41 ++++-- .../bluelib/event/ReloadEventHandler.java | 11 +- .../example/entity/dragon/DragonEntity.java | 4 +- .../bluelib/exception/CouldNotLoadJSON.java | 64 -------- .../interfaces/logging/ILogColorProvider.java | 7 + .../interfaces/variant/IVariantEntity.java | 12 +- .../variant/base/IVariantEntityBase.java | 5 +- .../software/bluelib/json/JSONLoader.java | 16 +- .../software/bluelib/json/JSONMerger.java | 21 ++- .../bluelib/utils/logging/BaseLogger.java | 69 +++++++++ .../utils/logging/BlueLibLogLevel.java | 12 ++ .../logging/DefaultLogColorProvider.java | 25 ++++ .../bluelib/utils/logging/LoggerConfig.java | 29 ++++ .../bluelib/utils/math/AlgebraicUtils.java | 22 ++- .../bluelib/utils/math/ConversionUtils.java | 21 ++- .../bluelib/utils/math/GeometricUtils.java | 55 ++++++- .../bluelib/utils/math/MatrixUtils.java | 23 +-- .../bluelib/utils/math/MiscUtils.java | 31 ++-- .../bluelib/utils/math/RandomGenUtils.java | 20 ++- .../bluelib/utils/math/StatisticalUtils.java | 82 +++++++++-- .../bluelib/utils/minecraft/ChunkUtils.java | 139 +++++++++++------- .../bluelib/utils/variant/ParameterUtils.java | 12 +- 25 files changed, 572 insertions(+), 265 deletions(-) delete mode 100644 NeoForge/src/main/java/software/bluelib/exception/CouldNotLoadJSON.java create mode 100644 NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java create mode 100644 NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java create mode 100644 NeoForge/src/main/java/software/bluelib/utils/logging/BlueLibLogLevel.java create mode 100644 NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java create mode 100644 NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java diff --git a/NeoForge/src/main/java/software/bluelib/BlueLib.java b/NeoForge/src/main/java/software/bluelib/BlueLib.java index 99d1bc8d..29d5e2e9 100644 --- a/NeoForge/src/main/java/software/bluelib/BlueLib.java +++ b/NeoForge/src/main/java/software/bluelib/BlueLib.java @@ -8,9 +8,9 @@ import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLLoadCompleteEvent; import net.neoforged.fml.loading.FMLEnvironment; -import net.neoforged.neoforge.common.NeoForge; import software.bluelib.example.event.ClientEvents; import software.bluelib.example.init.ModEntities; +import software.bluelib.utils.logging.BaseLogger; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -48,7 +48,7 @@ public class BlueLib { * @Co-author MeAlam, Dan * @since 1.0.0 */ - private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1); /** * The Mod ID for {@link BlueLib}. This serves as a unique identifier for the mod. @@ -72,7 +72,6 @@ public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { pModEventBus.register(this); if (isDeveloperMode()) { ModEntities.REGISTRY.register(pModEventBus); - if (FMLEnvironment.dist.isClient()) { pModEventBus.addListener(ClientEvents::registerAttributes); pModEventBus.addListener(ClientEvents::registerRenderers); @@ -94,17 +93,14 @@ public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { @SubscribeEvent public void onLoadComplete(FMLLoadCompleteEvent pEvent) { if (isDeveloperMode()) { - scheduler.schedule(() -> { - System.out.println(""" - - ************************************************** - * * - * Thank you for using BlueLib! * - * We appreciate your support. * - * * - ************************************************** - """); - scheduler.shutdown(); + SCHEDULER.schedule(() -> { + BaseLogger.logBlueLib("**************************************************"); + BaseLogger.logBlueLib(" "); + BaseLogger.logBlueLib(" Thank you for using BlueLib! "); + BaseLogger.logBlueLib(" We appreciate your support. "); + BaseLogger.logBlueLib(" "); + BaseLogger.logBlueLib("**************************************************"); + SCHEDULER.shutdown(); }, 3, TimeUnit.SECONDS); } } @@ -121,6 +117,12 @@ public void onLoadComplete(FMLLoadCompleteEvent pEvent) { * @since 1.0.0 */ static boolean isDeveloperMode() { - return !FMLEnvironment.production; + boolean isDevMode = !FMLEnvironment.production; + if (isDevMode) { + BaseLogger.bluelibLogSuccess("Running in Developer mode."); + } else { + BaseLogger.bluelibLogSuccess("Running in Production mode."); + } + return isDevMode; } } diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java index 3dc0034b..b49faf66 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -11,6 +11,7 @@ import software.bluelib.interfaces.variant.base.IVariantEntityBase; import software.bluelib.json.JSONLoader; import software.bluelib.json.JSONMerger; +import software.bluelib.utils.logging.BaseLogger; import java.util.ArrayList; import java.util.HashMap; @@ -32,25 +33,8 @@ */ public class VariantLoader implements IVariantEntityBase { - /** - * A {@link Map} to store loaded {@link VariantParameter} for each entity type. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ private static final Map> entityVariantsMap = new HashMap<>(); - - /** - * A {@link JSONLoader} instance to load JSON data. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ private static final JSONLoader jsonLoader = new JSONLoader(); - - /** - * A {@link JSONMerger} instance to merge JSON data. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ private static final JSONMerger jsonMerger = new JSONMerger(); /** @@ -61,33 +45,36 @@ public class VariantLoader implements IVariantEntityBase { * @param pJSONLocationData {@link ResourceLocation} - The {@link ResourceLocation} of the Latest DataPack's JSON data. * @param pServer {@link MinecraftServer} - The {@link MinecraftServer} instance. * @param pEntityName {@link String} - The name of the entity whose variants should be cleared before loading new ones. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 */ public static void loadVariants(ResourceLocation pJSONLocationMod, ResourceLocation pJSONLocationData, MinecraftServer pServer, String pEntityName) { + BaseLogger.bluelibLogInfo("Starting to load variants for entity: " + pEntityName); + clearVariantsForEntity(pEntityName); + ResourceManager resourceManager = pServer.getResourceManager(); JsonObject mergedJsonObject = new JsonObject(); - JsonObject modJson = jsonLoader.loadJson(pJSONLocationMod, resourceManager); - JsonObject dataJson = jsonLoader.loadJson(pJSONLocationData, resourceManager); + try { + JsonObject modJson = jsonLoader.loadJson(pJSONLocationMod, resourceManager); + JsonObject dataJson = jsonLoader.loadJson(pJSONLocationData, resourceManager); - jsonMerger.mergeJsonObjects(mergedJsonObject, modJson); - jsonMerger.mergeJsonObjects(mergedJsonObject, dataJson); + jsonMerger.mergeJsonObjects(mergedJsonObject, modJson); + jsonMerger.mergeJsonObjects(mergedJsonObject, dataJson); - parseVariants(mergedJsonObject); + BaseLogger.bluelibLogInfo("Successfully loaded and merged JSON data for entity: " + pEntityName); + parseVariants(mergedJsonObject); + } catch (Exception pException) { + BaseLogger.logError("Failed to load variants for entity: " + pEntityName, pException); + } } /** * A {@code void} method that clears variants for a specific entity type from the map. * * @param pEntityName {@link String} - The name of the entity whose variants should be cleared. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 */ private static void clearVariantsForEntity(String pEntityName) { + BaseLogger.bluelibLogInfo("Clearing variants for entity: " + pEntityName); entityVariantsMap.remove(pEntityName); } @@ -95,15 +82,13 @@ private static void clearVariantsForEntity(String pEntityName) { * A {@code void} method that parses the merged JSON data and converts it into {@link VariantParameter} instances. * * @param pJsonObject {@link JsonObject} - The merged {@link JsonObject} containing variant data. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 */ private static void parseVariants(JsonObject pJsonObject) { for (Map.Entry entry : pJsonObject.entrySet()) { String entityName = entry.getKey(); JsonArray textureArray = entry.getValue().getAsJsonArray(); + BaseLogger.bluelibLogInfo("Parsing variants for entity: " + entityName); List variantList = entityVariantsMap.computeIfAbsent(entityName, k -> new ArrayList<>()); for (JsonElement variant : textureArray) { @@ -125,9 +110,6 @@ private static void parseVariants(JsonObject pJsonObject) { * @param pJsonKey {@link String} - The key associated with this variant. * @param pJsonObject {@link JsonObject} - The {@link JsonObject} containing the variant data. * @return A {@link VariantParameter} instance. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 */ private static VariantParameter getEntityVariant(String pJsonKey, JsonObject pJsonObject) { return new VariantParameter(pJsonKey, pJsonObject); @@ -139,11 +121,9 @@ private static VariantParameter getEntityVariant(String pJsonKey, JsonObject pJs * * @param pEntityName {@link String} - The name of the entity to retrieve variants for. * @return A {@link List} of {@link VariantParameter} instances for the specified entity. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 */ public static List getVariantsFromEntity(String pEntityName) { + BaseLogger.bluelibLogInfo("Retrieving variants for entity: " + pEntityName); return entityVariantsMap.getOrDefault(pEntityName, new ArrayList<>()); } @@ -153,17 +133,16 @@ public static List getVariantsFromEntity(String pEntityName) { * @param pEntityName {@link String} - The name of the entity to retrieve variants for. * @param pVariantName {@link String} - The name of the variant to retrieve. * @return The {@link VariantParameter} with the specified name, or {@code null} if not found. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 */ public static VariantParameter getVariantByName(String pEntityName, String pVariantName) { + BaseLogger.bluelibLogInfo("Retrieving variant by name: " + pVariantName + " for entity: " + pEntityName); List variants = getVariantsFromEntity(pEntityName); for (VariantParameter variant : variants) { if (variant.getVariantName().equals(pVariantName)) { return variant; } } + BaseLogger.logWarning("Variant with name: " + pVariantName + " not found for entity: " + pEntityName); return null; } } diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java index db3d3319..82e42718 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java @@ -5,6 +5,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import software.bluelib.entity.variant.base.ParameterBase; +import software.bluelib.utils.logging.BaseLogger; import java.util.Map; import java.util.Set; @@ -59,14 +60,19 @@ public class VariantParameter extends ParameterBase { */ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { if (pJsonKey == null || pJsonObject == null) { - throw new IllegalArgumentException("JSON key and object must not be null"); + Throwable throwable = new Throwable("JSON key or JSON object is null"); + IllegalArgumentException exception = new IllegalArgumentException("JSON key and object must not be null"); + BaseLogger.logError(exception.toString(), throwable); + throw exception; } this.jsonKey = pJsonKey; + BaseLogger.bluelibLogInfo("Creating VariantParameter with JSON key: " + pJsonKey); Set> entryMap = pJsonObject.entrySet(); for (Map.Entry entry : entryMap) { JsonElement element = entry.getValue(); if (element.isJsonPrimitive()) { addParameter(entry.getKey(), element.getAsString()); + BaseLogger.bluelibLogInfo("Added primitive parameter: " + entry.getKey() + " = " + element.getAsString()); } else if (element.isJsonArray()) { StringBuilder arrayValues = new StringBuilder(); element.getAsJsonArray().forEach(e -> arrayValues.append(e.getAsString()).append(",")); @@ -74,10 +80,13 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { arrayValues.setLength(arrayValues.length() - 1); } addParameter(entry.getKey(), arrayValues.toString()); + BaseLogger.bluelibLogInfo("Added array parameter: " + entry.getKey() + " = " + arrayValues.toString()); } else if (element.isJsonObject()) { addParameter(entry.getKey(), element.toString()); + BaseLogger.bluelibLogInfo("Added object parameter: " + entry.getKey() + " = " + element.toString()); } else { addParameter(entry.getKey(), "null"); + BaseLogger.bluelibLogInfo("Added null parameter for key: " + entry.getKey()); } } } @@ -95,8 +104,12 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { */ public String getJsonKey() { if (this.jsonKey == null) { - throw new IllegalStateException("JSON key should not be null"); + Throwable throwable = new Throwable("JSON key should not be null"); + IllegalStateException exception = new IllegalStateException("JSON key is unexpectedly null when retrieving from VariantParameter."); + BaseLogger.logError(exception.toString(), throwable); + throw exception; } + BaseLogger.bluelibLogSuccess("Retrieved JSON key: " + this.jsonKey); return this.jsonKey; } @@ -111,7 +124,9 @@ public String getJsonKey() { * @since 1.0.0 */ public String getVariantName() { - return getParameter("variantName"); + String variantName = getParameter("variantName"); + BaseLogger.bluelibLogSuccess("Retrieved variant name: " + variantName); + return variantName; } /** @@ -126,6 +141,8 @@ public String getVariantName() { * @since 1.0.0 */ public String getParameter(String pKey) { - return (String) super.getParameter(pKey); + String value = (String) super.getParameter(pKey); + BaseLogger.bluelibLogSuccess("Retrieved parameter for key " + pKey + ": " + value); + return value; } } diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java index 2f1af3a1..e0ffa79d 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java @@ -2,6 +2,8 @@ package software.bluelib.entity.variant.base; +import software.bluelib.utils.logging.BaseLogger; + import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -48,6 +50,7 @@ public abstract class ParameterBase { */ protected void addParameter(String pKey, Object pValue) { parameters.put(pKey, pValue); + BaseLogger.bluelibLogSuccess(String.format("Parameter added: Key = %s, Value = %s", pKey, pValue)); } /** @@ -60,11 +63,13 @@ protected void addParameter(String pKey, Object pValue) { * @since 1.0.0 */ protected Object getParameter(String pKey) { - return parameters.get(pKey); + Object value = parameters.get(pKey); + BaseLogger.bluelibLogSuccess(String.format("Parameter retrieved: Key = %s, Value = %s", pKey, value)); + return value; } /** - * A {@code Void} that removes a parameter from the collection by its key. + * A {@code void} method that removes a parameter from the collection by its key. * * @param pKey {@link String} - The key of the parameter to remove. * @author MeAlam @@ -72,18 +77,23 @@ protected Object getParameter(String pKey) { * @since 1.0.0 */ protected void removeParameter(String pKey) { - parameters.remove(pKey); + if (parameters.remove(pKey) != null) { + BaseLogger.bluelibLogSuccess(String.format("Parameter removed: Key = %s", pKey)); + } else { + BaseLogger.logWarning(String.format("Attempted to remove non-existent parameter: Key = %s", pKey)); + } } /** - * A {@link Map} method that returns all parameters in the collection. + * A {@link Map} method that returns all parameters in the collection. * - * @return A {@link Map} containing all parameters. + * @return A {@link Map} containing all parameters. * @author MeAlam * @Co-author Dan * @since 1.0.0 */ protected Map getAllParameters() { + BaseLogger.bluelibLogSuccess("Retrieved all parameters."); return new HashMap<>(parameters); } @@ -97,7 +107,9 @@ protected Map getAllParameters() { * @since 1.0.0 */ protected boolean containsParameter(String pKey) { - return parameters.containsKey(pKey); + boolean exists = parameters.containsKey(pKey); + BaseLogger.bluelibLogInfo(String.format("Parameter existence check: Key = %s, Exists = %b", pKey, exists)); + return exists; } /** @@ -109,7 +121,9 @@ protected boolean containsParameter(String pKey) { * @since 1.0.0 */ protected boolean isEmpty() { - return parameters.isEmpty(); + boolean empty = parameters.isEmpty(); + BaseLogger.bluelibLogInfo("Checked if parameters are empty: " + empty); + return empty; } /** @@ -121,6 +135,7 @@ protected boolean isEmpty() { */ protected void clearParameters() { parameters.clear(); + BaseLogger.bluelibLogSuccess("Cleared all parameters."); } /** @@ -132,7 +147,9 @@ protected void clearParameters() { * @since 1.0.0 */ protected int getParameterCount() { - return parameters.size(); + int count = parameters.size(); + BaseLogger.bluelibLogSuccess("Retrieved parameter count: " + count); + return count; } /** @@ -144,6 +161,7 @@ protected int getParameterCount() { * @since 1.0.0 */ protected Set getParameterKeys() { + BaseLogger.bluelibLogSuccess("Retrieved parameter keys."); return parameters.keySet(); } @@ -156,6 +174,7 @@ protected Set getParameterKeys() { * @since 1.0.0 */ protected Collection getParameterValues() { + BaseLogger.bluelibLogSuccess("Retrieved parameter values."); return parameters.values(); } @@ -172,8 +191,12 @@ protected Collection getParameterValues() { protected void updateParameter(String pKey, Object pNewValue) { if (parameters.containsKey(pKey)) { parameters.put(pKey, pNewValue); + BaseLogger.bluelibLogInfo(String.format("Parameter updated: Key = %s, New Value = %s", pKey, pNewValue)); } else { - throw new IllegalArgumentException("Key does not exist: " + pKey); + Throwable throwable = new Throwable("Key does not exist: " + pKey); + IllegalArgumentException exception = new IllegalArgumentException("Key does not exist: " + pKey); + BaseLogger.logError(String.format("Attempted to update non-existent parameter: Key = %s", pKey), throwable); + throw exception; } } } diff --git a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java index 9da36f9a..2405cb96 100644 --- a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -6,6 +6,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import software.bluelib.entity.variant.VariantLoader; +import software.bluelib.utils.logging.BaseLogger; /** * A {@code ReloadEventHandler} class responsible for handling events related to reloading entity variants. @@ -67,12 +68,18 @@ public class ReloadEventHandler { protected static void registerEntityVariants(MinecraftServer pServer, String pEntityName, String pModID, String pModPathLocation, String pDataPathLocation) { ResourceLocation modLocation = ResourceLocation.fromNamespaceAndPath(pModID, pModPathLocation); ResourceLocation dataLocation = ResourceLocation.fromNamespaceAndPath(pModID, pDataPathLocation); + + BaseLogger.bluelibLogInfo("Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID); + try { VariantLoader.loadVariants(modLocation, dataLocation, pServer, pEntityName); + BaseLogger.bluelibLogSuccess("Successfully registered entity variants for " + pEntityName + " from ModID: " + pModID); } catch (JsonParseException pException) { - throw new RuntimeException("Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from Mod with ModID: " + pModID, pException); + BaseLogger.logError("Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); + throw pException; } catch (Exception pException) { - throw new RuntimeException("Unexpected error occurred while registering entity variants for " + pEntityName + " from Mod with ModID: " + pModID, pException); + BaseLogger.logError("Unexpected error occurred while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); + throw pException; } } } diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index e8edac91..8078c6ae 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -23,6 +23,7 @@ import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.util.GeckoLibUtil; import software.bluelib.interfaces.variant.IVariantEntity; +import software.bluelib.utils.logging.BaseLogger; import software.bluelib.utils.minecraft.ChunkUtils; import software.bluelib.utils.variant.ParameterUtils; @@ -164,8 +165,7 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul .withParameter("array") .connect(); } - int Check = ChunkUtils.getChunkBlockCount(pLevel.getLevel(), new ChunkPos(this.blockPosition())); - System.out.println(Check); + BaseLogger.logSuccess("Dragon Spawned with Variant: " + getVariantName()); return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } diff --git a/NeoForge/src/main/java/software/bluelib/exception/CouldNotLoadJSON.java b/NeoForge/src/main/java/software/bluelib/exception/CouldNotLoadJSON.java deleted file mode 100644 index c93d1015..00000000 --- a/NeoForge/src/main/java/software/bluelib/exception/CouldNotLoadJSON.java +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.exception; - -/** - * A {@code RuntimeException} that represents an error when a JSON file could not be loaded. - *

- * This exception provides additional context by including the {@link #getResourceId()} of the JSON file that failed to load. - *

- *

- * Key Features: - *

    - *
  • {@link #getResourceId()} - Retrieves the ID of the resource that could not be loaded.
  • - *
- *

- * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public class CouldNotLoadJSON extends RuntimeException { - - /** - * A {@link String} that represents the ID of the resource that could not be loaded. - *

- * This ID is used to provide additional context for the error. - *

- * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private final String resourceId; - - /** - * Constructs a new {@code CouldNotLoadJSON} exception with the specified detail message and resource ID. - *

- * The detail message provides information about the nature of the error, while the resource ID indicates - * which specific resource could not be loaded. - *

- * - * @param pMessage {@link String} - The detail message explaining the reason for the exception. - * @param pResourceId {@link String} - The ID of the resource that could not be loaded. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public CouldNotLoadJSON(String pMessage, String pResourceId) { - super(pMessage); - this.resourceId = pResourceId; - } - - /** - * A {@link String} that retrieves the resource ID of the JSON file that could not be loaded. - *

- * This method provides access to the ID of the resource that caused the exception. - *

- * - * @return The resource ID as a {@link String}. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public String getResourceId() { - return resourceId; - } -} diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java b/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java new file mode 100644 index 00000000..2f723b9e --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java @@ -0,0 +1,7 @@ +package software.bluelib.interfaces.logging; + +import java.util.logging.Level; + +public interface ILogColorProvider { + String getColor(Level pLevel); +} diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java index a9bf1919..bc662430 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java @@ -4,6 +4,7 @@ import net.minecraft.util.RandomSource; import software.bluelib.interfaces.variant.base.IVariantEntityBase; +import software.bluelib.utils.logging.BaseLogger; import java.util.List; @@ -47,10 +48,13 @@ public interface IVariantEntity extends IVariantEntityBase { * @since 1.0.0 */ default String getRandomVariant(List pVariantNamesList, String pDefaultVariant) { - List spawnableVariants = pVariantNamesList.stream().toList(); - if (!spawnableVariants.isEmpty()) { - return spawnableVariants.get(this.random.nextInt(spawnableVariants.size())); + if (pVariantNamesList.isEmpty()) { + BaseLogger.logWarning("Variant names list is empty. Returning default variant: " + pDefaultVariant); + return pDefaultVariant; } - return pDefaultVariant; + int index = random.nextInt(pVariantNamesList.size()); + String selectedVariant = pVariantNamesList.get(index); + BaseLogger.bluelibLogSuccess("Selected random variant: " + selectedVariant + " from list of size: " + pVariantNamesList.size()); + return selectedVariant; } } diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index baecfe62..e8c1f026 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -5,6 +5,7 @@ import net.minecraft.resources.ResourceLocation; import software.bluelib.entity.variant.VariantLoader; import software.bluelib.entity.variant.VariantParameter; +import software.bluelib.utils.logging.BaseLogger; import java.util.List; import java.util.stream.Collectors; @@ -58,8 +59,10 @@ default ResourceLocation getTextureLocation(String pModId, String pPath) { */ default List getEntityVariants(String pEntityName) { List variants = VariantLoader.getVariantsFromEntity(pEntityName); - return variants.stream() + List variantNames = variants.stream() .map(VariantParameter::getVariantName) .collect(Collectors.toList()); + BaseLogger.bluelibLogSuccess("Retrieved " + variantNames.size() + " variants for entity: " + pEntityName); + return variantNames; } } diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java b/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java index f046903c..fee0c458 100644 --- a/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java +++ b/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java @@ -7,7 +7,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; -import software.bluelib.exception.CouldNotLoadJSON; +import software.bluelib.utils.logging.BaseLogger; import java.io.IOException; import java.io.InputStream; @@ -44,26 +44,32 @@ public class JSONLoader { * @param pResourceLocation {@link ResourceLocation} - The {@link ResourceLocation} of the JSON resource. * @param pResourceManager {@link ResourceManager} - The {@link ResourceManager} to load the resource. * @return The loaded {@link JsonObject}. - * @throws CouldNotLoadJSON If the JSON could not be loaded. * @author MeAlam * @Co-author Dan * @since 1.0.0 */ - public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager pResourceManager) throws CouldNotLoadJSON { + public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager pResourceManager) { + BaseLogger.bluelibLogInfo("Attempting to load JSON resource: " + pResourceLocation); + try { Optional resource = pResourceManager.getResource(pResourceLocation); if (resource.isEmpty()) { + BaseLogger.logWarning("Resource not found: " + pResourceLocation); return new JsonObject(); } try (InputStream inputStream = resource.get().open(); InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { - return gson.fromJson(reader, JsonObject.class); + JsonObject jsonObject = gson.fromJson(reader, JsonObject.class); + BaseLogger.bluelibLogSuccess("Successfully loaded JSON resource: " + pResourceLocation); + return jsonObject; } } catch (IOException pException) { - throw new CouldNotLoadJSON("Failed to load JSON from resource: " + pResourceLocation + ". Error: " + pException.getMessage(), pResourceLocation.toString()); + RuntimeException exception = new RuntimeException("Failed to load JSON resource: " + pResourceLocation, pException); + BaseLogger.logError("Failed to load JSON resource: " + pResourceLocation, exception); + throw exception; } } } diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java b/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java index 918ed2cf..b3608d9b 100644 --- a/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java +++ b/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java @@ -5,6 +5,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import software.bluelib.utils.logging.BaseLogger; import java.util.Map; @@ -41,10 +42,14 @@ public class JSONMerger { * @since 1.0.0 */ public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { + BaseLogger.bluelibLogInfo("Starting JSON merge operation."); + for (Map.Entry entry : pSource.entrySet()) { - if (pTarget.has(entry.getKey())) { - JsonElement targetElement = pTarget.get(entry.getKey()); - JsonElement sourceElement = entry.getValue(); + String key = entry.getKey(); + JsonElement sourceElement = entry.getValue(); + + if (pTarget.has(key)) { + JsonElement targetElement = pTarget.get(key); if (targetElement.isJsonArray() && sourceElement.isJsonArray()) { JsonArray targetArray = targetElement.getAsJsonArray(); @@ -53,12 +58,18 @@ public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { for (JsonElement element : sourceArray) { targetArray.add(element); } + + BaseLogger.bluelibLogInfo("Merged array for key: " + key); } else { - pTarget.add(entry.getKey(), sourceElement); + pTarget.add(key, sourceElement); + BaseLogger.bluelibLogInfo("Overwriting value for key: " + key); } } else { - pTarget.add(entry.getKey(), entry.getValue()); + pTarget.add(key, sourceElement); + BaseLogger.bluelibLogInfo("Adding new key: " + key); } } + + BaseLogger.bluelibLogSuccess("JSON merge operation completed."); } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java new file mode 100644 index 00000000..ab2f6f7d --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -0,0 +1,69 @@ +package software.bluelib.utils.logging; + +import java.util.logging.Logger; + +public class BaseLogger { + + private static final Logger logger = Logger.getLogger(BaseLogger.class.getName()); + + //FIXME: Set to false before release + private static boolean bluelibLogging = false; + + private static boolean logging = true; + + public static void setBlueLibLoggingEnabled(boolean pEnabled) { + bluelibLogging = pEnabled; + } + + public static boolean isBlueLibLoggingEnabled() { + return bluelibLogging; + } + + public static boolean isLoggingEnabled() { + return logging; + } + + public static void setLoggingEnabled(boolean pEnabled) { + logging = pEnabled; + } + + static { + LoggerConfig.configureLogger(logger, new DefaultLogColorProvider()); + } + + public static void logError(String pMessage, Throwable pThrowable) { + logger.log(BlueLibLogLevel.ERROR, pMessage, pThrowable); + } + + public static void logWarning(String pMessage) { + logger.log(BlueLibLogLevel.WARNING, pMessage); + } + + public static void logBlueLib(String pMessage) { + logger.log(BlueLibLogLevel.BLUELIB, pMessage); + } + + public static void bluelibLogSuccess(String pMessage) { + if (bluelibLogging) { + logger.log(BlueLibLogLevel.SUCCESS, pMessage); + } + } + + public static void bluelibLogInfo(String pMessage) { + if (bluelibLogging) { + logger.log(BlueLibLogLevel.INFO, pMessage); + } + } + + public static void logSuccess(String pMessage) { + if (logging) { + logger.log(BlueLibLogLevel.SUCCESS, pMessage); + } + } + + public static void logInfo(String pMessage) { + if (logging) { + logger.log(BlueLibLogLevel.INFO, pMessage); + } + } +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BlueLibLogLevel.java b/NeoForge/src/main/java/software/bluelib/utils/logging/BlueLibLogLevel.java new file mode 100644 index 00000000..f1e503ae --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/BlueLibLogLevel.java @@ -0,0 +1,12 @@ +package software.bluelib.utils.logging; + +import java.util.logging.Level; + +public class BlueLibLogLevel { + public static final Level INFO = new Level("INFO: ", Level.INFO.intValue()) {}; + public static final Level ERROR = new Level("ERROR: ", Level.SEVERE.intValue()) {}; + public static final Level WARNING = new Level("WARNING: ", Level.WARNING.intValue()) {}; + + public static final Level SUCCESS = new Level("SUCCESS: ", Level.INFO.intValue() + 50) {}; + public static final Level BLUELIB = new Level("", Level.INFO.intValue() + 50) {}; +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java b/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java new file mode 100644 index 00000000..8fc91965 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java @@ -0,0 +1,25 @@ +package software.bluelib.utils.logging; + +import software.bluelib.interfaces.logging.ILogColorProvider; + +import java.util.logging.Level; + +public class DefaultLogColorProvider implements ILogColorProvider { + + @Override + public String getColor(Level pLevel) { + if (pLevel == BlueLibLogLevel.ERROR) { + return LoggerConfig.RED; + } else if (pLevel == BlueLibLogLevel.WARNING) { + return LoggerConfig.ORANGE; + } else if (pLevel == BlueLibLogLevel.INFO) { + return LoggerConfig.BLUE; + } else if (pLevel == BlueLibLogLevel.SUCCESS) { + return LoggerConfig.GREEN; + } else if (pLevel == BlueLibLogLevel.BLUELIB) { + return LoggerConfig.GREEN; + } else { + return LoggerConfig.RESET; + } + } +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java new file mode 100644 index 00000000..42d21e14 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java @@ -0,0 +1,29 @@ +package software.bluelib.utils.logging; + +import software.bluelib.interfaces.logging.ILogColorProvider; + +import java.util.logging.ConsoleHandler; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; + +public abstract class LoggerConfig { + + protected static final String RESET = "\u001B[0m"; + protected static final String RED = "\u001B[31m"; + protected static final String ORANGE = "\u001B[38;5;214m"; + protected static final String BLUE = "\u001B[34m"; + protected static final String GREEN = "\u001B[38;5;10m"; + + public static void configureLogger(Logger pLogger, ILogColorProvider pColorProvider) { + ConsoleHandler handler = new ConsoleHandler(); + handler.setFormatter(new SimpleFormatter() { + @Override + public synchronized String format(java.util.logging.LogRecord pRecord) { + String color = pColorProvider.getColor(pRecord.getLevel()); + return color + pRecord.getLevel().getName() + pRecord.getMessage() + RESET + "\n"; + } + }); + pLogger.setUseParentHandlers(false); + pLogger.addHandler(handler); + } +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java index 79a37df5..56364d06 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java @@ -2,6 +2,8 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogger; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -21,13 +23,18 @@ public class AlgebraicUtils { * @since 1.0.0 */ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { + double discriminant = pB * pB - 4 * pA * pC; if (discriminant < 0) { + BaseLogger.logWarning("No real roots found for the quadratic equation."); return new double[0]; } + double sqrtDiscriminant = Math.sqrt(discriminant); double root1 = (-pB + sqrtDiscriminant) / (2 * pA); double root2 = (-pB - sqrtDiscriminant) / (2 * pA); + + BaseLogger.bluelibLogInfo("Roots found: root1=" + root1 + ", root2=" + root2); return new double[] { root1, root2 }; } @@ -42,12 +49,17 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { */ public static long factorial(int pNumber) { if (pNumber < 0) { - throw new IllegalArgumentException("Number must be non-negative."); + IllegalArgumentException exception = new IllegalArgumentException("Number must be non-negative."); + BaseLogger.logError("Attempted to calculate factorial of a negative number: " + pNumber, exception); + throw exception; } + long result = 1; for (int i = 1; i <= pNumber; i++) { result *= i; } + + BaseLogger.bluelibLogInfo("Factorial of " + pNumber + " is " + result); return result; } @@ -61,11 +73,14 @@ public static long factorial(int pNumber) { * @since 1.0.0 */ public static int calculateGCD(int pA, int pB) { + while (pB != 0) { int temp = pB; pB = pA % pB; pA = temp; } + + BaseLogger.bluelibLogInfo("GCD found: " + pA); return pA; } @@ -79,6 +94,7 @@ public static int calculateGCD(int pA, int pB) { * @since 1.0.0 */ public static List> generatePowerSet(Set pSet) { + List> powerSet = new ArrayList<>(); powerSet.add(new HashSet<>()); for (T element : pSet) { @@ -90,8 +106,8 @@ public static List> generatePowerSet(Set pSet) { } powerSet.addAll(newSubsets); } + + BaseLogger.bluelibLogInfo("Power set generated with " + powerSet.size() + " subsets."); return powerSet; } - - } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java index 6c4a7c22..a663f9a7 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java @@ -5,6 +5,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import software.bluelib.utils.logging.BaseLogger; public class ConversionUtils { @@ -31,7 +32,6 @@ public static double centimetersToInches(double pCentimeters) { return pCentimeters / 2.54; } - /** * A {@code double} that converts a temperature from Celsius to Fahrenheit. * @@ -89,8 +89,13 @@ public static double milesToKilometers(double pMiles) { * @since 1.0.0 */ public static Date stringToDate(String pDateStr, String pFormat) throws ParseException { - SimpleDateFormat formatter = new SimpleDateFormat(pFormat); - return formatter.parse(pDateStr); + try { + SimpleDateFormat formatter = new SimpleDateFormat(pFormat); + return formatter.parse(pDateStr); + } catch (ParseException pException) { + BaseLogger.logError("Error parsing date string: " + pDateStr + " with format: " + pFormat, pException); + throw pException; + } } /** @@ -103,8 +108,12 @@ public static Date stringToDate(String pDateStr, String pFormat) throws ParseExc * @since 1.0.0 */ public static String dateToString(Date pDate, String pFormat) { - SimpleDateFormat formatter = new SimpleDateFormat(pFormat); - return formatter.format(pDate); + try { + SimpleDateFormat formatter = new SimpleDateFormat(pFormat); + return formatter.format(pDate); + } catch (Exception pException) { + BaseLogger.logError("Error formatting date: " + pDate.toString() + " with format: " + pFormat, pException); + return pException.getMessage(); + } } - } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java index 8d219116..62f0b533 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java @@ -2,6 +2,8 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogger; + public class GeometricUtils { /** @@ -50,6 +52,11 @@ public static double calculateDistance3D(double pX1, double pY1, double pZ1, dou * @since 1.0.0 */ public static double calculateCircleArea(double pRadius) { + if (pRadius < 0) { + Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); + BaseLogger.logError("Error calculating circle area", throwable); + return Double.NaN; + } return Math.PI * pRadius * pRadius; } @@ -62,6 +69,11 @@ public static double calculateCircleArea(double pRadius) { * @since 1.0.0 */ public static double calculateCircleCircumference(double pRadius) { + if (pRadius < 0) { + Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); + BaseLogger.logError("Error calculating circle circumference", throwable); + return Double.NaN; + } return 2 * Math.PI * pRadius; } @@ -75,6 +87,11 @@ public static double calculateCircleCircumference(double pRadius) { * @since 1.0.0 */ public static double calculateRectangleArea(double pWidth, double pHeight) { + if (pWidth < 0 || pHeight < 0) { + Throwable throwable = new IllegalArgumentException("Width and height must be non-negative."); + BaseLogger.logError("Error calculating rectangle area", throwable); + return Double.NaN; + } return pWidth * pHeight; } @@ -88,6 +105,11 @@ public static double calculateRectangleArea(double pWidth, double pHeight) { * @since 1.0.0 */ public static double calculateRectanglePerimeter(double pWidth, double pHeight) { + if (pWidth < 0 || pHeight < 0) { + Throwable throwable = new IllegalArgumentException("Width and height must be non-negative."); + BaseLogger.logError("Error calculating rectangle perimeter", throwable); + return Double.NaN; + } return 2 * (pWidth + pHeight); } @@ -100,6 +122,11 @@ public static double calculateRectanglePerimeter(double pWidth, double pHeight) * @since 1.0.0 */ public static double calculateTriangleArea(double pBase, double pHeight) { + if (pBase < 0 || pHeight < 0) { + Throwable throwable = new IllegalArgumentException("Base and height must be non-negative."); + BaseLogger.logError("Error calculating triangle area", throwable); + return Double.NaN; + } return 0.5 * pBase * pHeight; } @@ -113,6 +140,11 @@ public static double calculateTriangleArea(double pBase, double pHeight) { * @since 1.0.0 */ public static double calculateTrianglePerimeter(double pSide1, double pSide2, double pSide3) { + if (pSide1 < 0 || pSide2 < 0 || pSide3 < 0) { + Throwable throwable = new IllegalArgumentException("Sides must be non-negative."); + BaseLogger.logError("Error calculating triangle perimeter", throwable); + return Double.NaN; + } return pSide1 + pSide2 + pSide3; } @@ -125,6 +157,11 @@ public static double calculateTrianglePerimeter(double pSide1, double pSide2, do * @since 1.0.0 */ public static double calculateSphereVolume(double pRadius) { + if (pRadius < 0) { + Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); + BaseLogger.logError("Error calculating sphere volume", throwable); + return Double.NaN; + } return (4.0 / 3.0) * Math.PI * Math.pow(pRadius, 3); } @@ -137,6 +174,11 @@ public static double calculateSphereVolume(double pRadius) { * @since 1.0.0 */ public static double calculateCubeSurfaceArea(double pSideLength) { + if (pSideLength < 0) { + Throwable throwable = new IllegalArgumentException("Side length must be non-negative."); + BaseLogger.logError("Error calculating cube surface area", throwable); + return Double.NaN; + } return 6 * Math.pow(pSideLength, 2); } @@ -150,10 +192,14 @@ public static double calculateCubeSurfaceArea(double pSideLength) { * @since 1.0.0 */ public static double calculateCylinderVolume(double pRadius, double pHeight) { + if (pRadius < 0 || pHeight < 0) { + Throwable throwable = new IllegalArgumentException("Radius and height must be non-negative."); + BaseLogger.logError("Error calculating cylinder volume", throwable); + return Double.NaN; + } return Math.PI * Math.pow(pRadius, 2) * pHeight; } - /** * A {@code double} that calculates the surface area of a cone given its radius and slant height. * @@ -164,8 +210,11 @@ public static double calculateCylinderVolume(double pRadius, double pHeight) { * @since 1.0.0 */ public static double calculateConeSurfaceArea(double pRadius, double pSlantHeight) { + if (pRadius < 0 || pSlantHeight < 0) { + Throwable throwable = new IllegalArgumentException("Radius and slant height must be non-negative."); + BaseLogger.logError("Error calculating cone surface area", throwable); + return Double.NaN; + } return Math.PI * pRadius * (pRadius + pSlantHeight); } - - } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java index 07c4ea5f..e30ebb7f 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java @@ -2,6 +2,8 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogger; + public class MatrixUtils { /** @@ -19,7 +21,9 @@ public static double[][] multiplyMatrices(double[][] pMatrixA, double[][] pMatri int colsA = pMatrixA[0].length; int colsB = pMatrixB[0].length; if (colsA != pMatrixB.length) { - throw new IllegalArgumentException("Number of columns in the first matrix must be equal to the number of rows in the second matrix."); + Throwable throwable = new IllegalArgumentException("Number of columns in the first matrix must be equal to the number of rows in the second matrix."); + BaseLogger.logError("Error performing matrix multiplication", throwable); + return new double[0][0]; } double[][] result = new double[rowsA][colsB]; for (int i = 0; i < rowsA; i++) { @@ -32,7 +36,6 @@ public static double[][] multiplyMatrices(double[][] pMatrixA, double[][] pMatri return result; } - /** * A {@code double[][]} that computes the transpose of a matrix. * @@ -64,12 +67,13 @@ public static double[][] transposeMatrix(double[][] pMatrix) { */ public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { if (pMatrix.length != 2 || pMatrix[0].length != 2) { - throw new IllegalArgumentException("Matrix must be 2x2."); + Throwable throwable = new IllegalArgumentException("Matrix must be 2x2."); + BaseLogger.logError("Error calculating 2x2 matrix determinant", throwable); + return Double.NaN; } return pMatrix[0][0] * pMatrix[1][1] - pMatrix[0][1] * pMatrix[1][0]; } - /** * A {@code double[][]} that calculates the inverse of a 2x2 matrix. * @@ -81,11 +85,15 @@ public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { */ public static double[][] invert2x2Matrix(double[][] pMatrix) { if (pMatrix.length != 2 || pMatrix[0].length != 2) { - throw new IllegalArgumentException("Matrix must be 2x2."); + Throwable throwable = new IllegalArgumentException("Matrix must be 2x2."); + BaseLogger.logError("Error inverting 2x2 matrix", throwable); + return new double[0][0]; } double determinant = calculate2x2MatrixDeterminant(pMatrix); if (determinant == 0) { - throw new IllegalArgumentException("Matrix is not invertible."); + Throwable throwable = new IllegalArgumentException("Matrix is not invertible."); + BaseLogger.logError("Error inverting 2x2 matrix", throwable); + return new double[0][0]; } double[][] inverse = new double[2][2]; inverse[0][0] = pMatrix[1][1] / determinant; @@ -94,7 +102,4 @@ public static double[][] invert2x2Matrix(double[][] pMatrix) { inverse[1][1] = pMatrix[0][0] / determinant; return inverse; } - - - } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java index 6640780d..15d3df82 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java @@ -2,6 +2,8 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogger; + public class MiscUtils { /** @@ -17,7 +19,6 @@ public static boolean isValidEmail(String pEmail) { return pEmail != null && pEmail.matches(emailRegex); } - /** * A {@code int} that converts a string to an integer, returning a default value if the string is not a valid integer. * @@ -30,7 +31,8 @@ public static boolean isValidEmail(String pEmail) { public static int stringToIntWithDefault(String pString, int pDefaultValue) { try { return Integer.parseInt(pString); - } catch (NumberFormatException e) { + } catch (NumberFormatException pException) { + BaseLogger.logError("Error converting string to integer", pException); return pDefaultValue; } } @@ -74,18 +76,27 @@ public static int calculateLevenshteinDistance(String pStr1, String pStr2) { * @since 1.0.0 */ public static int[] hexToRGB(String pHex) { + if (pHex == null || pHex.isEmpty()) { + Throwable throwable = new IllegalArgumentException("Hex color code cannot be null or empty."); + BaseLogger.logError("Error converting hex to RGB", throwable); + return new int[]{0, 0, 0}; + } if (pHex.charAt(0) == '#') { pHex = pHex.substring(1); } if (pHex.length() != 6) { - throw new IllegalArgumentException("Invalid hex color code."); + Throwable throwable = new IllegalArgumentException("Invalid hex color code."); + BaseLogger.logError("Error converting hex to RGB", throwable); + return new int[]{0, 0, 0}; + } + try { + int r = Integer.parseInt(pHex.substring(0, 2), 16); + int g = Integer.parseInt(pHex.substring(2, 4), 16); + int b = Integer.parseInt(pHex.substring(4, 6), 16); + return new int[]{r, g, b}; + } catch (NumberFormatException pException) { + BaseLogger.logError("Error parsing hex color code to RGB", pException); + return new int[]{0, 0, 0}; } - int r = Integer.parseInt(pHex.substring(0, 2), 16); - int g = Integer.parseInt(pHex.substring(2, 4), 16); - int b = Integer.parseInt(pHex.substring(4, 6), 16); - return new int[]{r, g, b}; } - - - } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java index 767996ae..a161b581 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java @@ -2,6 +2,8 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogger; + public class RandomGenUtils { /** @@ -15,7 +17,9 @@ public class RandomGenUtils { */ public static int generateRandomInt(int pMin, int pMax) { if (pMin > pMax) { - throw new IllegalArgumentException("Minimum value must not be greater than maximum value."); + Throwable throwable = new IllegalArgumentException("Minimum value must not be greater than maximum value."); + BaseLogger.logError("Error generating random integer", throwable); + return 0; } return pMin + (int)(Math.random() * (pMax - pMin + 1)); } @@ -31,7 +35,9 @@ public static int generateRandomInt(int pMin, int pMax) { */ public static double generateRandomDouble(double pMin, double pMax) { if (pMin > pMax) { - throw new IllegalArgumentException("Minimum value must not be greater than maximum value."); + Throwable throwable = new IllegalArgumentException("Minimum value must not be greater than maximum value."); + BaseLogger.logError("Error generating random double", throwable); + return 0; } return pMin + Math.random() * (pMax - pMin); } @@ -58,7 +64,9 @@ public static boolean generateRandomBoolean() { */ public static String generateRandomString(int pLength) { if (pLength < 0) { - throw new IllegalArgumentException("Length must be non-negative."); + Throwable throwable = new IllegalArgumentException("Length must be non-negative."); + BaseLogger.logError("Error generating random string", throwable); + return "unknown"; } String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; StringBuilder sb = new StringBuilder(pLength); @@ -80,10 +88,10 @@ public static String generateRandomString(int pLength) { */ public static String generateRandomStringWithPrefix(String pPrefix, int pLength) { if (pLength < 0) { - throw new IllegalArgumentException("Length must be non-negative."); + Throwable throwable = new IllegalArgumentException("Length must be non-negative."); + BaseLogger.logError("Error generating random string with prefix", throwable); + return "unknown"; } return pPrefix + generateRandomString(pLength - pPrefix.length()); } - - } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java index 98364748..398ffb1d 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java @@ -2,6 +2,8 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogger; + import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -9,42 +11,55 @@ public class StatisticalUtils { /** - * A {@code double} that calculates the mean (average) of an array of values. + * A {@link Double} that calculates the mean (average) of an array of values. * - * @param pValues {@link double[]} - The array of values. + * @param pValues {@link Double}{@code []} - The array of values. * @return The mean of the values. * @author MeAlam * @since 1.0.0 */ public static double calculateMean(double[] pValues) { + if (pValues.length == 0) { + BaseLogger.logWarning("Array is empty, mean calculation might fail."); + return 0; + } + double sum = 0; for (double value : pValues) { sum += value; } - return sum / pValues.length; + double mean = sum / pValues.length; + BaseLogger.bluelibLogSuccess("Mean successfully calculated: " + mean); + return mean; } /** - * A {@code double} that calculates the median of an array of values. + * A {@link Double} that calculates the median of an array of values. * - * @param pValues {@link double[]} - The array of values. + * @param pValues {@link Double}{@code []} - The array of values. * @return The median of the values. * @author MeAlam * @since 1.0.0 */ public static double calculateMedian(double[] pValues) { + if (pValues.length == 0) { + BaseLogger.logWarning("Array is empty, median calculation might fail."); + return 0; + } + double[] sorted = pValues.clone(); Arrays.sort(sorted); int middle = sorted.length / 2; - if (sorted.length % 2 == 0) { - return (sorted[middle - 1] + sorted[middle]) / 2.0; - } else { - return sorted[middle]; - } + double median = (sorted.length % 2 == 0) ? + (sorted[middle - 1] + sorted[middle]) / 2.0 : + sorted[middle]; + + BaseLogger.bluelibLogSuccess("Median successfully calculated: " + median); + return median; } /** - * A {@code double} that calculates the mode (most frequent value) of an array of values. + * A {@code double} that calculates the mode (the most frequent value) of an array of values. * * @param pValues {@link double[]} - The array of values. * @return The mode of the values. @@ -52,10 +67,16 @@ public static double calculateMedian(double[] pValues) { * @since 1.0.0 */ public static double calculateMode(double[] pValues) { + if (pValues.length == 0) { + BaseLogger.logWarning("Array is empty, mode calculation might fail."); + return 0; + } + Map frequencyMap = new HashMap<>(); for (double value : pValues) { frequencyMap.put(value, frequencyMap.getOrDefault(value, 0) + 1); } + double mode = pValues[0]; int maxCount = 0; for (Map.Entry entry : frequencyMap.entrySet()) { @@ -64,6 +85,8 @@ public static double calculateMode(double[] pValues) { mode = entry.getKey(); } } + + BaseLogger.bluelibLogSuccess("Mode successfully calculated: " + mode); return mode; } @@ -76,15 +99,21 @@ public static double calculateMode(double[] pValues) { * @since 1.0.0 */ public static double calculateStandardDeviation(double[] pValues) { + if (pValues.length == 0) { + BaseLogger.logWarning("Array is empty, standard deviation calculation might fail."); + return 0; + } + double mean = calculateMean(pValues); double sumSquaredDifferences = 0; for (double value : pValues) { sumSquaredDifferences += Math.pow(value - mean, 2); } - return Math.sqrt(sumSquaredDifferences / pValues.length); + double stdDev = Math.sqrt(sumSquaredDifferences / pValues.length); + BaseLogger.bluelibLogSuccess("Standard deviation successfully calculated: " + stdDev); + return stdDev; } - /** * A {@code double} that calculates the variance of an array of values. * @@ -94,12 +123,19 @@ public static double calculateStandardDeviation(double[] pValues) { * @since 1.0.0 */ public static double calculateVariance(double[] pValues) { + if (pValues.length == 0) { + BaseLogger.logWarning("Array is empty, variance calculation might fail."); + return 0; + } + double mean = calculateMean(pValues); double sumSquaredDifferences = 0; for (double value : pValues) { sumSquaredDifferences += Math.pow(value - mean, 2); } - return sumSquaredDifferences / pValues.length; + double variance = sumSquaredDifferences / pValues.length; + BaseLogger.bluelibLogSuccess("Variance successfully calculated: " + variance); + return variance; } /** @@ -111,9 +147,16 @@ public static double calculateVariance(double[] pValues) { * @since 1.0.0 */ public static double calculateRange(double[] pValues) { + if (pValues.length == 0) { + BaseLogger.logWarning("Array is empty, range calculation might fail."); + return 0; + } + double max = Arrays.stream(pValues).max().orElseThrow(); double min = Arrays.stream(pValues).min().orElseThrow(); - return max - min; + double range = max - min; + BaseLogger.bluelibLogSuccess("Range successfully calculated: " + range); + return range; } /** @@ -125,8 +168,15 @@ public static double calculateRange(double[] pValues) { * @since 1.0.0 */ public static double calculateCoefficientOfVariation(double[] pValues) { + if (pValues.length == 0) { + BaseLogger.logWarning("Array is empty, coefficient of variation calculation might fail."); + return 0; + } + double mean = calculateMean(pValues); double stdDev = calculateStandardDeviation(pValues); - return (stdDev / mean) * 100; + double coefficient = (stdDev / mean) * 100; + BaseLogger.bluelibLogSuccess("Coefficient of variation successfully calculated: " + coefficient); + return coefficient; } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java b/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java index 05bbfb12..0545d826 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java @@ -7,13 +7,15 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import software.bluelib.utils.logging.BaseLogger; import java.util.Arrays; import java.util.Collection; -import java.util.Objects; import java.util.stream.Collectors; /** @@ -39,9 +41,17 @@ public class ChunkUtils { * @return The {@link Biome} associated with the specified chunk. */ public static Biome getBiomeOfChunk(Level pLevel, ChunkPos pChunkPos) { - return Objects.requireNonNull(pLevel.getBiome(pChunkPos.getWorldPosition()).value()); + try { + Biome biome = pLevel.getBiome(pChunkPos.getWorldPosition()).value(); + BaseLogger.bluelibLogSuccess("Retrieved biome for chunk at position " + pChunkPos + ": " + biome); + return biome; + } catch (Exception pException) { + BaseLogger.logError("Error retrieving biome for chunk at position " + pChunkPos, pException); + throw pException; + } } + /** * A {@link String} representing the registry name of the biome of a chunk. * Example: "minecraft:plains", "minecraft:desert" @@ -51,11 +61,21 @@ public static Biome getBiomeOfChunk(Level pLevel, ChunkPos pChunkPos) { * @return The registry name of the chunk's biome as a {@link String}. */ public static String getBiomeRegistryNameOfChunk(Level pLevel, ChunkPos pChunkPos) { - return Objects.requireNonNull(pLevel.registryAccess() + ResourceLocation biomeKey = pLevel.registryAccess() .registryOrThrow(Registries.BIOME) - .getKey(pLevel.getBiome(pChunkPos.getWorldPosition()).value())).toString(); + .getKey(pLevel.getBiome(pChunkPos.getWorldPosition()).value()); + + if (biomeKey == null) { + NullPointerException exception = new NullPointerException("Biome at chunk position " + pChunkPos + " is null"); + BaseLogger.logError("Error retrieving biome registry name of chunk at " + pChunkPos, exception); + return "Biome at chunk position " + pChunkPos + " is null"; + } + + BaseLogger.bluelibLogSuccess("Retrieved biome registry name for chunk at position " + pChunkPos + ": " + biomeKey); + return biomeKey.toString(); } + /** * A {@link String} that retrieves the simple name of the biome in the chunk. * Example: "plains", "desert" @@ -77,10 +97,18 @@ public static String getBiomeSimpleNameOfChunk(Level pLevel, ChunkPos pChunkPos) * @return A collection of tile entities present in the specified chunk. */ public static Collection getChunkTileEntities(Level pLevel, ChunkPos pChunkPos) { - LevelChunk chunk = pLevel.getChunk(pChunkPos.x, pChunkPos.z); - return chunk.getBlockEntities().values(); + try { + LevelChunk chunk = pLevel.getChunk(pChunkPos.x, pChunkPos.z); + Collection tileEntities = chunk.getBlockEntities().values(); + BaseLogger.bluelibLogSuccess("Retrieved " + tileEntities.size() + " tile entities for chunk at position " + pChunkPos); + return tileEntities; + } catch (Exception pException) { + BaseLogger.logError("Error retrieving tile entities for chunk at position " + pChunkPos, pException); + throw pException; + } } + /** * A {@link String} that retrieves the registry names of tile entities in a chunk. * Example: "minecraft:chest, minecraft:furnace" @@ -90,17 +118,24 @@ public static Collection getChunkTileEntities(Level pLevel, ChunkPo * @return A comma-separated string of tile entity registry names in the chunk. */ public static String getChunkTileEntitiesRegistryNames(Level pLevel, ChunkPos pChunkPos) { - Collection blockEntities = getChunkTileEntities(pLevel, pChunkPos); - - return blockEntities.stream() - .map(blockEntity -> { - ResourceLocation key = pLevel.registryAccess() - .registryOrThrow(Registries.BLOCK_ENTITY_TYPE) - .getKey(blockEntity.getType()); - - return key != null ? key.toString() : "unknown"; - }) - .collect(Collectors.joining(", ")); + try { + Collection blockEntities = getChunkTileEntities(pLevel, pChunkPos); + String registryNames = blockEntities.stream() + .map(blockEntity -> { + ResourceLocation key = pLevel.registryAccess() + .registryOrThrow(Registries.BLOCK_ENTITY_TYPE) + .getKey(blockEntity.getType()); + + return key != null ? key.toString() : "unknown"; + }) + .collect(Collectors.joining(", ")); + + BaseLogger.bluelibLogSuccess("Tile entities for chunk at position " + pChunkPos + ": " + registryNames); + return registryNames; + } catch (Exception pException) { + BaseLogger.logError("Error retrieving tile entity registry names for chunk at position " + pChunkPos, pException); + throw pException; + } } /** @@ -127,51 +162,41 @@ public static String getChunkTileEntitiesSimpleNames(Level pLevel, ChunkPos pChu * @return The number of non-air blocks in the specified chunk. */ public static int getChunkBlockCount(Level pLevel, ChunkPos pChunkPos) { - LevelChunk chunk = pLevel.getChunk(pChunkPos.x, pChunkPos.z); - int blockCount = 0; - - for (int x = 0; x < 16; x++) { - for (int y = pLevel.getMinBuildHeight(); y < pLevel.getHeight(); y++) { - for (int z = 0; z < 16; z++) { - BlockPos worldPos = new BlockPos(pChunkPos.getMinBlockX() + x, y, pChunkPos.getMinBlockZ() + z); - if (!chunk.getBlockState(worldPos).isAir()) { - blockCount++; + try { + LevelChunk chunk = pLevel.getChunk(pChunkPos.x, pChunkPos.z); + int blockCount = 0; + + for (int x = 0; x < 16; x++) { + for (int y = pLevel.getMinBuildHeight(); y < pLevel.getHeight(); y++) { + for (int z = 0; z < 16; z++) { + BlockPos worldPos = new BlockPos(pChunkPos.getMinBlockX() + x, y, pChunkPos.getMinBlockZ() + z); + if (!chunk.getBlockState(worldPos).isAir()) { + blockCount++; + } } } } + + BaseLogger.bluelibLogSuccess("Non-air block count for chunk at position " + pChunkPos + ": " + blockCount); + return blockCount; + } catch (Exception pException) { + BaseLogger.logError("Error counting blocks for chunk at position " + pChunkPos, pException); + throw pException; } - return blockCount; } -//FIXME: This method is not working as expected, Only returns true in SpawnChunks in stead of all loaded chunks. - /** - public static boolean isChunkLoaded(final LevelAccessor world, final int x, final int z) { - if (world.getChunkSource() instanceof ServerChunkCache chunkCache) { - final CompletableFuture> future = chunkCache.getChunkFuture(x, z, ChunkStatus.FULL, false); - - try { - boolean isFutureDone = future.isDone(); - ChunkResult chunkResult = future.getNow(ChunkHolder.UNLOADED_CHUNK); - - if (chunkResult instanceof ChunkResult.Fail) { - System.out.println("Chunk at (" + x + ", " + z + ") failed to load with error: " + chunkResult); - return false; - } - - boolean isChunkLoaded = chunkResult != ChunkHolder.UNLOADED_CHUNK && chunkResult.isSuccess(); - System.out.println("Chunk at (" + x + ", " + z + ") future done: " + isFutureDone); - System.out.println("Chunk at (" + x + ", " + z + ") loaded: " + isChunkLoaded); - - return isChunkLoaded; - } catch (Exception e) { - e.printStackTrace(); - System.out.println("Error checking chunk loading status at (" + x + ", " + z + "): " + e.getMessage()); - return false; - } - } - boolean isLoaded = world.getChunk(x, z, ChunkStatus.FULL, false) != null; - System.out.println("Chunk at (" + x + ", " + z + ") loaded: " + isLoaded); - return isLoaded; - }*/ + /** FIXME: This method is not working as expected. It is not returning correctly. + public static boolean isChunkLoaded(final LevelAccessor pWorld, final int pX, final int pZ) { + try { + boolean isLoaded = pWorld.getChunk(pX, pZ, ChunkStatus.FULL, false) != null; + BaseLogger.bluelibLogSuccess("Chunk at (" + pX + ", " + pZ + ") is loaded: " + isLoaded); + return isLoaded; + } catch (Exception e) { + BaseLogger.logError("Error checking if chunk at (" + pX + ", " + pZ + ") is loaded", e); + return false; + } + } + */ + } diff --git a/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java b/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java index 160bba35..7fb728fc 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java @@ -4,6 +4,7 @@ import software.bluelib.entity.variant.VariantParameter; import software.bluelib.entity.variant.VariantLoader; +import software.bluelib.utils.logging.BaseLogger; import java.util.HashMap; import java.util.Map; @@ -97,7 +98,7 @@ public static class ParameterBuilder { private final String entityName; /** - * A {@link Map} to store parameters for the variant. + * A {@link Map} to store parameters for the variant. *

* Each key-value pair represents a parameter name and its default value. *

@@ -135,7 +136,7 @@ public static ParameterBuilder forVariant(String pEntityName, String pVariantNam } /** - * Adds a parameter to the parameters map with a default value of "null".
+ * Adds a parameter to the parameter map with a default value of "null".
*

* **Note:** The "null" value is used only if the parameter is not specified in the JSON files. *

@@ -159,7 +160,7 @@ public ParameterBuilder withParameter(String pParameter) { *

* * @return The current instance of {@link ParameterBuilder} for method chaining. - * @throws NoSuchElementException if the specified variant is not found for the entity. + * @throws NoSuchElementException if the variant or entity is not found in the database. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -173,9 +174,12 @@ public ParameterBuilder connect() { } variantParametersMap.put(variantName, updatedParameters); } else { - throw new NoSuchElementException("Variant '" + variantName + "' not found for entity '" + entityName + "'"); + Throwable cause = new Throwable("Variant or entity not found in the database"); + NoSuchElementException exception = new NoSuchElementException("Variant '" + variantName + "' not found for entity '" + entityName + "'", cause); + BaseLogger.logError(exception.getMessage(), exception); } return this; } + } } From ef775ac7dbb58a18d9774b15b58d9556c652fd30 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 18 Sep 2024 21:23:43 +0200 Subject: [PATCH 15/62] Variant Loader doesnt need 2 paths anymore but 1 folder it loops thru --- .../bluelib/entity/variant/VariantLoader.java | 38 ++++++++++-------- .../bluelib/event/ReloadEventHandler.java | 8 +--- .../bluelib/example/event/ReloadHandler.java | 5 +-- .../bluelib/utils/logging/BaseLogger.java | 2 +- .../bluelib/textures/entity/dragon/blue.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/dragon/pink.png | Bin 0 -> 676 bytes .../bluelib/variant/entity/dragon/blue.json | 14 +++++++ .../variant/entity/{ => dragon}/dragon.json | 0 .../bluelib/variant/entity/dragon/pink.json | 14 +++++++ .../bluelib/variant/entity/{ => rex}/rex.json | 0 10 files changed, 54 insertions(+), 27 deletions(-) create mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png create mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png create mode 100644 NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/blue.json rename NeoForge/src/main/resources/data/bluelib/variant/entity/{ => dragon}/dragon.json (100%) create mode 100644 NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/pink.json rename NeoForge/src/main/resources/data/bluelib/variant/entity/{ => rex}/rex.json (100%) diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java index b49faf66..f0bb0473 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -8,22 +8,21 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.packs.resources.ResourceManager; +import software.bluelib.BlueLib; import software.bluelib.interfaces.variant.base.IVariantEntityBase; import software.bluelib.json.JSONLoader; import software.bluelib.json.JSONMerger; import software.bluelib.utils.logging.BaseLogger; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.io.File; +import java.util.*; /** * A {@link VariantLoader} class that loads and manages {@link VariantParameter} for entities by merging JSON data from multiple sources. *

* Key Methods: *

    - *
  • {@link #loadVariants(ResourceLocation, ResourceLocation, MinecraftServer, String)} - Loads and merges variant data from both the main mod and the latest datapack.
  • + *
  • {@link #loadVariants(String, MinecraftServer, String)} - Loads and merges variant data from both the main mod and the latest datapack.
  • *
  • {@link #getVariantsFromEntity(String)} - Retrieves the list of loaded {@link VariantParameter} for a specific entity.
  • *
  • {@link #getVariantByName(String, String)} - Retrieves a specific {@link VariantParameter} by its name for a given entity.
  • *
@@ -41,12 +40,10 @@ public class VariantLoader implements IVariantEntityBase { * A {@code void} method that loads and merges variant data from both the Main Mod and the Latest Datapack. * Parses the merged data into {@link VariantParameter}. * - * @param pJSONLocationMod {@link ResourceLocation} - The {@link ResourceLocation} of the Mod's JSON data. - * @param pJSONLocationData {@link ResourceLocation} - The {@link ResourceLocation} of the Latest DataPack's JSON data. * @param pServer {@link MinecraftServer} - The {@link MinecraftServer} instance. * @param pEntityName {@link String} - The name of the entity whose variants should be cleared before loading new ones. */ - public static void loadVariants(ResourceLocation pJSONLocationMod, ResourceLocation pJSONLocationData, MinecraftServer pServer, String pEntityName) { + public static void loadVariants(String folderPath, MinecraftServer pServer, String pModID, String pEntityName) { BaseLogger.bluelibLogInfo("Starting to load variants for entity: " + pEntityName); clearVariantsForEntity(pEntityName); @@ -54,20 +51,27 @@ public static void loadVariants(ResourceLocation pJSONLocationMod, ResourceLocat ResourceManager resourceManager = pServer.getResourceManager(); JsonObject mergedJsonObject = new JsonObject(); - try { - JsonObject modJson = jsonLoader.loadJson(pJSONLocationMod, resourceManager); - JsonObject dataJson = jsonLoader.loadJson(pJSONLocationData, resourceManager); + Collection collection = resourceManager.listResources(folderPath, pFiles -> pFiles.getPath().endsWith(".json")).keySet(); - jsonMerger.mergeJsonObjects(mergedJsonObject, modJson); - jsonMerger.mergeJsonObjects(mergedJsonObject, dataJson); + BaseLogger.logBlueLib("Found resources: " + collection); - BaseLogger.bluelibLogInfo("Successfully loaded and merged JSON data for entity: " + pEntityName); - parseVariants(mergedJsonObject); - } catch (Exception pException) { - BaseLogger.logError("Failed to load variants for entity: " + pEntityName, pException); + for (ResourceLocation resourceLocation : collection) { + try { + BaseLogger.logBlueLib("Loading JSON data from resource: " + resourceLocation.toString()); + JsonObject jsonObject = jsonLoader.loadJson(resourceLocation, resourceManager); + jsonMerger.mergeJsonObjects(mergedJsonObject, jsonObject); + } catch (Exception pException) { + BaseLogger.logError("Failed to load JSON data from resource: " + resourceLocation.toString(), pException); + } } + + BaseLogger.logBlueLib("Successfully loaded and merged JSON data for entity: " + pEntityName); + parseVariants(mergedJsonObject); } + + + /** * A {@code void} method that clears variants for a specific entity type from the map. * diff --git a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java index 2405cb96..921f7bf1 100644 --- a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -54,8 +54,6 @@ public class ReloadEventHandler { * @param pServer {@link MinecraftServer} - The server instance of the current world. * @param pEntityName {@link String} - The entity name to load. * @param pModID {@link String} - The mod ID used to locate the entity variant resources. (Use your Mod's ID) - * @param pModPathLocation {@link String} - The path location within the mod where variants are stored. - * @param pDataPathLocation {@link String} - The path location within the datapack where variants are stored. * @throws JsonParseException if there is an error parsing the JSON files. * @throws RuntimeException if an unexpected error occurs during the registration process. * @see MinecraftServer @@ -65,14 +63,12 @@ public class ReloadEventHandler { * @Co-author Dan * @since 1.0.0 */ - protected static void registerEntityVariants(MinecraftServer pServer, String pEntityName, String pModID, String pModPathLocation, String pDataPathLocation) { - ResourceLocation modLocation = ResourceLocation.fromNamespaceAndPath(pModID, pModPathLocation); - ResourceLocation dataLocation = ResourceLocation.fromNamespaceAndPath(pModID, pDataPathLocation); + protected static void registerEntityVariants(String pFolderPath , MinecraftServer pServer, String pModID, String pEntityName) { BaseLogger.bluelibLogInfo("Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID); try { - VariantLoader.loadVariants(modLocation, dataLocation, pServer, pEntityName); + VariantLoader.loadVariants(pFolderPath, pServer, pModID, pEntityName); BaseLogger.bluelibLogSuccess("Successfully registered entity variants for " + pEntityName + " from ModID: " + pModID); } catch (JsonParseException pException) { BaseLogger.logError("Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); diff --git a/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java b/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java index 4d36d784..c5f3405e 100644 --- a/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java +++ b/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java @@ -134,9 +134,8 @@ public static void onReload(AddReloadListenerEvent pEvent) { */ public static void LoadEntityVariants(MinecraftServer pServer) { for (String entityName : entityNames) { - String modPath = basePath + entityName + ".json"; - String dataPath = basePath + entityName + "data.json"; - ReloadEventHandler.registerEntityVariants(pServer, entityName, BlueLib.MODID, modPath, dataPath); + String folderPath = basePath + entityName; + ReloadEventHandler.registerEntityVariants(folderPath, pServer, BlueLib.MODID, entityName); } } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java index ab2f6f7d..f90959d9 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -7,7 +7,7 @@ public class BaseLogger { private static final Logger logger = Logger.getLogger(BaseLogger.class.getName()); //FIXME: Set to false before release - private static boolean bluelibLogging = false; + private static boolean bluelibLogging = true; private static boolean logging = true; diff --git a/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png b/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png new file mode 100644 index 0000000000000000000000000000000000000000..83be2147b8db3aaab415e12dc3b6e9a11a594ea4 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!7Pn|)P)=iz4q{MmaJHmZ`5KTT zT@vIM%(v z(aRpoCoWyiTgojaD&F|F!PdZVM@UbNjptVBj4jLF?f%O$LFQ-3hJ{yuCnpH{RqTF0 zeUaRrN`{moTZcM{69EVLnQmQO%s%OtOoW(UeeqPr*})2&$=17>Km8Ke@%eU3;;UAl z_dE-lA2QvTo9bV8@y{Lo#EEr$XX6_ew|<>1!7nqtJ8%c@3EiH9*VZm)@~qx!CojNR zaWk9uaEODlE8kU9hhhtcCz6N4bsR43<#29rQagW3>HO}AsXY7mmmhHEtgR04`g-ue zwv#SzoSD}|v`Lv6asM;6d&}sM&)V{9@7_H|f67<|ydtWYcW8+%(7BtgsyBPB&W+HL z{c<<=%Uw8|weJPP@nd2)_peY@i7iud+B+%Zp5z_{-H+UVy3Ca989GZ6MLiBbQ|UWb z(Y^fs4MF?eSt1usd41cW*!(Qw)s%f3B9+u@XC5>Aq_Xz;j^mF{Oz1waD#L%1(lgZ; z3|#E;@8(@%^IqToRn(#6{C~ELFSiAJm_Id{T)EuXZp3k!(UWyjbJC~xst$5b_e=bf q?_)BNT$9h7r)_M&3`GSo`xu+NS2^bO6ubn+JAk44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!Zjwt65OA~RHu2!IKd|xH`;UJotCY^rs5}_f`{vw>EiO$N z3LOzw<`r~)`(`)e=Yh7PEk`d-JKbu&a%s|urSjIR6`Z;x41ng`DxW(eV9(;TfP5fF zx+KUinBhN8a3r(H6zIsKo-U3d6?5KRy`8t%K!EMR{p2K$y_w2uzx|D07t}vHbT_ZS zqnACFPh7g3x0G8Pb3e8>o{E6%i-MMq;~$6()ryJQ+f9BFF)YSSz8_8_4VL` zZ6{scI5V$_Xp=HC;{IoB_m!M8-n(`vqUbO^7^(#vH4lVt10_7L@KG*&OB!JNoDQx9mgM^n9zM-Rfhj2rDv)y z7`WKw-_5(k=DoiEtEfZC`TuMgUv3NdFn?+?xpKL&-H78dqbKX6=A=*WRUPD>?w9x{ q-^XMkxh9`EPutjl8Hx&G_AxejuX4=mDR>EtcLq;aKbLh*2~7ZCIW7SJ literal 0 HcmV?d00001 diff --git a/NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/blue.json b/NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/blue.json new file mode 100644 index 00000000..1125138b --- /dev/null +++ b/NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/blue.json @@ -0,0 +1,14 @@ +{ + "dragon": [ + { + "variantName": "blue", + "customParameter": "customValue3", + "int": 1, + "bool": true, + "array": [ + "boop", + "blep" + ] + } + ] +} \ No newline at end of file diff --git a/NeoForge/src/main/resources/data/bluelib/variant/entity/dragon.json b/NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/dragon.json similarity index 100% rename from NeoForge/src/main/resources/data/bluelib/variant/entity/dragon.json rename to NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/dragon.json diff --git a/NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/pink.json b/NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/pink.json new file mode 100644 index 00000000..4133639c --- /dev/null +++ b/NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/pink.json @@ -0,0 +1,14 @@ +{ + "dragon": [ + { + "variantName": "pink", + "customParameter": "customValue3", + "int": 1, + "bool": true, + "array": [ + "boop", + "blep" + ] + } + ] +} \ No newline at end of file diff --git a/NeoForge/src/main/resources/data/bluelib/variant/entity/rex.json b/NeoForge/src/main/resources/data/bluelib/variant/entity/rex/rex.json similarity index 100% rename from NeoForge/src/main/resources/data/bluelib/variant/entity/rex.json rename to NeoForge/src/main/resources/data/bluelib/variant/entity/rex/rex.json From c2fcc2352d1297e5dcf004462438b7d76201d59b Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 18 Sep 2024 21:25:49 +0200 Subject: [PATCH 16/62] Removed Useless Parameter --- .../java/software/bluelib/entity/variant/VariantLoader.java | 2 +- .../main/java/software/bluelib/event/ReloadEventHandler.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java index f0bb0473..375fa961 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -43,7 +43,7 @@ public class VariantLoader implements IVariantEntityBase { * @param pServer {@link MinecraftServer} - The {@link MinecraftServer} instance. * @param pEntityName {@link String} - The name of the entity whose variants should be cleared before loading new ones. */ - public static void loadVariants(String folderPath, MinecraftServer pServer, String pModID, String pEntityName) { + public static void loadVariants(String folderPath, MinecraftServer pServer, String pEntityName) { BaseLogger.bluelibLogInfo("Starting to load variants for entity: " + pEntityName); clearVariantsForEntity(pEntityName); diff --git a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java index 921f7bf1..ec635cda 100644 --- a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -68,7 +68,7 @@ protected static void registerEntityVariants(String pFolderPath , MinecraftServe BaseLogger.bluelibLogInfo("Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID); try { - VariantLoader.loadVariants(pFolderPath, pServer, pModID, pEntityName); + VariantLoader.loadVariants(pFolderPath, pServer, pEntityName); BaseLogger.bluelibLogSuccess("Successfully registered entity variants for " + pEntityName + " from ModID: " + pModID); } catch (JsonParseException pException) { BaseLogger.logError("Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); From eec27f3d01ab27ecaa297619b22d62e176af887e Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 18 Sep 2024 21:34:44 +0200 Subject: [PATCH 17/62] Added the Last Util and Updated the Logging --- .../bluelib/entity/variant/VariantLoader.java | 6 +- .../bluelib/utils/CaseConverterUtil.java | 92 +++++++++++++++++++ .../bluelib/utils/logging/BaseLogger.java | 2 +- 3 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java index 375fa961..9cdac792 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -53,11 +53,11 @@ public static void loadVariants(String folderPath, MinecraftServer pServer, Stri Collection collection = resourceManager.listResources(folderPath, pFiles -> pFiles.getPath().endsWith(".json")).keySet(); - BaseLogger.logBlueLib("Found resources: " + collection); + BaseLogger.bluelibLogSuccess("Found resources: " + collection); for (ResourceLocation resourceLocation : collection) { try { - BaseLogger.logBlueLib("Loading JSON data from resource: " + resourceLocation.toString()); + BaseLogger.bluelibLogInfo("Loading JSON data from resource: " + resourceLocation.toString()); JsonObject jsonObject = jsonLoader.loadJson(resourceLocation, resourceManager); jsonMerger.mergeJsonObjects(mergedJsonObject, jsonObject); } catch (Exception pException) { @@ -65,7 +65,7 @@ public static void loadVariants(String folderPath, MinecraftServer pServer, Stri } } - BaseLogger.logBlueLib("Successfully loaded and merged JSON data for entity: " + pEntityName); + BaseLogger.bluelibLogSuccess("Successfully loaded and merged JSON data for entity: " + pEntityName); parseVariants(mergedJsonObject); } diff --git a/NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java b/NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java new file mode 100644 index 00000000..29fc0464 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java @@ -0,0 +1,92 @@ +package software.bluelib.utils; + +import software.bluelib.utils.logging.BaseLogger; + +public class CaseConverterUtil { + + public static String toCamelCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.logWarning("Input for toCamelCase is null or empty."); + return pInput; + } + + String[] parts = pInput.split("_"); + StringBuilder camelCaseString = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + if (i == 0) { + camelCaseString.append(parts[i].toLowerCase()); + } else { + camelCaseString.append(toProperCase(parts[i])); + } + } + BaseLogger.bluelibLogSuccess("Converted to camelCase: " + camelCaseString); + return camelCaseString.toString(); + } + + public static String toPascalCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.logWarning("Input for toPascalCase is null or empty."); + return pInput; + } + + String[] parts = pInput.split("_"); + StringBuilder pascalCaseString = new StringBuilder(); + for (String part : parts) { + pascalCaseString.append(toProperCase(part)); + } + BaseLogger.bluelibLogSuccess("Converted to PascalCase: " + pascalCaseString); + return pascalCaseString.toString(); + } + + public static String toProperCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.logWarning("Input for toProperCase is null or empty."); + return pInput; + } + String result = pInput.substring(0, 1).toUpperCase() + pInput.substring(1).toLowerCase(); + BaseLogger.bluelibLogSuccess("Converted to ProperCase: " + result); + return result; + } + + public static String toSnakeCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.logWarning("Input for toSnakeCase is null or empty."); + return pInput; + } + + StringBuilder snakeCaseString = new StringBuilder(); + for (int i = 0; i < pInput.length(); i++) { + char c = pInput.charAt(i); + if (Character.isUpperCase(c)) { + if (!snakeCaseString.isEmpty()) { + snakeCaseString.append("_"); + } + snakeCaseString.append(Character.toLowerCase(c)); + } else { + snakeCaseString.append(c); + } + } + BaseLogger.bluelibLogSuccess("Converted to snake_case: " + snakeCaseString); + return snakeCaseString.toString(); + } + + public static String toLowerCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.logWarning("Input for toLowerCase is null or empty."); + return pInput; + } + String result = pInput.toLowerCase(); + BaseLogger.bluelibLogSuccess("Converted to lowercase: " + result); + return result; + } + + public static String toUpperCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.logWarning("Input for toUpperCase is null or empty."); + return pInput; + } + String result = pInput.toUpperCase(); + BaseLogger.bluelibLogSuccess("Converted to UPPERCASE: " + result); + return result; + } +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java index f90959d9..ab2f6f7d 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -7,7 +7,7 @@ public class BaseLogger { private static final Logger logger = Logger.getLogger(BaseLogger.class.getName()); //FIXME: Set to false before release - private static boolean bluelibLogging = true; + private static boolean bluelibLogging = false; private static boolean logging = true; From 9be323e26ed6fbb0dc45e23cc9763b4f3e8ca125 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 18 Sep 2024 21:43:09 +0200 Subject: [PATCH 18/62] Update CONTRIBUTING.md --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 053dcc87..9eb82b88 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,12 +83,16 @@ - Versioning: Include the `@since` tag in both class-level and method-level comments to indicate the version since which the class or method has been available. - If you update a Class/Method, please add/update the `@version` to indicate it has been changed. - Copyright: Each file should start with `// Copyright (c) BlueLib. Licensed under the MIT License.` + - Tags: Use `@see` to link to the correct Wiki/Api Documentation page if it exists. + - Logging: Log every step using `BaseLogger.logError`, `BaseLogger.logWarning`, `BaseLogger.bluelibLogInfo`, or `BaseLogger.bluelibLogSuccess`, depending on the step. + - Error Handling: Always ensure that errors and warnings are logged using appropriate logging levels. Critical steps must be logged at least with `BaseLogger.bluelibLogInfo` to keep a trail of execution. ### Deprecation - If you optimize a method, variable, or class and determine that it is no longer necessary for the library, mark it as `@Deprecated` instead of removing it. This only applies to elements that have been included in previous released versions of the library. - Include a **strong TODO comment** explaining why it is deprecated and any further action required, such as testing or eventual removal. +- Include an **`@see`** that links to the New Method - **Example**: ```java /** @@ -99,6 +103,7 @@ * @author MeAlam * @Co-author Dan * @since 1.0.0 + * @see #newMethod() */ @Deprecated public Map build() { From 67a4ac9d36ab81297bd263a80740763860889d00 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 18 Sep 2024 22:33:38 +0200 Subject: [PATCH 19/62] Update All Comments --- .../main/java/software/bluelib/BlueLib.java | 29 ++--- .../bluelib/entity/variant/VariantLoader.java | 49 ++++---- .../entity/variant/VariantParameter.java | 28 ++--- .../entity/variant/base/ParameterBase.java | 73 ++++++++---- .../bluelib/event/ReloadEventHandler.java | 30 ++--- .../interfaces/logging/ILogColorProvider.java | 31 +++++ .../variant/base/IVariantEntityBase.java | 2 +- .../software/bluelib/json/JSONLoader.java | 11 +- .../software/bluelib/json/JSONMerger.java | 7 +- .../bluelib/utils/CaseConverterUtil.java | 97 +++++++++++++++ .../bluelib/utils/logging/BaseLogger.java | 83 +++++++++++++ .../utils/logging/BlueLibLogLevel.java | 17 +++ .../logging/DefaultLogColorProvider.java | 26 ++++ .../bluelib/utils/logging/LoggerConfig.java | 20 ++++ .../bluelib/utils/math/AlgebraicUtils.java | 33 ++++-- .../bluelib/utils/math/ConversionUtils.java | 45 ++++--- .../bluelib/utils/math/GeometricUtils.java | 91 ++++++++------ .../bluelib/utils/math/MatrixUtils.java | 31 +++-- .../bluelib/utils/math/MiscUtils.java | 23 +++- .../bluelib/utils/math/RandomGenUtils.java | 47 ++++++-- .../bluelib/utils/math/StatisticalUtils.java | 73 ++++++++++-- .../bluelib/utils/minecraft/ChunkUtils.java | 58 ++++++--- .../bluelib/utils/variant/ParameterUtils.java | 111 +++++++++--------- 23 files changed, 752 insertions(+), 263 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/BlueLib.java b/NeoForge/src/main/java/software/bluelib/BlueLib.java index 29d5e2e9..e390e67a 100644 --- a/NeoForge/src/main/java/software/bluelib/BlueLib.java +++ b/NeoForge/src/main/java/software/bluelib/BlueLib.java @@ -22,7 +22,6 @@ * This class serves as the entry point for the {@link BlueLib} mod, handling initialization by registering event handlers * and setting up necessary configurations. For more details, refer to the BlueLib Wiki. *

- * *

* Key Methods: *

    @@ -41,9 +40,9 @@ public class BlueLib { /** - * A {@link ScheduledExecutorService} used for scheduling tasks, such as printing messages after a delay. + * A {@link ScheduledExecutorService} used to schedule tasks, such as printing messages after a delay. *

    - * This is initialized with a single-threaded pool to handle delayed tasks in a separate thread. + * This executor runs tasks on a single thread to ensure delayed tasks run in a separate thread from the main thread. *

    * @Co-author MeAlam, Dan * @since 1.0.0 @@ -51,19 +50,21 @@ public class BlueLib { private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1); /** - * The Mod ID for {@link BlueLib}. This serves as a unique identifier for the mod. + * A {@link String} representing the Mod ID for the {@link BlueLib} mod. + *

    This serves as a unique identifier for the mod.

    * @Co-author MeAlam, Dan * @since 1.0.0 */ public static final String MODID = "bluelib"; - // public static final Logger LOGGER = LogUtils.getLogger(); - /** * Constructs a new {@link BlueLib} instance and registers the mod event bus. + *

    + * Registers necessary mod event listeners, and if in developer mode, additional client-side listeners for rendering and attributes. + *

    * - * @param pModEventBus {@link IEventBus} - The event bus to which the mod will register its event handlers. - * @param pModContainer {@link ModContainer} - The mod container for the mod instance. + * @param pModEventBus {@link IEventBus} - The event bus where the mod registers its handlers. + * @param pModContainer {@link ModContainer} - The mod container that holds the instance of the mod. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -80,12 +81,12 @@ public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { } /** - * Handles the {@link FMLLoadCompleteEvent}, which is triggered when the mod loading process is complete. + * a {@code void} that handles the {@link FMLLoadCompleteEvent}, which occurs when the mod finishes loading. *

    - * If the mod is running in developer mode, it schedules a task to print a thank-you message to the console after a short delay. + * If the mod is in developer mode, it schedules a task that prints a thank-you message after a short delay. *

    * - * @param pEvent {@link FMLLoadCompleteEvent} - The event triggered upon the completion of the mod loading process. + * @param pEvent {@link FMLLoadCompleteEvent} - The event fired after the mod loading process completes. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -106,12 +107,12 @@ public void onLoadComplete(FMLLoadCompleteEvent pEvent) { } /** - * Checks if the mod is running in developer mode. + * a {@code void} that checks if the mod is running in developer mode. *

    - * Developer mode is determined by checking if the mod is not running in a production environment. + * Developer mode is active when the mod is not running in a production environment. *

    * - * @return {@code true} if the mod is running in developer mode, {@code false} otherwise. + * @return {@code true} if running in developer mode, {@code false} otherwise. * @author MeAlam * @Co-author Dan * @since 1.0.0 diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java index 9cdac792..510a429b 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -14,12 +14,13 @@ import software.bluelib.json.JSONMerger; import software.bluelib.utils.logging.BaseLogger; -import java.io.File; import java.util.*; /** - * A {@link VariantLoader} class that loads and manages {@link VariantParameter} for entities by merging JSON data from multiple sources. + * A {@code class} that loads and manages {@link VariantParameter} instances for entities by merging JSON data from multiple sources. *

    + * The class handles loading of variant data from both the main mod and latest datapack, merging them, and parsing them into {@link VariantParameter} instances. + *

    * Key Methods: *
      *
    • {@link #loadVariants(String, MinecraftServer, String)} - Loads and merges variant data from both the main mod and the latest datapack.
    • @@ -37,10 +38,12 @@ public class VariantLoader implements IVariantEntityBase { private static final JSONMerger jsonMerger = new JSONMerger(); /** - * A {@code void} method that loads and merges variant data from both the Main Mod and the Latest Datapack. - * Parses the merged data into {@link VariantParameter}. - * - * @param pServer {@link MinecraftServer} - The {@link MinecraftServer} instance. + * A {@code void} that loads and merges variant data from both the main mod and the latest datapack. + *

      + * This method parses the merged JSON data into {@link VariantParameter} instances and stores them in the internal map. + *

      + * @param folderPath {@link String} - The path to the folder containing JSON resources. + * @param pServer {@link MinecraftServer} - The {@link MinecraftServer} instance used to access resources. * @param pEntityName {@link String} - The name of the entity whose variants should be cleared before loading new ones. */ public static void loadVariants(String folderPath, MinecraftServer pServer, String pEntityName) { @@ -69,12 +72,11 @@ public static void loadVariants(String folderPath, MinecraftServer pServer, Stri parseVariants(mergedJsonObject); } - - - /** - * A {@code void} method that clears variants for a specific entity type from the map. - * + * A {@code void} that clears variants for a specific entity type from the internal map. + *

      + * This method removes all variants associated with the given entity name. + *

      * @param pEntityName {@link String} - The name of the entity whose variants should be cleared. */ private static void clearVariantsForEntity(String pEntityName) { @@ -83,8 +85,10 @@ private static void clearVariantsForEntity(String pEntityName) { } /** - * A {@code void} method that parses the merged JSON data and converts it into {@link VariantParameter} instances. - * + * A {@code void} that parses the merged JSON data and converts it into {@link VariantParameter} instances. + *

      + * This method processes each entry in the JSON object and stores the created {@link VariantParameter} instances in the internal map. + *

      * @param pJsonObject {@link JsonObject} - The merged {@link JsonObject} containing variant data. */ private static void parseVariants(JsonObject pJsonObject) { @@ -109,8 +113,10 @@ private static void parseVariants(JsonObject pJsonObject) { } /** - * A {@link VariantParameter} method that creates a new {@link VariantParameter} instance from a JSON object. - * + * A {@link VariantParameter} that creates a new {@link VariantParameter} instance from a JSON object. + *

      + * This method wraps the creation of {@link VariantParameter} instances for easier management and potential modification. + *

      * @param pJsonKey {@link String} - The key associated with this variant. * @param pJsonObject {@link JsonObject} - The {@link JsonObject} containing the variant data. * @return A {@link VariantParameter} instance. @@ -120,9 +126,10 @@ private static VariantParameter getEntityVariant(String pJsonKey, JsonObject pJs } /** - * A {@link List} method that retrieves the {@link List} of loaded {@link VariantParameter} - * for a specific entity. - * + * A {@link List} that retrieves the {@link List} of loaded {@link VariantParameter} instances for a specific entity. + *

      + * This method returns a list of variants for the given entity name. If no variants are found, an empty list is returned. + *

      * @param pEntityName {@link String} - The name of the entity to retrieve variants for. * @return A {@link List} of {@link VariantParameter} instances for the specified entity. */ @@ -132,8 +139,10 @@ public static List getVariantsFromEntity(String pEntityName) { } /** - * A {@link VariantParameter} method that retrieves a {@link VariantParameter} by its name for a specific entity. - * + * A {@link VariantParameter} that retrieves a {@link VariantParameter} by its name for a specific entity. + *

      + * This method searches for a variant with the specified name within the list of variants for the given entity. + *

      * @param pEntityName {@link String} - The name of the entity to retrieve variants for. * @param pVariantName {@link String} - The name of the variant to retrieve. * @return The {@link VariantParameter} with the specified name, or {@code null} if not found. diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java index 82e42718..1dadbbd3 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java @@ -11,11 +11,11 @@ import java.util.Set; /** - * A {@code VariantParameter} class that represents the parameters associated with a specific variant of an entity. + * A {@code class} that represents the parameters associated with a specific variant of an entity. *

      - * This class extends {@link ParameterBase} to store and manage variant-specific parameters parsed from a JSON object. + * This class extends {@link ParameterBase} to store and manage variant-specific parameters parsed from a {@link JsonObject}. *

      - * The class is designed to handle various JSON element types, including {@code JsonPrimitive}, {@code JsonArray}, and {@code JsonObject}. + * The class handles various JSON element types, including {@code JsonPrimitive}, {@code JsonArray}, and {@code JsonObject}. *

      * Key Methods: *
        @@ -40,19 +40,19 @@ public class VariantParameter extends ParameterBase { private final String jsonKey; /** - * Constructs a new {@code VariantParameter} instance by extracting parameters from a given JSON object. + * Constructs a new {@code VariantParameter} instance by extracting parameters from a given {@link JsonObject}. *

        * This constructor processes different types of {@link JsonElement} values: *

          - *
        • {@code JsonPrimitive}: Stored directly as a string.
        • - *
        • {@code JsonArray}: Converts array elements into a single comma-separated string.
        • - *
        • {@code JsonObject}: Converts the nested JSON object to a string representation.
        • + *
        • {@link com.google.gson.JsonPrimitive}: Stored directly as a string.
        • + *
        • {@link com.google.gson.JsonArray}: Converts array elements into a single comma-separated string.
        • + *
        • {@link JsonObject}: Converts the nested JSON object to a string representation.
        • *
        • {@code Other Types}: Stores "null" for unhandled JSON types.
        • *
        *

        * @param pJsonKey {@link String} - The key that identifies this entity within the {@link JsonObject}. * @param pJsonObject {@link JsonObject} - The {@link JsonObject} containing the variant parameters. - * @throws IllegalArgumentException if {@code pJsonKey} or {@code pJsonObject} is null. + * @throws IllegalArgumentException if {@code pJsonKey} or {@code pJsonObject} is {@code null}. * @see ParameterBase * @author MeAlam * @Co-author Dan @@ -76,8 +76,8 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { } else if (element.isJsonArray()) { StringBuilder arrayValues = new StringBuilder(); element.getAsJsonArray().forEach(e -> arrayValues.append(e.getAsString()).append(",")); - if (!arrayValues.isEmpty()) { - arrayValues.setLength(arrayValues.length() - 1); + if (arrayValues.length() > 0) { + arrayValues.setLength(arrayValues.length() - 1); // Remove trailing comma } addParameter(entry.getKey(), arrayValues.toString()); BaseLogger.bluelibLogInfo("Added array parameter: " + entry.getKey() + " = " + arrayValues.toString()); @@ -92,12 +92,12 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { } /** - * A {@link String} method that returns the key of the {@link JsonObject} that identifies this entity. + * A {@link String} method that retrieves the key of the {@link JsonObject} that identifies this entity. *

        - * This key is typically used to retrieve or map the entity within a broader data structure. + * This key is used to retrieve or map the entity within a broader data structure. *

        * @return The key of the JSON object representing this entity. - * @throws IllegalStateException if the key is unexpectedly null. + * @throws IllegalStateException if the key is unexpectedly {@code null}. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -116,7 +116,7 @@ public String getJsonKey() { /** * A {@link String} method that retrieves the name of the variant. *

        - * The variant name is expected to be stored under the key {@code "variantName"} in the parameters/JSON Files. + * The variant name is expected to be stored under the key {@code "variantName"} in the parameters/JSON files. *

        * @return The name of the variant, or {@code null} if the variant name is not found. * @author MeAlam diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java index e0ffa79d..0cbf374e 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java @@ -10,8 +10,10 @@ import java.util.Set; /** - * An {@code Abstract base class} for managing a collection of parameters. + * An abstract base class for managing a collection of parameters. *

        + * This class provides methods to add, retrieve, remove, and manipulate parameters stored as key-value pairs. + *

        * Key Methods: *
          *
        • {@link #addParameter(String, Object)} - Adds a parameter to the collection.
        • @@ -34,14 +36,19 @@ public abstract class ParameterBase { /** * A {@link Map} to store parameters as key-value pairs. + *

          + * This map holds parameter keys and their corresponding values. + *

          * @Co-author MeAlam, Dan * @since 1.0.0 */ private final Map parameters = new HashMap<>(); /** - * A {@code void} method to add a parameter to the collection. - * + * A {@code void} that adds a parameter to the collection. + *

          + * This method stores a new parameter with the specified key and value in the internal map. + *

          * @param pKey {@link String} - The key under which the parameter is stored. * @param pValue {@link Object} - The value of the parameter. * @author MeAlam @@ -54,8 +61,10 @@ protected void addParameter(String pKey, Object pValue) { } /** - * An {@link Object} method to retrieve a parameter from the collection by its key. - * + * A {@link Object} that retrieves a parameter from the collection by its key. + *

          + * This method returns the value associated with the specified key, or {@code null} if the key does not exist. + *

          * @param pKey {@link String} - The key of the parameter to retrieve. * @return The value associated with the key, or {@code null} if the key does not exist. * @author MeAlam @@ -69,8 +78,10 @@ protected Object getParameter(String pKey) { } /** - * A {@code void} method that removes a parameter from the collection by its key. - * + * A {@code void} that removes a parameter from the collection by its key. + *

          + * This method deletes the parameter with the specified key from the internal map. If the key does not exist, no action is taken. + *

          * @param pKey {@link String} - The key of the parameter to remove. * @author MeAlam * @Co-author Dan @@ -85,8 +96,10 @@ protected void removeParameter(String pKey) { } /** - * A {@link Map} method that returns all parameters in the collection. - * + * A {@link Map} that returns all parameters in the collection. + *

          + * This method returns a new {@link Map} containing all parameters stored in the internal map. + *

          * @return A {@link Map} containing all parameters. * @author MeAlam * @Co-author Dan @@ -98,8 +111,10 @@ protected Map getAllParameters() { } /** - * A {@link Boolean} method that checks if a parameter exists by its key. - * + * A {@link Boolean} that checks if a parameter exists by its key. + *

          + * This method returns {@code true} if the parameter with the specified key exists in the collection, {@code false} otherwise. + *

          * @param pKey {@link String} - The key of the parameter to check. * @return {@code true} if the parameter exists, {@code false} otherwise. * @author MeAlam @@ -113,8 +128,10 @@ protected boolean containsParameter(String pKey) { } /** - * A {@link Boolean} method that checks if the collection of parameters is empty. - * + * A {@link Boolean} that checks if the collection of parameters is empty. + *

          + * This method returns {@code true} if the collection contains no parameters, {@code false} otherwise. + *

          * @return {@code true} if the collection is empty, {@code false} otherwise. * @author MeAlam * @Co-author Dan @@ -127,8 +144,10 @@ protected boolean isEmpty() { } /** - * A {@code void} method that clears all parameters from the collection. - * + * A {@code void} that clears all parameters from the collection. + *

          + * This method removes all parameters from the internal map. + *

          * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -139,8 +158,10 @@ protected void clearParameters() { } /** - * An {@link Integer} method that returns the number of parameters in the collection. - * + * A {@link Integer} that returns the number of parameters in the collection. + *

          + * This method provides the count of parameters currently stored in the internal map. + *

          * @return The number of parameters in the collection. * @author MeAlam * @Co-author Dan @@ -153,8 +174,10 @@ protected int getParameterCount() { } /** - * A {@link Set} method that returns a set of all parameter keys. - * + * A {@link Set} that returns a set of all parameter keys. + *

          + * This method provides a {@link Set} containing all the keys of parameters in the collection. + *

          * @return A {@link Set} containing all parameter keys. * @author MeAlam * @Co-author Dan @@ -166,8 +189,10 @@ protected Set getParameterKeys() { } /** - * A {@link Collection} method that returns a collection of all parameter values. - * + * A {@link Collection} that returns a collection of all parameter values. + *

          + * This method provides a {@link Collection} containing all the values of parameters in the collection. + *

          * @return A {@link Collection} containing all parameter values. * @author MeAlam * @Co-author Dan @@ -179,8 +204,10 @@ protected Collection getParameterValues() { } /** - * A {@code void} method that updates the value of an existing parameter. - * + * A {@code void} that updates the value of an existing parameter. + *

          + * This method changes the value of a parameter identified by the specified key. If the key does not exist, an exception is thrown. + *

          * @param pKey {@link String} - The key of the parameter to update. * @param pNewValue {@link Object} - The new value to set for the parameter. * @throws IllegalArgumentException if the key does not exist. diff --git a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java index ec635cda..f66a0dad 100644 --- a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -9,14 +9,14 @@ import software.bluelib.utils.logging.BaseLogger; /** - * A {@code ReloadEventHandler} class responsible for handling events related to reloading entity variants. + * A {@code class} responsible for handling events related to reloading entity variants. *

          - * This class includes methods for registering entity variants when the server starts. + * This class provides functionality to register entity variants from specified locations when the server starts. *

          *

          * Key Features: *

            - *
          • {@link #registerEntityVariants(MinecraftServer, String, String, String, String)} - Registers entity variants from specified locations.
          • + *
          • {@link #registerEntityVariants(String, MinecraftServer, String, String)} - Registers entity variants from specified locations.
          • *
          *

          * @see VariantLoader @@ -29,31 +29,31 @@ public class ReloadEventHandler { /** - * A {@code void} method that registers entity variants from specified locations. + * A {@code void} that registers entity variants from specified locations. *

          - * This method attempts to load variants from both mod and datapack locations, providing status information - * and handling any exceptions that occur during the loading process. + * This method attempts to load variants from both mod and datapack locations. It logs status information and + * handles exceptions that occur during the loading process. *

          *

          * Parameters: *

            - *
          • {@code pServer} - The server instance of the current world.
          • - *
          • {@code pEntityName} - The entity name to load.
          • - *
          • {@code pModID} - The mod ID used to locate the entity variant resources. (Use your Mod's ID)
          • - *
          • {@code pModPathLocation} - The path location within the mod where variants are stored.
          • - *
          • {@code pDataPathLocation} - The path location within the resource pack where variants are stored.
          • + *
          • {@code pFolderPath} {@link String} - The folder path location within the mod or datapack where variants are stored.
          • + *
          • {@code pServer} {@link MinecraftServer} - The server instance of the current world.
          • + *
          • {@code pModID} {@link String} - The mod ID used to locate the entity variant resources. (Use your Mod's ID)
          • + *
          • {@code pEntityName} {@link String} - The entity name to load.
          • *
          *

          *

          * Exception Handling: *

            - *
          • {@code JsonParseException} - Thrown when there is an error parsing the JSON files.
          • - *
          • {@code RuntimeException} - Thrown for unexpected errors during the registration process.
          • + *
          • {@link JsonParseException} - Thrown when there is an error parsing the JSON files.
          • + *
          • {@link RuntimeException} - Thrown for unexpected errors during the registration process.
          • *
          *

          + * @param pFolderPath {@link String} - The folder path location within the mod or datapack where variants are stored. * @param pServer {@link MinecraftServer} - The server instance of the current world. - * @param pEntityName {@link String} - The entity name to load. * @param pModID {@link String} - The mod ID used to locate the entity variant resources. (Use your Mod's ID) + * @param pEntityName {@link String} - The entity name to load. * @throws JsonParseException if there is an error parsing the JSON files. * @throws RuntimeException if an unexpected error occurs during the registration process. * @see MinecraftServer @@ -63,7 +63,7 @@ public class ReloadEventHandler { * @Co-author Dan * @since 1.0.0 */ - protected static void registerEntityVariants(String pFolderPath , MinecraftServer pServer, String pModID, String pEntityName) { + protected static void registerEntityVariants(String pFolderPath, MinecraftServer pServer, String pModID, String pEntityName) { BaseLogger.bluelibLogInfo("Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID); diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java b/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java index 2f723b9e..ba85c030 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java @@ -1,7 +1,38 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.interfaces.logging; import java.util.logging.Level; +/** + * An {@code Interface} for providing color codes based on log levels. + *

          + * This interface defines a method to retrieve color codes for various log levels. Implementations should provide + * the appropriate color codes for each log level to enhance the readability of log messages. + *

          + *

          + * Key Methods: + *

            + *
          • {@link #getColor(Level)} - Retrieves the color code associated with a specific {@link Level} of logging.
          • + *
          + *

          + * @author MeAlam + * @Co-author Dan + * @since 1.0.0 + */ public interface ILogColorProvider { + + /** + * A {@link String} that provides the color code for the specified {@link Level}. + *

          + * Implementations should return a color code suitable for displaying log messages with the given log level. + *

          + * + * @param pLevel {@link Level} - The log level for which to retrieve the color code. + * @return The color code as a {@link String} for the specified log level. + * @author MeAlam + * @Co-author Dan + * @since 1.0.0 + */ String getColor(Level pLevel); } diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index e8c1f026..2805eb3e 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -11,7 +11,7 @@ import java.util.stream.Collectors; /** - * A {@code base Interface} providing fundamental methods for handling entity variants. + * An {@code base Interface} providing fundamental methods for handling entity variants. *

          * This interface defines methods for retrieving texture locations and variant names associated with entities. *

          diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java b/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java index fee0c458..827cabe1 100644 --- a/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java +++ b/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java @@ -16,13 +16,13 @@ import java.util.Optional; /** - * The {@code JSONLoader} class is responsible for loading and parsing JSON data from + * A {@code class} responsible for loading and parsing JSON data from * resources defined by {@link ResourceLocation} within a Minecraft mod environment.
          * It uses the {@link Gson} library to convert JSON strings into {@link JsonObject} instances. *

          - * Key methods: + * Key Methods: *

            - *
          • {@link #loadJson(ResourceLocation, ResourceManager)} - Loads a JSON resource.
          • + *
          • {@link #loadJson(ResourceLocation, ResourceManager)} - Loads a JSON resource from the specified location.
          • *
          * @author MeAlam * @Co-author Dan @@ -42,8 +42,9 @@ public class JSONLoader { * in a Minecraft mod environment. *

          * @param pResourceLocation {@link ResourceLocation} - The {@link ResourceLocation} of the JSON resource. - * @param pResourceManager {@link ResourceManager} - The {@link ResourceManager} to load the resource. - * @return The loaded {@link JsonObject}. + * @param pResourceManager {@link ResourceManager} - The {@link ResourceManager} used to load the resource. + * @return The loaded {@link JsonObject}. Returns an empty {@link JsonObject} if the resource is not found. + * @throws RuntimeException if there is an error reading the resource. * @author MeAlam * @Co-author Dan * @since 1.0.0 diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java b/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java index b3608d9b..551a368c 100644 --- a/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java +++ b/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java @@ -10,7 +10,7 @@ import java.util.Map; /** - * A {@code Class} responsible for merging JSON data from a source {@link JsonObject} into a target {@link JsonObject}. + * A {@code class} responsible for merging JSON data from a source {@link JsonObject} into a target {@link JsonObject}. *

          * This class provides functionality to combine JSON data where overlapping keys result in merging arrays, * and non-overlapping keys are simply added to the target. @@ -29,7 +29,7 @@ public class JSONMerger { /** - * Merges data from a source {@link JsonObject} into a target {@link JsonObject}. + * A {@code void} method that merges data from a source {@link JsonObject} into a target {@link JsonObject}. *

          * If the target JSON object already contains a key present in the source JSON object, the values are merged if they are arrays. * Otherwise, the source value is added to the target JSON object. @@ -37,9 +37,6 @@ public class JSONMerger { * * @param pTarget {@link JsonObject} - The target {@link JsonObject} to merge data into. This object will be modified by adding or updating its values. * @param pSource {@link JsonObject} - The source {@link JsonObject} to merge data from. This object is not modified by the operation. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 */ public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { BaseLogger.bluelibLogInfo("Starting JSON merge operation."); diff --git a/NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java b/NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java index 29fc0464..f2cddaae 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java +++ b/NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java @@ -1,9 +1,46 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.utils; import software.bluelib.utils.logging.BaseLogger; +/** + * a {@code class} for converting strings between various cases, including camelCase, PascalCase, snake_case, and others. + *

          + * This class provides static methods for case conversion to facilitate consistent string formatting throughout the application. + *

          + * + *

          + * Key Methods: + *

            + *
          • {@link #toCamelCase(String)} - Converts a string to camelCase format.
          • + *
          • {@link #toPascalCase(String)} - Converts a string to PascalCase format.
          • + *
          • {@link #toProperCase(String)} - Converts a string to ProperCase format, capitalizing the first letter.
          • + *
          • {@link #toSnakeCase(String)} - Converts a string to snake_case format.
          • + *
          • {@link #toLowerCase(String)} - Converts a string to lowercase.
          • + *
          • {@link #toUpperCase(String)} - Converts a string to UPPERCASE.
          • + *
          + *

          + * + * @author MeAlam + * @Co-author Dan + * @since 1.0.0 + * @see BlueLib Wiki + */ public class CaseConverterUtil { + /** + * A {@link String} that converts a string to camelCase format. + *

          + * This method splits the input string by underscores and concatenates the parts, making the first letter of each subsequent word uppercase. + *

          + * + * @param pInput {@link String} - The input string to be converted. (Needs to be in snake_case format) + * @return {@link String} - The converted camelCase string. + * @author MeAlam + * @Co-author Dan + * @since 1.0.0 + */ public static String toCamelCase(String pInput) { if (pInput == null || pInput.isEmpty()) { BaseLogger.logWarning("Input for toCamelCase is null or empty."); @@ -23,6 +60,18 @@ public static String toCamelCase(String pInput) { return camelCaseString.toString(); } + /** + * A {@link String} that converts a string to PascalCase format. + *

          + * This method splits the input string by underscores and concatenates the parts, making the first letter of each word uppercase. + *

          + * + * @param pInput {@link String} - The input string to be converted. (Needs to be in snake_case format) + * @return {@link String} - The converted PascalCase string. + * @author MeAlam + * @Co-author Dan + * @since 1.0.0 + */ public static String toPascalCase(String pInput) { if (pInput == null || pInput.isEmpty()) { BaseLogger.logWarning("Input for toPascalCase is null or empty."); @@ -38,6 +87,18 @@ public static String toPascalCase(String pInput) { return pascalCaseString.toString(); } + /** + * A {@link String} that converts a string to ProperCase format. + *

          + * ProperCase capitalizes the first letter of the input string and converts the rest to lowercase. + *

          + * + * @param pInput {@link String} - The input string to be converted. + * @return {@link String} - The converted ProperCase string. + * @author MeAlam + * @Co-author Dan + * @since 1.0.0 + */ public static String toProperCase(String pInput) { if (pInput == null || pInput.isEmpty()) { BaseLogger.logWarning("Input for toProperCase is null or empty."); @@ -48,6 +109,18 @@ public static String toProperCase(String pInput) { return result; } + /** + * A {@link String} that converts a string to snake_case format. + *

          + * This method transforms uppercase letters into lowercase and inserts an underscore before each uppercase letter. + *

          + * + * @param pInput {@link String} - The input string to be converted. (Needs to be in camelCase or PascalCase format) + * @return {@link String} - The converted snake_case string. + * @author MeAlam + * @Co-author Dan + * @since 1.0.0 + */ public static String toSnakeCase(String pInput) { if (pInput == null || pInput.isEmpty()) { BaseLogger.logWarning("Input for toSnakeCase is null or empty."); @@ -70,6 +143,18 @@ public static String toSnakeCase(String pInput) { return snakeCaseString.toString(); } + /** + * A {@link String} that converts a string to lowercase. + *

          + * This method converts all characters in the input string to lowercase. + *

          + * + * @param pInput {@link String} - The input string to be converted. + * @return {@link String} - The converted lowercase string. + * @author MeAlam + * @Co-author Dan + * @since 1.0.0 + */ public static String toLowerCase(String pInput) { if (pInput == null || pInput.isEmpty()) { BaseLogger.logWarning("Input for toLowerCase is null or empty."); @@ -80,6 +165,18 @@ public static String toLowerCase(String pInput) { return result; } + /** + * A {@link String} that converts a string to UPPERCASE. + *

          + * This method converts all characters in the input string to uppercase. + *

          + * + * @param pInput {@link String} - The input string to be converted. + * @return {@link String} - The converted UPPERCASE string. + * @author MeAlam + * @Co-author Dan + * @since 1.0.0 + */ public static String toUpperCase(String pInput) { if (pInput == null || pInput.isEmpty()) { BaseLogger.logWarning("Input for toUpperCase is null or empty."); diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java index ab2f6f7d..29b11a70 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -1,7 +1,34 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.utils.logging; import java.util.logging.Logger; +/** + * A {@code class} class that provides a centralized logging mechanism for BlueLib, + * with support for custom log levels and colored output. + *

          + * The {@link BaseLogger} allows for enabling/disabling logging and includes methods + * for logging messages at different levels. It also supports conditional logging based + * on the {@code bluelibLogging} flag, which determines if BlueLib-specific logs should be output. + *

          + * Key Methods: + *

            + *
          • {@link #setBlueLibLoggingEnabled(boolean)} - Enables or disables BlueLib-specific logging.
          • + *
          • {@link #isBlueLibLoggingEnabled()} - Checks if BlueLib-specific logging is enabled.
          • + *
          • {@link #isLoggingEnabled()} - Checks if general logging is enabled.
          • + *
          • {@link #setLoggingEnabled(boolean)} - Enables or disables general logging.
          • + *
          • {@link #logError(String, Throwable)} - Logs an error message with an associated throwable.
          • + *
          • {@link #logWarning(String)} - Logs a warning message.
          • + *
          • {@link #logBlueLib(String)} - Logs a BlueLib-specific message.
          • + *
          • {@link #bluelibLogSuccess(String)} - Logs a success message if BlueLib-specific logging is enabled.
          • + *
          • {@link #bluelibLogInfo(String)} - Logs an info message if BlueLib-specific logging is enabled.
          • + *
          • {@link #logSuccess(String)} - Logs a success message if general logging is enabled.
          • + *
          • {@link #logInfo(String)} - Logs an info message if general logging is enabled.
          • + *
          + * @author MeAlam + * @since 1.0.0 + */ public class BaseLogger { private static final Logger logger = Logger.getLogger(BaseLogger.class.getName()); @@ -11,18 +38,38 @@ public class BaseLogger { private static boolean logging = true; + /** + * Enables or disables BlueLib-specific logging. + * + * @param pEnabled {@link boolean} - {@code true} to enable BlueLib logging, {@code false} to disable. + */ public static void setBlueLibLoggingEnabled(boolean pEnabled) { bluelibLogging = pEnabled; } + /** + * Checks if BlueLib-specific logging is enabled. + * + * @return {@link boolean} - {@code true} if BlueLib logging is enabled, {@code false} otherwise. + */ public static boolean isBlueLibLoggingEnabled() { return bluelibLogging; } + /** + * Checks if general logging is enabled. + * + * @return {@link boolean} - {@code true} if general logging is enabled, {@code false} otherwise. + */ public static boolean isLoggingEnabled() { return logging; } + /** + * Enables or disables general logging. + * + * @param pEnabled {@link boolean} - {@code true} to enable logging, {@code false} to disable. + */ public static void setLoggingEnabled(boolean pEnabled) { logging = pEnabled; } @@ -31,36 +78,72 @@ public static void setLoggingEnabled(boolean pEnabled) { LoggerConfig.configureLogger(logger, new DefaultLogColorProvider()); } + /** + * A {@code void} method that logs an error message with an associated {@link Throwable}. + * + * @param pMessage {@link String} - The error message to be logged. + * @param pThrowable {@link Throwable} - The throwable associated with the error. + */ public static void logError(String pMessage, Throwable pThrowable) { logger.log(BlueLibLogLevel.ERROR, pMessage, pThrowable); } + /** + * A {@code void} method that logs a warning message. + * + * @param pMessage {@link String} - The warning message to be logged. + */ public static void logWarning(String pMessage) { logger.log(BlueLibLogLevel.WARNING, pMessage); } + /** + * A {@code void} method that logs a BlueLib-specific message. + * + * @param pMessage {@link String} - The BlueLib-specific message to be logged. + */ public static void logBlueLib(String pMessage) { logger.log(BlueLibLogLevel.BLUELIB, pMessage); } + /** + * A {@code void} method that logs a success message if BlueLib-specific logging is enabled. + * + * @param pMessage {@link String} - The success message to be logged. + */ public static void bluelibLogSuccess(String pMessage) { if (bluelibLogging) { logger.log(BlueLibLogLevel.SUCCESS, pMessage); } } + /** + * A {@code void} method that logs an info message if BlueLib-specific logging is enabled. + * + * @param pMessage {@link String} - The info message to be logged. + */ public static void bluelibLogInfo(String pMessage) { if (bluelibLogging) { logger.log(BlueLibLogLevel.INFO, pMessage); } } + /** + * A {@code void} method that logs a success message if general logging is enabled. + * + * @param pMessage {@link String} - The success message to be logged. + */ public static void logSuccess(String pMessage) { if (logging) { logger.log(BlueLibLogLevel.SUCCESS, pMessage); } } + /** + * A {@code void} method that logs an info message if general logging is enabled. + * + * @param pMessage {@link String} - The info message to be logged. + */ public static void logInfo(String pMessage) { if (logging) { logger.log(BlueLibLogLevel.INFO, pMessage); diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BlueLibLogLevel.java b/NeoForge/src/main/java/software/bluelib/utils/logging/BlueLibLogLevel.java index f1e503ae..11f92169 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/BlueLibLogLevel.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/BlueLibLogLevel.java @@ -1,7 +1,24 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.utils.logging; import java.util.logging.Level; +/** + * A {@code class} defining custom log levels for the BlueLib logging system. + *

          + * This class extends the standard {@link Level} class to introduce additional log levels + * with specific names and integer values: + *

            + *
          • {@link #INFO} - Standard informational log level.
          • + *
          • {@link #ERROR} - Log level for error messages.
          • + *
          • {@link #WARNING} - Log level for warning messages.
          • + *
          • {@link #SUCCESS} - Custom log level for indicating successful operations.
          • + *
          • {@link #BLUELIB} - Custom log level specific to BlueLib.
          • + *
          + * @author MeAlam + * @since 1.0.0 + */ public class BlueLibLogLevel { public static final Level INFO = new Level("INFO: ", Level.INFO.intValue()) {}; public static final Level ERROR = new Level("ERROR: ", Level.SEVERE.intValue()) {}; diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java b/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java index 8fc91965..0e28411a 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java @@ -1,11 +1,37 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.utils.logging; import software.bluelib.interfaces.logging.ILogColorProvider; import java.util.logging.Level; +/** + * A {@code class} that implements the {@link ILogColorProvider} interface + * to provide color codes for different log levels. + *

          + * This implementation uses predefined colors for various log levels, including: + *

            + *
          • {@link BlueLibLogLevel#ERROR} - Red color.
          • + *
          • {@link BlueLibLogLevel#WARNING} - Orange color.
          • + *
          • {@link BlueLibLogLevel#INFO} - Blue color.
          • + *
          • {@link BlueLibLogLevel#SUCCESS} - Green color.
          • + *
          • {@link BlueLibLogLevel#BLUELIB} - Green color.
          • + *
          + * @author MeAlam + * @since 1.0.0 + */ public class DefaultLogColorProvider implements ILogColorProvider { + /** + * A {@link String} that provides the color code for a given {@link Level}. + * The color code is determined based on the log level. + * + * @param pLevel {@link Level} - The log level for which to determine the color. + * @return The color code associated with the {@code pLevel}. + * @author MeAlam + * @since 1.0.0 + */ @Override public String getColor(Level pLevel) { if (pLevel == BlueLibLogLevel.ERROR) { diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java index 42d21e14..a5954da7 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.utils.logging; import software.bluelib.interfaces.logging.ILogColorProvider; @@ -6,6 +8,17 @@ import java.util.logging.Logger; import java.util.logging.SimpleFormatter; +/** + * A {@code class} responsible for configuring logging settings + * including setting up custom colors for log levels. + *

          + * Key Methods: + *

            + *
          • {@link #configureLogger(Logger, ILogColorProvider)} - Configures a {@link Logger} to use custom colors for log levels.
          • + *
          + * @author MeAlam + * @since 1.0.0 + */ public abstract class LoggerConfig { protected static final String RESET = "\u001B[0m"; @@ -14,6 +27,13 @@ public abstract class LoggerConfig { protected static final String BLUE = "\u001B[34m"; protected static final String GREEN = "\u001B[38;5;10m"; + /** + * A {@link Logger} configuration method that sets up a {@link ConsoleHandler} with custom color formatting + * based on log level using the provided {@link ILogColorProvider}. + * + * @param pLogger {@link Logger} - The logger instance to be configured. + * @param pColorProvider {@link ILogColorProvider} - Provides color codes for different log levels. + */ public static void configureLogger(Logger pLogger, ILogColorProvider pColorProvider) { ConsoleHandler handler = new ConsoleHandler(); handler.setFormatter(new SimpleFormatter() { diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java index 56364d06..960ffb9e 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java @@ -9,15 +9,28 @@ import java.util.List; import java.util.Set; +/** + * A {@code class} providing methods for various algebraic and combinatorial calculations. + *

          + * Key Methods: + *

            + *
          • {@link #solveQuadraticEquation(double, double, double)} - Solves a quadratic equation.
          • + *
          • {@link #factorial(int)} - Calculates the factorial of a non-negative integer.
          • + *
          • {@link #calculateGCD(int, int)} - Calculates the greatest common divisor of two integers.
          • + *
          • {@link #generatePowerSet(Set)} - Generates the power set of a given set.
          • + *
          + * @author MeAlam + * @since 1.0.0 + */ public class AlgebraicUtils { /** - * A {@code double[]} that solves the quadratic equation {@code ax^2 + bx + c = 0} + * A {@link Double}{@code []} that solves the quadratic equation {@code ax^2 + bx + c = 0} * using the quadratic formula. * - * @param pA {@link double} - The coefficient a of the quadratic equation. - * @param pB {@link double} - The coefficient b of the quadratic equation. - * @param pC {@link double} - The coefficient c of the quadratic equation. + * @param pA {@link Double} - The coefficient a of the quadratic equation. + * @param pB {@link Double} - The coefficient b of the quadratic equation. + * @param pC {@link Double} - The coefficient c of the quadratic equation. * @return An array of roots of the quadratic equation. The array may be empty if there are no real roots. * @author MeAlam * @since 1.0.0 @@ -39,9 +52,9 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { } /** - * A {@code long} that calculates the factorial of a non-negative integer. + * A {@link Long} that calculates the factorial of a non-negative integer. * - * @param pNumber {@link int} - The non-negative integer. + * @param pNumber {@link Integer} - The non-negative integer. * @return The factorial of the integer. * @throws IllegalArgumentException if {@code pNumber} is negative. * @author MeAlam @@ -64,10 +77,10 @@ public static long factorial(int pNumber) { } /** - * A {@code int} that calculates the greatest common divisor of two integers using the Euclidean algorithm. + * A {@link Integer} that calculates the greatest common divisor of two integers using the Euclidean algorithm. * - * @param pA {@link int} - The first integer. - * @param pB {@link int} - The second integer. + * @param pA {@link Integer} - The first integer. + * @param pB {@link Integer} - The second integer. * @return The greatest common divisor of {@code pA} and {@code pB}. * @author MeAlam * @since 1.0.0 @@ -85,7 +98,7 @@ public static int calculateGCD(int pA, int pB) { } /** - * A {@code List>} that generates the power set (all subsets) of a given set. + * A {@link List} that generates the power set (all subsets) of a given set. * * @param pSet {@link Set} - The input set. * @param The type of elements in the set. diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java index a663f9a7..b01056b4 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java @@ -7,12 +7,29 @@ import java.util.Date; import software.bluelib.utils.logging.BaseLogger; +/** + * A {@code class} providing methods for common unit and date conversions. + *

          + * Key Methods: + *

            + *
          • {@link #inchesToCentimeters(double)} - Converts inches to centimeters.
          • + *
          • {@link #centimetersToInches(double)} - Converts centimeters to inches.
          • + *
          • {@link #celsiusToFahrenheit(double)} - Converts Celsius to Fahrenheit.
          • + *
          • {@link #fahrenheitToCelsius(double)} - Converts Fahrenheit to Celsius.
          • + *
          • {@link #kilometersToMiles(double)} - Converts kilometers to miles.
          • + *
          • {@link #milesToKilometers(double)} - Converts miles to kilometers.
          • + *
          • {@link #stringToDate(String, String)} - Converts a string to a {@link Date} object.
          • + *
          • {@link #dateToString(Date, String)} - Converts a {@link Date} object to a string.
          • + *
          + * @author MeAlam + * @since 1.0.0 + */ public class ConversionUtils { /** - * A {@code double} that converts a length from inches to centimeters. + * A {@link Double} that converts a length from inches to centimeters. * - * @param pInches {@link double} - The length in inches. + * @param pInches {@link Double} - The length in inches. * @return The length in centimeters. * @author MeAlam * @since 1.0.0 @@ -22,9 +39,9 @@ public static double inchesToCentimeters(double pInches) { } /** - * A {@code double} that converts a length from centimeters to inches. + * A {@link Double} that converts a length from centimeters to inches. * - * @param pCentimeters {@link double} - The length in centimeters. + * @param pCentimeters {@link Double} - The length in centimeters. * @return The length in inches. * @since 1.0.0 */ @@ -33,9 +50,9 @@ public static double centimetersToInches(double pCentimeters) { } /** - * A {@code double} that converts a temperature from Celsius to Fahrenheit. + * A {@link Double} that converts a temperature from Celsius to Fahrenheit. * - * @param pCelsius {@link double} - The temperature in Celsius. + * @param pCelsius {@link Double} - The temperature in Celsius. * @return The temperature in Fahrenheit. * @author MeAlam * @since 1.0.0 @@ -45,9 +62,9 @@ public static double celsiusToFahrenheit(double pCelsius) { } /** - * A {@code double} that converts a temperature from Fahrenheit to Celsius. + * A {@link Double} that converts a temperature from Fahrenheit to Celsius. * - * @param pFahrenheit {@link double} - The temperature in Fahrenheit. + * @param pFahrenheit {@link Double} - The temperature in Fahrenheit. * @return The temperature in Celsius. * @since 1.0.0 */ @@ -56,9 +73,9 @@ public static double fahrenheitToCelsius(double pFahrenheit) { } /** - * A {@code double} that converts a distance from kilometers to miles. + * A {@link Double} that converts a distance from kilometers to miles. * - * @param pKilometers {@link double} - The distance in kilometers. + * @param pKilometers {@link Double} - The distance in kilometers. * @return The distance in miles. * @author MeAlam * @since 1.0.0 @@ -68,9 +85,9 @@ public static double kilometersToMiles(double pKilometers) { } /** - * A {@code double} that converts a distance from miles to kilometers. + * A {@link Double} that converts a distance from miles to kilometers. * - * @param pMiles {@link double} - The distance in miles. + * @param pMiles {@link Double} - The distance in miles. * @return The distance in kilometers. * @since 1.0.0 */ @@ -79,7 +96,7 @@ public static double milesToKilometers(double pMiles) { } /** - * A {@code Date} that converts a string to a {@link Date} object. + * A {@link Date} that converts a string to a {@link Date} object. * * @param pDateStr {@link String} - The date in string format (e.g., "yyyy-MM-dd"). * @param pFormat {@link String} - The format of the input date string. @@ -99,7 +116,7 @@ public static Date stringToDate(String pDateStr, String pFormat) throws ParseExc } /** - * A {@code String} that converts a {@link Date} object to a string in a specified format. + * A {@link String} that converts a {@link Date} object to a string in a specified format. * * @param pDate {@link Date} - The date to be converted. * @param pFormat {@link String} - The desired date format (e.g., "yyyy-MM-dd"). diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java index 62f0b533..2c5560f3 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java @@ -4,10 +4,31 @@ import software.bluelib.utils.logging.BaseLogger; +/** + * A {@code class} providing utility methods for various geometric calculations. + *

          + * Key Methods: + *

            + *
          • {@link #calculateDistance2D(double, double, double, double)} - Calculates the Euclidean distance between two points in 2D space.
          • + *
          • {@link #calculateDistance3D(double, double, double, double, double, double)} - Calculates the Euclidean distance between two points in 3D space.
          • + *
          • {@link #calculateCircleArea(double)} - Calculates the area of a circle given its radius.
          • + *
          • {@link #calculateCircleCircumference(double)} - Calculates the circumference of a circle given its radius.
          • + *
          • {@link #calculateRectangleArea(double, double)} - Calculates the area of a rectangle given its width and height.
          • + *
          • {@link #calculateRectanglePerimeter(double, double)} - Calculates the perimeter of a rectangle given its width and height.
          • + *
          • {@link #calculateTriangleArea(double, double)} - Calculates the area of a triangle given its base and height.
          • + *
          • {@link #calculateTrianglePerimeter(double, double, double)} - Calculates the perimeter of a triangle given its three sides.
          • + *
          • {@link #calculateSphereVolume(double)} - Calculates the volume of a sphere given its radius.
          • + *
          • {@link #calculateCubeSurfaceArea(double)} - Calculates the surface area of a cube given its side length.
          • + *
          • {@link #calculateCylinderVolume(double, double)} - Calculates the volume of a cylinder given its radius and height.
          • + *
          • {@link #calculateConeSurfaceArea(double, double)} - Calculates the surface area of a cone given its radius and slant height.
          • + *
          + * @author MeAlam + * @since 1.0.0 + */ public class GeometricUtils { /** - * A {@code double} that calculates the Euclidean distance between two points in 2D space. + * A {@link Double} that calculates the Euclidean distance between two points in 2D space. * * @param pX1 {@link double} - The x-coordinate of the first point. * @param pY1 {@link double} - The y-coordinate of the first point. @@ -24,14 +45,14 @@ public static double calculateDistance2D(double pX1, double pY1, double pX2, dou } /** - * A {@code double} that calculates the Euclidean distance between two points in 3D space. + * A {@link Double} that calculates the Euclidean distance between two points in 3D space. * - * @param pX1 {@link double} - The x-coordinate of the first point. - * @param pY1 {@link double} - The y-coordinate of the first point. - * @param pZ1 {@link double} - The z-coordinate of the first point. - * @param pX2 {@link double} - The x-coordinate of the second point. - * @param pY2 {@link double} - The y-coordinate of the second point. - * @param pZ2 {@link double} - The z-coordinate of the second point. + * @param pX1 {@link Double} - The x-coordinate of the first point. + * @param pY1 {@link Double} - The y-coordinate of the first point. + * @param pZ1 {@link Double} - The z-coordinate of the first point. + * @param pX2 {@link Double} - The x-coordinate of the second point. + * @param pY2 {@link Double} - The y-coordinate of the second point. + * @param pZ2 {@link Double} - The z-coordinate of the second point. * @return The distance between the two points in 3D space. * @author MeAlam * @since 1.0.0 @@ -44,9 +65,9 @@ public static double calculateDistance3D(double pX1, double pY1, double pZ1, dou } /** - * A {@code double} that calculates the area of a circle given its radius. + * A {@link Double} that calculates the area of a circle given its radius. * - * @param pRadius {@link double} - The radius of the circle. + * @param pRadius {@link Double} - The radius of the circle. * @return The area of the circle. * @author MeAlam * @since 1.0.0 @@ -61,9 +82,9 @@ public static double calculateCircleArea(double pRadius) { } /** - * A {@code double} that calculates the circumference of a circle given its radius. + * A {@link Double} that calculates the circumference of a circle given its radius. * - * @param pRadius {@link double} - The radius of the circle. + * @param pRadius {@link Double} - The radius of the circle. * @return The circumference of the circle. * @author MeAlam * @since 1.0.0 @@ -78,10 +99,10 @@ public static double calculateCircleCircumference(double pRadius) { } /** - * A {@code double} that calculates the area of a rectangle given its width and height. + * A {@link Double} that calculates the area of a rectangle given its width and height. * - * @param pWidth {@link double} - The width of the rectangle. - * @param pHeight {@link double} - The height of the rectangle. + * @param pWidth {@link Double} - The width of the rectangle. + * @param pHeight {@link Double} - The height of the rectangle. * @return The area of the rectangle. * @author MeAlam * @since 1.0.0 @@ -96,10 +117,10 @@ public static double calculateRectangleArea(double pWidth, double pHeight) { } /** - * A {@code double} that calculates the perimeter of a rectangle given its width and height. + * A {@link Double} that calculates the perimeter of a rectangle given its width and height. * - * @param pWidth {@link double} - The width of the rectangle. - * @param pHeight {@link double} - The height of the rectangle. + * @param pWidth {@link Double} - The width of the rectangle. + * @param pHeight {@link Double} - The height of the rectangle. * @return The perimeter of the rectangle. * @author MeAlam * @since 1.0.0 @@ -114,10 +135,10 @@ public static double calculateRectanglePerimeter(double pWidth, double pHeight) } /** - * A {@code double} that calculates the area of a triangle given its base and height. + * A {@link Double} that calculates the area of a triangle given its base and height. * - * @param pBase {@link double} - The base of the triangle. - * @param pHeight {@link double} - The height of the triangle. + * @param pBase {@link Double} - The base of the triangle. + * @param pHeight {@link Double} - The height of the triangle. * @return The area of the triangle. * @since 1.0.0 */ @@ -131,11 +152,11 @@ public static double calculateTriangleArea(double pBase, double pHeight) { } /** - * A {@code double} that calculates the perimeter of a triangle given its three sides. + * A {@link Double} that calculates the perimeter of a triangle given its three sides. * - * @param pSide1 {@link double} - The first side of the triangle. - * @param pSide2 {@link double} - The second side of the triangle. - * @param pSide3 {@link double} - The third side of the triangle. + * @param pSide1 {@link Double} - The first side of the triangle. + * @param pSide2 {@link Double} - The second side of the triangle. + * @param pSide3 {@link Double} - The third side of the triangle. * @return The perimeter of the triangle. * @since 1.0.0 */ @@ -149,9 +170,9 @@ public static double calculateTrianglePerimeter(double pSide1, double pSide2, do } /** - * A {@code double} that calculates the volume of a sphere given its radius. + * A {@link Double} that calculates the volume of a sphere given its radius. * - * @param pRadius {@link double} - The radius of the sphere. + * @param pRadius {@link Double} - The radius of the sphere. * @return The volume of the sphere. * @author MeAlam * @since 1.0.0 @@ -166,9 +187,9 @@ public static double calculateSphereVolume(double pRadius) { } /** - * A {@code double} that calculates the surface area of a cube given its side length. + * A {@link Double} that calculates the surface area of a cube given its side length. * - * @param pSideLength {@link double} - The length of a side of the cube. + * @param pSideLength {@link Double} - The length of a side of the cube. * @return The surface area of the cube. * @author MeAlam * @since 1.0.0 @@ -183,10 +204,10 @@ public static double calculateCubeSurfaceArea(double pSideLength) { } /** - * A {@code double} that calculates the volume of a cylinder given its radius and height. + * A {@link Double} that calculates the volume of a cylinder given its radius and height. * - * @param pRadius {@link double} - The radius of the cylinder's base. - * @param pHeight {@link double} - The height of the cylinder. + * @param pRadius {@link Double} - The radius of the cylinder's base. + * @param pHeight {@link Double} - The height of the cylinder. * @return The volume of the cylinder. * @author MeAlam * @since 1.0.0 @@ -201,10 +222,10 @@ public static double calculateCylinderVolume(double pRadius, double pHeight) { } /** - * A {@code double} that calculates the surface area of a cone given its radius and slant height. + * A {@link Double} that calculates the surface area of a cone given its radius and slant height. * - * @param pRadius {@link double} - The radius of the base of the cone. - * @param pSlantHeight {@link double} - The slant height of the cone. + * @param pRadius {@link Double} - The radius of the base of the cone. + * @param pSlantHeight {@link Double} - The slant height of the cone. * @return The surface area of the cone. * @author MeAlam * @since 1.0.0 diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java index e30ebb7f..974782d9 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java @@ -4,13 +4,26 @@ import software.bluelib.utils.logging.BaseLogger; +/** + * A {@code class} providing utility methods for matrix operations. + *

          + * Key Methods: + *

            + *
          • {@link #multiplyMatrices(double[][], double[][])} - Performs matrix multiplication on two matrices.
          • + *
          • {@link #transposeMatrix(double[][])} - Computes the transpose of a matrix.
          • + *
          • {@link #calculate2x2MatrixDeterminant(double[][])} - Calculates the determinant of a 2x2 matrix.
          • + *
          • {@link #invert2x2Matrix(double[][])} - Calculates the inverse of a 2x2 matrix.
          • + *
          + * @author MeAlam + * @since 1.0.0 + */ public class MatrixUtils { /** - * A {@code double[][]} that performs matrix multiplication on two matrices. + * A {@link Double}{@code [][]} that performs matrix multiplication on two matrices. * - * @param pMatrixA {@link double[][]} - The first matrix to be multiplied. - * @param pMatrixB {@link double[][]} - The second matrix to be multiplied. + * @param pMatrixA {@link Double}{@code [][]} - The first matrix to be multiplied. + * @param pMatrixB {@link Double}{@code [][]} - The second matrix to be multiplied. * @return The product of the two matrices. * @throws IllegalArgumentException if the number of columns in the first matrix does not match the number of rows in the second matrix. * @author MeAlam @@ -37,9 +50,9 @@ public static double[][] multiplyMatrices(double[][] pMatrixA, double[][] pMatri } /** - * A {@code double[][]} that computes the transpose of a matrix. + * A {@link Double}{@code [][]} that computes the transpose of a matrix. * - * @param pMatrix {@link double[][]} - The matrix to be transposed. + * @param pMatrix {@link Double}{@code [][]} - The matrix to be transposed. * @return The transposed matrix. * @author MeAlam * @since 1.0.0 @@ -57,9 +70,9 @@ public static double[][] transposeMatrix(double[][] pMatrix) { } /** - * A {@code double} that calculates the determinant of a 2x2 matrix. + * A {@link Double}{@code [][]} that calculates the determinant of a 2x2 matrix. * - * @param pMatrix {@link double[][]} - The 2x2 matrix. + * @param pMatrix {@link Double}{@code [][]} - The 2x2 matrix. * @return The determinant of the matrix. * @throws IllegalArgumentException if the matrix is not 2x2. * @author MeAlam @@ -75,9 +88,9 @@ public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { } /** - * A {@code double[][]} that calculates the inverse of a 2x2 matrix. + * A {@link Double}{@code [][]} that calculates the inverse of a 2x2 matrix. * - * @param pMatrix {@link double[][]} - The 2x2 matrix. + * @param pMatrix {@link Double}{@code [][]} - The 2x2 matrix. * @return The inverse of the matrix. * @throws IllegalArgumentException if the matrix is not invertible or not 2x2. * @author MeAlam diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java index 15d3df82..625fb336 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java @@ -4,10 +4,23 @@ import software.bluelib.utils.logging.BaseLogger; +/** + * A {@code class} providing utility methods for various common operations. + *

          + * Key Methods: + *

            + *
          • {@link #isValidEmail(String)} - Checks if a string is a valid email address.
          • + *
          • {@link #stringToIntWithDefault(String, int)} - Converts a string to an integer with a default value if conversion fails.
          • + *
          • {@link #calculateLevenshteinDistance(String, String)} - Calculates the Levenshtein distance between two strings.
          • + *
          • {@link #hexToRGB(String)} - Converts a hexadecimal color code to an RGB array.
          • + *
          + * @author MeAlam + * @since 1.0.0 + */ public class MiscUtils { /** - * A {@code boolean} that checks if a string is a valid email address. + * A {@link Boolean} that checks if a string is a valid email address. * * @param pEmail {@link String} - The string to be checked. * @return {@code true} if the string is a valid email address, {@code false} otherwise. @@ -20,10 +33,10 @@ public static boolean isValidEmail(String pEmail) { } /** - * A {@code int} that converts a string to an integer, returning a default value if the string is not a valid integer. + * A {@link Integer} that converts a string to an integer, returning a default value if the string is not a valid integer. * * @param pString {@link String} - The string to be converted. - * @param pDefaultValue {@link int} - The default value to return if the string is not a valid integer. + * @param pDefaultValue {@link Integer} - The default value to return if the string is not a valid integer. * @return The integer value of the string, or {@code pDefaultValue} if the string is not a valid integer. * @author MeAlam * @since 1.0.0 @@ -38,7 +51,7 @@ public static int stringToIntWithDefault(String pString, int pDefaultValue) { } /** - * A {@code int} that calculates the Levenshtein distance between two strings. + * A {@link Integer} that calculates the Levenshtein distance between two strings. * * @param pStr1 {@link String} - The first string. * @param pStr2 {@link String} - The second string. @@ -67,7 +80,7 @@ public static int calculateLevenshteinDistance(String pStr1, String pStr2) { } /** - * A {@code int[]} that converts a hexadecimal color code to an RGB array. + * A {@link Integer}{@code []} that converts a hexadecimal color code to an RGB array. * * @param pHex {@link String} - The hexadecimal color code (e.g., "#FFFFFF"). * @return An array containing the RGB values. diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java index a161b581..bd82e335 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java @@ -4,13 +4,38 @@ import software.bluelib.utils.logging.BaseLogger; +/** + * A {@code class} for generating random values of various types. + *

          + * This class provides static methods to generate random integers, doubles, booleans, and alphanumeric strings. + * The methods offer flexibility in specifying the range or length for the generated values, and they ensure + * proper logging and error handling if invalid parameters are provided. + *

          + *

          + * Key Methods: + *

            + *
          • {@link #generateRandomInt(int, int)} - Generates a random integer between a specified minimum and maximum value (inclusive).
          • + *
          • {@link #generateRandomDouble(double, double)} - Generates a random double between a specified minimum and maximum value (inclusive).
          • + *
          • {@link #generateRandomBoolean()} - Generates a random boolean value.
          • + *
          • {@link #generateRandomString(int)} - Generates a random alphanumeric string of a specified length.
          • + *
          • {@link #generateRandomStringWithPrefix(String, int)} - Generates a random alphanumeric string with a specified prefix and length.
          • + *
          + *

          + *

          + * Each method logs errors using {@link BaseLogger} when invalid parameters are provided (e.g., negative lengths + * or minimum values greater than maximum values) and returns default values (e.g., `0` for integers and `"unknown"` for strings) + * in such cases. + *

          + * @author MeAlam + * @since 1.0.0 + */ public class RandomGenUtils { /** - * A {@code int} that generates a random integer between a specified minimum and maximum value (inclusive). + * A {@link Integer} that generates a random integer between a specified minimum and maximum value (inclusive). * - * @param pMin {@link int} - The minimum value (inclusive). - * @param pMax {@link int} - The maximum value (inclusive). + * @param pMin {@link Integer} - The minimum value (inclusive). + * @param pMax {@link Integer} - The maximum value (inclusive). * @return A random integer between {@code pMin} and {@code pMax}. * @author MeAlam * @since 1.0.0 @@ -25,10 +50,10 @@ public static int generateRandomInt(int pMin, int pMax) { } /** - * A {@code double} that generates a random double between a specified minimum and maximum value (inclusive). + * A {@link Double} that generates a random double between a specified minimum and maximum value (inclusive). * - * @param pMin {@link double} - The minimum value (inclusive). - * @param pMax {@link double} - The maximum value (inclusive). + * @param pMin {@link Double} - The minimum value (inclusive). + * @param pMax {@link Double} - The maximum value (inclusive). * @return A random double between {@code pMin} and {@code pMax}. * @author MeAlam * @since 1.0.0 @@ -43,7 +68,7 @@ public static double generateRandomDouble(double pMin, double pMax) { } /** - * A {@code boolean} that generates a random boolean value. + * A {@link Boolean} that generates a random boolean value. * * @return A random boolean value. * @author MeAlam @@ -54,9 +79,9 @@ public static boolean generateRandomBoolean() { } /** - * A {@code String} that generates a random alphanumeric string of a specified length. + * A {@link String} that generates a random alphanumeric string of a specified length. * - * @param pLength {@link int} - The length of the string to be generated. + * @param pLength {@link Integer} - The length of the string to be generated. * @return A random alphanumeric string of the specified length. * @throws IllegalArgumentException if {@code pLength} is negative. * @author MeAlam @@ -78,10 +103,10 @@ public static String generateRandomString(int pLength) { } /** - * A {@code String} that generates a random alphanumeric string of a specified length with a specified prefix. + * A {@link String} that generates a random alphanumeric string of a specified length with a specified prefix. * * @param pPrefix {@link String} - The prefix of the string. - * @param pLength {@link int} - The length of the string to be generated. + * @param pLength {@link Integer} - The length of the string to be generated. * @return A random alphanumeric string of the specified length with the specified prefix. * @throws IllegalArgumentException if {@code pLength} is negative. * @since 1.0.0 diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java index 398ffb1d..bf1c5939 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java @@ -8,12 +8,41 @@ import java.util.HashMap; import java.util.Map; +/** + * A {@code class} for performing various statistical calculations on arrays of double values. + *

          + * This class includes methods to compute key statistical metrics such as mean, median, mode, standard deviation, + * variance, range, and coefficient of variation. Each method logs appropriate messages for success or warnings + * when the input array is empty. + *

          + *

          + * Key Methods: + *

            + *
          • {@link #calculateMean(double[])} - Calculates the mean (average) of an array of values.
          • + *
          • {@link #calculateMedian(double[])} - Calculates the median value of an array of values.
          • + *
          • {@link #calculateMode(double[])} - Determines the mode (most frequent value) of an array of values.
          • + *
          • {@link #calculateStandardDeviation(double[])} - Computes the standard deviation of an array of values.
          • + *
          • {@link #calculateVariance(double[])} - Computes the variance of an array of values.
          • + *
          • {@link #calculateRange(double[])} - Determines the range (difference between maximum and minimum) of an array of values.
          • + *
          • {@link #calculateCoefficientOfVariation(double[])} - Calculates the coefficient of variation (CV) of an array of values.
          • + *
          + *

          + *

          + * Each method logs a success message with the computed value or a warning if the input array is empty. + * The logging is done via {@link BaseLogger}, ensuring that any issues or results are recorded appropriately. + *

          + * @author MeAlam + * @since 1.0.0 + */ public class StatisticalUtils { /** * A {@link Double} that calculates the mean (average) of an array of values. + *

          + * Logs a warning if the array is empty and a success message with the calculated mean. + *

          * - * @param pValues {@link Double}{@code []} - The array of values. + * @param pValues {@link double[]} - The array of values to calculate the mean for. * @return The mean of the values. * @author MeAlam * @since 1.0.0 @@ -34,9 +63,12 @@ public static double calculateMean(double[] pValues) { } /** - * A {@link Double} that calculates the median of an array of values. + * A {@link Double}{@code []} that calculates the median of an array of values. + *

          + * Logs a warning if the array is empty and a success message with the calculated median. + *

          * - * @param pValues {@link Double}{@code []} - The array of values. + * @param pValues {@link Double}{@code []} - The array of values to calculate the median for. * @return The median of the values. * @author MeAlam * @since 1.0.0 @@ -59,9 +91,12 @@ public static double calculateMedian(double[] pValues) { } /** - * A {@code double} that calculates the mode (the most frequent value) of an array of values. + * A {@link Double}{@code []} that calculates the mode (the most frequent value) of an array of values. + *

          + * Logs a warning if the array is empty and a success message with the calculated mode. + *

          * - * @param pValues {@link double[]} - The array of values. + * @param pValues {@link Double}{@code []} - The array of values to calculate the mode for. * @return The mode of the values. * @author MeAlam * @since 1.0.0 @@ -91,9 +126,12 @@ public static double calculateMode(double[] pValues) { } /** - * A {@code double} that calculates the standard deviation of an array of values. + * A {@link Double}{@code []} that calculates the standard deviation of an array of values. + *

          + * Logs a warning if the array is empty and a success message with the calculated standard deviation. + *

          * - * @param pValues {@link double[]} - The array of values. + * @param pValues {@link Double}{@code []} - The array of values to calculate the standard deviation for. * @return The standard deviation of the values. * @author MeAlam * @since 1.0.0 @@ -115,9 +153,12 @@ public static double calculateStandardDeviation(double[] pValues) { } /** - * A {@code double} that calculates the variance of an array of values. + * A {@link Double}{@code []} that calculates the variance of an array of values. + *

          + * Logs a warning if the array is empty and a success message with the calculated variance. + *

          * - * @param pValues {@link double[]} - The array of values. + * @param pValues {@link Double}{@code []} - The array of values to calculate the variance for. * @return The variance of the values. * @author MeAlam * @since 1.0.0 @@ -139,9 +180,12 @@ public static double calculateVariance(double[] pValues) { } /** - * A {@code double} that calculates the range (difference between maximum and minimum) of an array of values. + * A {@link Double}{@code []} that calculates the range (difference between maximum and minimum) of an array of values. + *

          + * Logs a warning if the array is empty and a success message with the calculated range. + *

          * - * @param pValues {@link double[]} - The array of values. + * @param pValues {@link Double}{@code []} - The array of values to calculate the range for. * @return The range of the values. * @author MeAlam * @since 1.0.0 @@ -160,9 +204,12 @@ public static double calculateRange(double[] pValues) { } /** - * A {@code double} that calculates the coefficient of variation of an array of values. + * A {@link Double}{@code []} that calculates the coefficient of variation of an array of values. + *

          + * Logs a warning if the array is empty and a success message with the calculated coefficient of variation. + *

          * - * @param pValues {@link double[]} - The array of values. + * @param pValues {@link Double}{@code []} - The array of values to calculate the coefficient of variation for. * @return The coefficient of variation of the values. * @author MeAlam * @since 1.0.0 diff --git a/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java b/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java index 0545d826..5b7db46f 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java @@ -19,26 +19,36 @@ import java.util.stream.Collectors; /** - * A {@code ChunkUtils} class providing utility methods for interacting with Minecraft chunks, - * specifically focusing on retrieving biome and tile entity information. - * + * A {@code class} providing methods to interact with Minecraft chunks, + * specifically for retrieving biome and tile entity information. + *

          * Key Methods: *

            - *
          • {@link #getBiomeOfChunk(Level, ChunkPos)} - Returns the {@link Biome} of the chunk.
          • - *
          • {@link #getBiomeRegistryNameOfChunk(Level, ChunkPos)} - Retrieves the biome registry name of the chunk.
          • - *
          • {@link #getChunkTileEntities(Level, ChunkPos)} - Gets the tile entities within the chunk.
          • + *
          • {@link #getBiomeOfChunk(Level, ChunkPos)} - Retrieves the {@link Biome} of the specified chunk.
          • + *
          • {@link #getBiomeRegistryNameOfChunk(Level, ChunkPos)} - Retrieves the biome registry name of the specified chunk.
          • + *
          • {@link #getBiomeSimpleNameOfChunk(Level, ChunkPos)} - Retrieves the simple name of the biome in the specified chunk.
          • + *
          • {@link #getChunkTileEntities(Level, ChunkPos)} - Retrieves the tile entities within the specified chunk.
          • + *
          • {@link #getChunkTileEntitiesRegistryNames(Level, ChunkPos)} - Retrieves the registry names of tile entities in the specified chunk.
          • + *
          • {@link #getChunkTileEntitiesSimpleNames(Level, ChunkPos)} - Retrieves the simple names of tile entities in the specified chunk.
          • + *
          • {@link #getChunkBlockCount(Level, ChunkPos)} - Counts the number of non-air blocks in the specified chunk.
          • *
          - * @author MeAlam + *

          * @since 1.0.0 + * @author MeAlam */ public class ChunkUtils { /** - * A {@link Biome} that retrieves the biome of a chunk. + * A {@link Biome} that retrieves the {@link Biome} of the specified chunk. + *

          + * Logs a success message if the biome is retrieved successfully, + * and an error message if an exception occurs. + *

          * * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return The {@link Biome} associated with the specified chunk. + * @throws RuntimeException if there is an error retrieving the biome. */ public static Biome getBiomeOfChunk(Level pLevel, ChunkPos pChunkPos) { try { @@ -53,12 +63,15 @@ public static Biome getBiomeOfChunk(Level pLevel, ChunkPos pChunkPos) { /** - * A {@link String} representing the registry name of the biome of a chunk. + * A {@link String} that retrieves the biome registry name of the specified chunk. + *

          * Example: "minecraft:plains", "minecraft:desert" + *

          * * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return The registry name of the chunk's biome as a {@link String}. + * @throws RuntimeException if there is an error retrieving the biome registry name. */ public static String getBiomeRegistryNameOfChunk(Level pLevel, ChunkPos pChunkPos) { ResourceLocation biomeKey = pLevel.registryAccess() @@ -77,8 +90,10 @@ public static String getBiomeRegistryNameOfChunk(Level pLevel, ChunkPos pChunkPo /** - * A {@link String} that retrieves the simple name of the biome in the chunk. + * A {@link String} that retrieves the simple name of the biome in the specified chunk. + *

          * Example: "plains", "desert" + *

          * * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. @@ -90,11 +105,16 @@ public static String getBiomeSimpleNameOfChunk(Level pLevel, ChunkPos pChunkPos) } /** - * A {@link Collection} of {@link BlockEntity} that retrieves the tile entities in a chunk. + * A {@link Collection} that retrieves the tile entities within the specified chunk. + *

          + * Logs a success message with the number of tile entities retrieved, + * and an error message if an exception occurs. + *

          * * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return A collection of tile entities present in the specified chunk. + * @throws RuntimeException if there is an error retrieving tile entities. */ public static Collection getChunkTileEntities(Level pLevel, ChunkPos pChunkPos) { try { @@ -110,12 +130,15 @@ public static Collection getChunkTileEntities(Level pLevel, ChunkPo /** - * A {@link String} that retrieves the registry names of tile entities in a chunk. + * A {@link String} that retrieves the registry names of tile entities in the specified chunk. + *

          * Example: "minecraft:chest, minecraft:furnace" + *

          * * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return A comma-separated string of tile entity registry names in the chunk. + * @throws RuntimeException if there is an error retrieving tile entity registry names. */ public static String getChunkTileEntitiesRegistryNames(Level pLevel, ChunkPos pChunkPos) { try { @@ -139,8 +162,10 @@ public static String getChunkTileEntitiesRegistryNames(Level pLevel, ChunkPos pC } /** - * A {@link String} that retrieves the simple names of tile entities in a chunk. + * A {@link String} that retrieves the simple names of tile entities in the specified chunk. + *

          * Example: "chest, furnace" + *

          * * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. @@ -155,11 +180,16 @@ public static String getChunkTileEntitiesSimpleNames(Level pLevel, ChunkPos pChu } /** - * An {@code int} that counts the number of non-air blocks in the chunk. + * A {@link Integer} that counts the number of non-air blocks in the specified chunk. + *

          + * Logs a success message with the block count, + * and an error message if an exception occurs. + *

          * * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return The number of non-air blocks in the specified chunk. + * @throws RuntimeException if there is an error counting blocks. */ public static int getChunkBlockCount(Level pLevel, ChunkPos pChunkPos) { try { diff --git a/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java b/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java index 7fb728fc..d7c2c38b 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java @@ -11,110 +11,113 @@ import java.util.NoSuchElementException; /** - * A {@code Class} for managing custom parameters associated with entity variants. + * A utility class for managing custom parameters associated with entity variants. *

          - * This class provides methods to retrieve custom parameters for variants and allows - * for building and connecting parameters to specific variants using the {@link ParameterBuilder}. + * Provides methods to retrieve custom parameters for variants and allows for + * building and connecting parameters to specific variants via the {@link ParameterBuilder} class. *

          *

          - * Key Methods: + * Key Methods: *

            *
          • {@link #getParameter(String, String)} - Retrieves the value of a custom parameter for a specific variant.
          • *
          *

          - * Nested Classes: + *

          + * Nested Classes: *

            - *
          • {@link ParameterBuilder} - A builder class for creating and associating custom parameters with a specific variant.
          • + *
          • {@link ParameterBuilder} - Builder class for creating and associating custom parameters with variants.
          • *
          *

          + * * @since 1.0.0 * @author MeAlam * @Co-author Dan + * @version 1.0.0 + * @see software.bluelib.entity.variant.VariantParameter */ public class ParameterUtils { /** - * A {@link Map} holding custom parameters for each variant. + * Holds custom parameters for each variant. *

          - * The outer map's key is the variant's name, and the inner map contains key-value pairs - * of custom parameters for that variant. + * The outer map's key is the variant name, and the inner map contains key-value pairs + * representing custom parameters for that variant. *

          - * @Co-author MeAlam, Dan + * * @since 1.0.0 + * @Co-author MeAlam, Dan */ private static final Map> variantParametersMap = new HashMap<>(); /** - * Retrieves the value of a custom parameter for a specific variant. + * A {@link String} that retrieves the value of a custom parameter for a specific variant. *

          - * If the parameter is not found, "null" is returned. + * If the parameter is not found, {@code null} is returned. *

          * - * @param pVariantName {@link String} - The name of the variant. - * @param pParameterKey {@link String} - The key of the parameter to retrieve. - * @return The value of the custom parameter for the specified variant. + * @param pVariantName {@link String} The name of the variant. + * @param pParameterKey {@link String} The key of the parameter to retrieve. + * @return {@link String} The value of the custom parameter for the specified variant or {@code null} if not found. + * @since 1.0.0 * @author MeAlam * @Co-author Dan - * @since 1.0.0 */ public static String getParameter(String pVariantName, String pParameterKey) { return variantParametersMap.getOrDefault(pVariantName, new HashMap<>()).getOrDefault(pParameterKey, "null"); } /** - * A {@code Builder} class for creating and associating custom parameters with a specific variant. + * A {@code class} for creating and associating custom parameters with a specific variant. *

          - * This class allows chaining methods to build and connect parameters to a variant. + * Allows chaining methods to build and connect parameters to a variant. *

          - * *

          - * Key Methods: + * Key Methods: *

            - *
          • {@link #forVariant(String, String)} - Creates a new instance of {@link ParameterBuilder} for the specified entity and variant.
          • - *
          • {@link #withParameter(String)} - Adds a parameter to the parameters map with a default value of "null".
          • - *
          • {@link #connect()} - Adds parameters to the variant and updates the static {@link VariantParameter} with these parameters.
          • + *
          • {@link #forVariant(String, String)} - Creates a new instance of {@link ParameterBuilder} for a specific entity and variant.
          • + *
          • {@link #withParameter(String)} - Adds a parameter with a default value of {@code null} .
          • + *
          • {@link #connect()} - Connects the parameters to the variant and updates {@link VariantParameter} with the parameters.
          • *
          *

          - *

          - * **Note:** The "null" value is used only if the parameter is not specified in the JSON files. - *

          + * * @since 1.0.0 * @author MeAlam * @Co-author Dan */ public static class ParameterBuilder { + /** - * The name of the variant for which parameters are being built. - * @Co-author MeAlam, Dan + * The name of the variant being associated with custom parameters. + * * @since 1.0.0 + * @Co-author MeAlam, Dan */ private final String variantName; /** - * The name of the entity for which parameters are being built. - * @Co-author MeAlam, Dan + * The name of the entity being associated with custom parameters. + * * @since 1.0.0 + * @Co-author MeAlam, Dan */ private final String entityName; /** - * A {@link Map} to store parameters for the variant. - *

          - * Each key-value pair represents a parameter name and its default value. - *

          - * @Co-author MeAlam, Dan + * Stores custom parameters being built for the variant. + * * @since 1.0.0 + * @Co-author MeAlam, Dan */ private final Map parameters = new HashMap<>(); /** - * Constructor to initialize the builder with a specific entity name and variant name. + * Constructor to initialize the builder for a specific entity and variant. * - * @param pEntityName {@link String} - The name of the entity. - * @param pVariantName {@link String} - The name of the variant. + * @param pEntityName {@link String} The name of the entity. + * @param pVariantName {@link String} The name of the variant. + * @since 1.0.0 * @author MeAlam * @Co-author Dan - * @since 1.0.0 */ private ParameterBuilder(String pEntityName, String pVariantName) { this.variantName = pVariantName; @@ -122,30 +125,30 @@ private ParameterBuilder(String pEntityName, String pVariantName) { } /** - * Creates a new instance of {@link ParameterBuilder} for the specified entity and variant. + * A {@link ParameterBuilder} that creates a new instance of {@link ParameterBuilder} for the specified entity and variant. * - * @param pEntityName {@link String} - The name of the entity. - * @param pVariantName {@link String} - The name of the variant. - * @return A new instance of {@link ParameterBuilder}. + * @param pEntityName {@link String} The name of the entity. + * @param pVariantName {@link String} The name of the variant. + * @return {@link ParameterBuilder} A new instance for chaining. + * @since 1.0.0 * @author MeAlam * @Co-author Dan - * @since 1.0.0 */ public static ParameterBuilder forVariant(String pEntityName, String pVariantName) { return new ParameterBuilder(pEntityName, pVariantName); } /** - * Adds a parameter to the parameter map with a default value of "null".
          + * A {@link ParameterBuilder} that adds a custom parameter to the builder with a default value of "null". *

          - * **Note:** The "null" value is used only if the parameter is not specified in the JSON files. + * The {@code null} value is used if the parameter is not specified in the data source. *

          * - * @param pParameter {@link String} - The key of the parameter to add. - * @return The current instance of {@link ParameterBuilder} for method chaining. + * @param pParameter {@link String} The parameter key. + * @return {@link ParameterBuilder} The builder instance for chaining. + * @since 1.0.0 * @author MeAlam * @Co-author Dan - * @since 1.0.0 */ public ParameterBuilder withParameter(String pParameter) { parameters.put(pParameter, "null"); @@ -153,17 +156,16 @@ public ParameterBuilder withParameter(String pParameter) { } /** - * Adds a parameter to the parameters map with a specified default value. + * A {@link ParameterBuilder} that connects the custom parameters to the specified variant and updates the {@link VariantParameter}. *

          - * Connects the parameters built with this builder to the specified variant. - * Updates the static {@link VariantParameter} with the parameters for the specified variant. + * Throws a {@link NoSuchElementException} if the variant or entity is not found. *

          * - * @return The current instance of {@link ParameterBuilder} for method chaining. + * @return {@link ParameterBuilder} The builder instance for chaining. * @throws NoSuchElementException if the variant or entity is not found in the database. + * @since 1.0.0 * @author MeAlam * @Co-author Dan - * @since 1.0.0 */ public ParameterBuilder connect() { VariantParameter variant = VariantLoader.getVariantByName(entityName, variantName); @@ -180,6 +182,5 @@ public ParameterBuilder connect() { } return this; } - } } From 424ca4ed1fe4bfd227332745fc63b1f6d937f184 Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 19 Sep 2024 10:23:14 +0200 Subject: [PATCH 20/62] Moved Math Conversion * And improved Case Converter --- .../bluelib/utils/CaseConverterUtil.java | 189 ------------------ .../utils/conversion/CaseConverterUtils.java | 182 +++++++++++++++++ .../MathConverterUtils.java} | 4 +- 3 files changed, 184 insertions(+), 191 deletions(-) delete mode 100644 NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java create mode 100644 NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java rename NeoForge/src/main/java/software/bluelib/utils/{math/ConversionUtils.java => conversion/MathConverterUtils.java} (98%) diff --git a/NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java b/NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java deleted file mode 100644 index f2cddaae..00000000 --- a/NeoForge/src/main/java/software/bluelib/utils/CaseConverterUtil.java +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.utils; - -import software.bluelib.utils.logging.BaseLogger; - -/** - * a {@code class} for converting strings between various cases, including camelCase, PascalCase, snake_case, and others. - *

          - * This class provides static methods for case conversion to facilitate consistent string formatting throughout the application. - *

          - * - *

          - * Key Methods: - *

            - *
          • {@link #toCamelCase(String)} - Converts a string to camelCase format.
          • - *
          • {@link #toPascalCase(String)} - Converts a string to PascalCase format.
          • - *
          • {@link #toProperCase(String)} - Converts a string to ProperCase format, capitalizing the first letter.
          • - *
          • {@link #toSnakeCase(String)} - Converts a string to snake_case format.
          • - *
          • {@link #toLowerCase(String)} - Converts a string to lowercase.
          • - *
          • {@link #toUpperCase(String)} - Converts a string to UPPERCASE.
          • - *
          - *

          - * - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - * @see BlueLib Wiki - */ -public class CaseConverterUtil { - - /** - * A {@link String} that converts a string to camelCase format. - *

          - * This method splits the input string by underscores and concatenates the parts, making the first letter of each subsequent word uppercase. - *

          - * - * @param pInput {@link String} - The input string to be converted. (Needs to be in snake_case format) - * @return {@link String} - The converted camelCase string. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public static String toCamelCase(String pInput) { - if (pInput == null || pInput.isEmpty()) { - BaseLogger.logWarning("Input for toCamelCase is null or empty."); - return pInput; - } - - String[] parts = pInput.split("_"); - StringBuilder camelCaseString = new StringBuilder(); - for (int i = 0; i < parts.length; i++) { - if (i == 0) { - camelCaseString.append(parts[i].toLowerCase()); - } else { - camelCaseString.append(toProperCase(parts[i])); - } - } - BaseLogger.bluelibLogSuccess("Converted to camelCase: " + camelCaseString); - return camelCaseString.toString(); - } - - /** - * A {@link String} that converts a string to PascalCase format. - *

          - * This method splits the input string by underscores and concatenates the parts, making the first letter of each word uppercase. - *

          - * - * @param pInput {@link String} - The input string to be converted. (Needs to be in snake_case format) - * @return {@link String} - The converted PascalCase string. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public static String toPascalCase(String pInput) { - if (pInput == null || pInput.isEmpty()) { - BaseLogger.logWarning("Input for toPascalCase is null or empty."); - return pInput; - } - - String[] parts = pInput.split("_"); - StringBuilder pascalCaseString = new StringBuilder(); - for (String part : parts) { - pascalCaseString.append(toProperCase(part)); - } - BaseLogger.bluelibLogSuccess("Converted to PascalCase: " + pascalCaseString); - return pascalCaseString.toString(); - } - - /** - * A {@link String} that converts a string to ProperCase format. - *

          - * ProperCase capitalizes the first letter of the input string and converts the rest to lowercase. - *

          - * - * @param pInput {@link String} - The input string to be converted. - * @return {@link String} - The converted ProperCase string. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public static String toProperCase(String pInput) { - if (pInput == null || pInput.isEmpty()) { - BaseLogger.logWarning("Input for toProperCase is null or empty."); - return pInput; - } - String result = pInput.substring(0, 1).toUpperCase() + pInput.substring(1).toLowerCase(); - BaseLogger.bluelibLogSuccess("Converted to ProperCase: " + result); - return result; - } - - /** - * A {@link String} that converts a string to snake_case format. - *

          - * This method transforms uppercase letters into lowercase and inserts an underscore before each uppercase letter. - *

          - * - * @param pInput {@link String} - The input string to be converted. (Needs to be in camelCase or PascalCase format) - * @return {@link String} - The converted snake_case string. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public static String toSnakeCase(String pInput) { - if (pInput == null || pInput.isEmpty()) { - BaseLogger.logWarning("Input for toSnakeCase is null or empty."); - return pInput; - } - - StringBuilder snakeCaseString = new StringBuilder(); - for (int i = 0; i < pInput.length(); i++) { - char c = pInput.charAt(i); - if (Character.isUpperCase(c)) { - if (!snakeCaseString.isEmpty()) { - snakeCaseString.append("_"); - } - snakeCaseString.append(Character.toLowerCase(c)); - } else { - snakeCaseString.append(c); - } - } - BaseLogger.bluelibLogSuccess("Converted to snake_case: " + snakeCaseString); - return snakeCaseString.toString(); - } - - /** - * A {@link String} that converts a string to lowercase. - *

          - * This method converts all characters in the input string to lowercase. - *

          - * - * @param pInput {@link String} - The input string to be converted. - * @return {@link String} - The converted lowercase string. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public static String toLowerCase(String pInput) { - if (pInput == null || pInput.isEmpty()) { - BaseLogger.logWarning("Input for toLowerCase is null or empty."); - return pInput; - } - String result = pInput.toLowerCase(); - BaseLogger.bluelibLogSuccess("Converted to lowercase: " + result); - return result; - } - - /** - * A {@link String} that converts a string to UPPERCASE. - *

          - * This method converts all characters in the input string to uppercase. - *

          - * - * @param pInput {@link String} - The input string to be converted. - * @return {@link String} - The converted UPPERCASE string. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public static String toUpperCase(String pInput) { - if (pInput == null || pInput.isEmpty()) { - BaseLogger.logWarning("Input for toUpperCase is null or empty."); - return pInput; - } - String result = pInput.toUpperCase(); - BaseLogger.bluelibLogSuccess("Converted to UPPERCASE: " + result); - return result; - } -} diff --git a/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java b/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java new file mode 100644 index 00000000..300375c4 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java @@ -0,0 +1,182 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.utils.conversion; + +import software.bluelib.utils.logging.BaseLogger; + +/** + * A {@code class} for converting strings between various naming conventions: + * camelCase, PascalCase, snake_case, and kebab-case. + *

          + * Key Methods: + *

            + *
          • {@link #toCamelCase(String)} - Converts input to camelCase.
          • + *
          • {@link #toPascalCase(String)} - Converts input to PascalCase.
          • + *
          • {@link #toSnakeCase(String)} - Converts input to snake_case.
          • + *
          • {@link #toKebabCase(String)} - Converts input to kebab-case.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ +public class CaseConverterUtils { + + /** + * A {@link String} that converts a given {@link String} to camelCase. + *

          + * If the input is in PascalCase, snake_case, or kebab-case, it will be converted accordingly. + * + * @param pInput {@link String} - The input string to be converted. + * @return The camelCase version of the input string. + * @author MeAlam + * @since 1.0.0 + */ + public static String toCamelCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.logWarning("Input for toCamelCase is null or empty."); + return pInput; + } + + if (Character.isUpperCase(pInput.charAt(0)) && !pInput.contains("_") && !pInput.contains("-")) { + BaseLogger.bluelibLogInfo("Input detected as PascalCase."); + return pInput.substring(0, 1).toLowerCase() + pInput.substring(1); + } + + if (pInput.contains("_")) { + BaseLogger.bluelibLogInfo("Input detected as snake_case."); + return convertUsingDelimiter(pInput, "_", true); + } + + if (pInput.contains("-")) { + BaseLogger.bluelibLogInfo("Input detected as kebab-case."); + return convertUsingDelimiter(pInput, "-", true); + } + + BaseLogger.logWarning("Input case is not recognized."); + return pInput; + } + + /** + * A {@link String} that converts a given {@link String} to PascalCase. + *

          + * If the input is in camelCase, snake_case, or kebab-case, it will be converted accordingly. + * + * @param pInput {@link String} - The input string to be converted. + * @return The PascalCase version of the input string. + * @author MeAlam + * @since 1.0.0 + */ + public static String toPascalCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.logWarning("Input for toPascalCase is null or empty."); + return pInput; + } + + if (!pInput.contains("_") && !pInput.contains("-") && Character.isLowerCase(pInput.charAt(0))) { + BaseLogger.bluelibLogInfo("Input detected as camelCase."); + return pInput.substring(0, 1).toUpperCase() + pInput.substring(1); + } + + if (pInput.contains("_")) { + BaseLogger.bluelibLogInfo("Input detected as snake_case."); + return convertUsingDelimiter(pInput, "_", false); + } + + if (pInput.contains("-")) { + BaseLogger.bluelibLogInfo("Input detected as kebab-case."); + return convertUsingDelimiter(pInput, "-", false); + } + + BaseLogger.logWarning("Input case is not recognized."); + return pInput; + } + + /** + * A {@link String} that converts a given {@link String} to snake_case. + *

          + * It converts camelCase, PascalCase, and kebab-case to snake_case by adding underscores where appropriate. + * + * @param pInput {@link String} - The input string to be converted. + * @return The snake_case version of the input string. + * @author MeAlam + * @since 1.0.0 + */ + public static String toSnakeCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.logWarning("Input for toSnakeCase is null or empty."); + return pInput; + } + + String result = pInput.replaceAll("([a-z])([A-Z])", "$1_$2"); + + result = result.toLowerCase(); + + result = result.replace("-", "_"); + + BaseLogger.bluelibLogSuccess("Converted to snake_case: " + result); + return result; + } + + /** + * A {@link String} that converts a given {@link String} to kebab-case. + *

          + * It converts camelCase, PascalCase, and snake_case to kebab-case by adding hyphens where appropriate. + * + * @param pInput {@link String} - The input string to be converted. + * @return The kebab-case version of the input string. + * @author MeAlam + * @since 1.0.0 + */ + public static String toKebabCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.logWarning("Input for toKebabCase is null or empty."); + return pInput; + } + + String result = pInput.replaceAll("([a-z])([A-Z])", "$1-$2"); + + result = result.toLowerCase(); + + result = result.replace("_", "-"); + + BaseLogger.bluelibLogSuccess("Converted to kebab-case: " + result); + return result; + } + + /** + * A {@link String} helper method to convert a string by splitting it using a given delimiter, then converting each part. + * + * @param pInput {@link String} - The input string to be converted. + * @param pDelimiter {@link String} - The delimiter used for splitting the input string. + * @param pIsCamelCase {@code boolean} - Whether the result should be in camelCase (lowercase first letter). + * @return The converted string. + * @author MeAlam + * @since 1.0.0 + */ + private static String convertUsingDelimiter(String pInput, String pDelimiter, boolean pIsCamelCase) { + String[] parts = pInput.split(pDelimiter); + StringBuilder convertedString = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + if (i == 0 && pIsCamelCase) { + convertedString.append(parts[i].toLowerCase()); + } else { + convertedString.append(toProperCase(parts[i])); + } + } + String result = convertedString.toString(); + BaseLogger.bluelibLogSuccess("Converted: " + result); + return result; + } + + /** + * A {@link String} that converts a string to ProperCase, where the first letter is capitalized and the rest are lowercase. + * + * @param pInput {@link String} - The input string to be converted. + * @return The ProperCase version of the input string. + * @author MeAlam + * @since 1.0.0 + */ + private static String toProperCase(String pInput) { + return pInput.substring(0, 1).toUpperCase() + pInput.substring(1).toLowerCase(); + } +} diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java b/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java similarity index 98% rename from NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java rename to NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java index b01056b4..b276ef93 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/ConversionUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java @@ -1,6 +1,6 @@ // Copyright (c) BlueLib. Licensed under the MIT License. -package software.bluelib.utils.math; +package software.bluelib.utils.conversion; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -24,7 +24,7 @@ * @author MeAlam * @since 1.0.0 */ -public class ConversionUtils { +public class MathConverterUtils { /** * A {@link Double} that converts a length from inches to centimeters. From 2ed120534149c13d3faf5d095aa9a7fc77171abd Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 19 Sep 2024 10:44:41 +0200 Subject: [PATCH 21/62] Update ParameterBase.java * Fixed all Comments --- .../entity/variant/base/ParameterBase.java | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java index 0cbf374e..37fe902d 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java @@ -10,23 +10,23 @@ import java.util.Set; /** - * An abstract base class for managing a collection of parameters. + * An {@code public abstract base class} for managing a collection of {@link #parameters}. *

          - * This class provides methods to add, retrieve, remove, and manipulate parameters stored as key-value pairs. + * This {@code class} provides methods to add, retrieve, remove, and manipulate {@link #parameters} stored as key-value pairs. *

          * Key Methods: *
            - *
          • {@link #addParameter(String, Object)} - Adds a parameter to the collection.
          • - *
          • {@link #getParameter(String)} - Retrieves a parameter from the collection.
          • - *
          • {@link #removeParameter(String)} - Removes a parameter from the collection.
          • - *
          • {@link #getAllParameters()} - Returns all parameters in the collection.
          • - *
          • {@link #containsParameter(String)} - Checks if a parameter exists by its key.
          • - *
          • {@link #isEmpty()} - Checks if the collection of parameters is empty.
          • - *
          • {@link #clearParameters()} - Clears all parameters from the collection.
          • - *
          • {@link #getParameterCount()} - Returns the number of parameters in the collection.
          • - *
          • {@link #getParameterKeys()} - Returns a set of all parameter keys.
          • - *
          • {@link #getParameterValues()} - Returns a collection of all parameter values.
          • - *
          • {@link #updateParameter(String, Object)} - Updates the value of an existing parameter.
          • + *
          • {@link #addParameter(String, Object)} - Adds a parameter to {@link #parameters}.
          • + *
          • {@link #getParameter(String)} - Retrieves a parameter from {@link #parameters}.
          • + *
          • {@link #removeParameter(String)} - Removes a parameter from {@link #parameters}.
          • + *
          • {@link #getAllParameters()} - Returns all parameters in {@link #parameters}.
          • + *
          • {@link #containsParameter(String)} - Checks if a parameter exists by its key from {@link #parameters}.
          • + *
          • {@link #isEmpty()} - Checks if {@link #parameters} is empty.
          • + *
          • {@link #clearParameters()} - Clears all parameters from {@link #parameters}.
          • + *
          • {@link #getParameterCount()} - Returns the number of parameters in {@link #parameters}.
          • + *
          • {@link #getParameterKeys()} - Returns a set of all parameter keys from {@link #parameters}.
          • + *
          • {@link #getParameterValues()} - Returns a collection of all parameter values from {@link #parameters}.
          • + *
          • {@link #updateParameter(String, Object)} - Updates the value of an existing parameter in {@link #parameters}.
          • *
          * @author MeAlam * @Co-author Dan @@ -35,9 +35,9 @@ public abstract class ParameterBase { /** - * A {@link Map} to store parameters as key-value pairs. + * A {@code private final} {@link Map} to store parameters as key-value pairs. *

          - * This map holds parameter keys and their corresponding values. + * This {@link Map} holds parameter keys and their corresponding values. *

          * @Co-author MeAlam, Dan * @since 1.0.0 @@ -45,9 +45,9 @@ public abstract class ParameterBase { private final Map parameters = new HashMap<>(); /** - * A {@code void} that adds a parameter to the collection. + * A {@code protected void} that adds a parameter to {@link #parameters}. *

          - * This method stores a new parameter with the specified key and value in the internal map. + * This method stores a new parameter with the specified key and value in {@link #parameters}. *

          * @param pKey {@link String} - The key under which the parameter is stored. * @param pValue {@link Object} - The value of the parameter. @@ -61,12 +61,12 @@ protected void addParameter(String pKey, Object pValue) { } /** - * A {@link Object} that retrieves a parameter from the collection by its key. + * A {@code protected} {@link Object} that retrieves a parameter from {@link #parameters} by its key. *

          * This method returns the value associated with the specified key, or {@code null} if the key does not exist. *

          * @param pKey {@link String} - The key of the parameter to retrieve. - * @return The value associated with the key, or {@code null} if the key does not exist. + * @return {@link Object} - The value associated with the key, or {@code null} if the key does not exist. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -78,9 +78,9 @@ protected Object getParameter(String pKey) { } /** - * A {@code void} that removes a parameter from the collection by its key. + * A {@code protected void} that removes a parameter from {@link #parameters} by its key. *

          - * This method deletes the parameter with the specified key from the internal map. If the key does not exist, no action is taken. + * This method deletes the parameter with the specified key from {@link #parameters}. If the key does not exist, no action is taken. *

          * @param pKey {@link String} - The key of the parameter to remove. * @author MeAlam @@ -96,11 +96,11 @@ protected void removeParameter(String pKey) { } /** - * A {@link Map} that returns all parameters in the collection. + * A {@code protected} {@link Map} that returns all parameters in {@link #parameters}. *

          - * This method returns a new {@link Map} containing all parameters stored in the internal map. + * This method returns a new {@link Map} containing all parameters stored in {@link #parameters}. *

          - * @return A {@link Map} containing all parameters. + * @return {@link Map} - A {@link Map} containing all parameters. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -111,12 +111,12 @@ protected Map getAllParameters() { } /** - * A {@link Boolean} that checks if a parameter exists by its key. + * A {@code protected} {@link Boolean} that checks if a parameter exists by its key. *

          - * This method returns {@code true} if the parameter with the specified key exists in the collection, {@code false} otherwise. + * This method returns {@code true} if the parameter with the specified key exists in {@link #parameters}, {@code false} otherwise. *

          * @param pKey {@link String} - The key of the parameter to check. - * @return {@code true} if the parameter exists, {@code false} otherwise. + * @return {@link Boolean} - {@code true} if the parameter exists, {@code false} otherwise. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -128,11 +128,11 @@ protected boolean containsParameter(String pKey) { } /** - * A {@link Boolean} that checks if the collection of parameters is empty. + * A {@code protected} {@link Boolean} that checks if {@link #parameters} is empty. *

          - * This method returns {@code true} if the collection contains no parameters, {@code false} otherwise. + * This method returns {@code true} if {@link #parameters} contains no parameters, {@code false} otherwise. *

          - * @return {@code true} if the collection is empty, {@code false} otherwise. + * @return {@link Boolean} - {@code true} if {@link #parameters} is empty, {@code false} otherwise. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -144,9 +144,9 @@ protected boolean isEmpty() { } /** - * A {@code void} that clears all parameters from the collection. + * A {@code protected void} that clears all parameters from {@link #parameters}. *

          - * This method removes all parameters from the internal map. + * This method removes all parameters from {@link #parameters}. *

          * @author MeAlam * @Co-author Dan @@ -158,11 +158,11 @@ protected void clearParameters() { } /** - * A {@link Integer} that returns the number of parameters in the collection. + * A {@code protected} {@link Integer} that returns the number of parameters in {@link #parameters}. *

          - * This method provides the count of parameters currently stored in the internal map. + * This method provides the count of parameters currently stored in {@link #parameters}. *

          - * @return The number of parameters in the collection. + * @return {@link Integer} - The number of parameters in the collection. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -174,11 +174,11 @@ protected int getParameterCount() { } /** - * A {@link Set} that returns a set of all parameter keys. + * A {@code protected} {@link Set} that returns a set of all parameter keys. *

          - * This method provides a {@link Set} containing all the keys of parameters in the collection. + * This method provides a {@link Set} containing all the keys of parameters in {@link #parameters}. *

          - * @return A {@link Set} containing all parameter keys. + * @return {@link Set} - A {@link Set} containing all parameter keys. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -189,11 +189,11 @@ protected Set getParameterKeys() { } /** - * A {@link Collection} that returns a collection of all parameter values. + * A {@code protected} {@link Collection} that returns a {@link Collection} of all parameter values. *

          - * This method provides a {@link Collection} containing all the values of parameters in the collection. + * This method provides a {@link Collection} containing all the values of parameters in {@link #parameters}. *

          - * @return A {@link Collection} containing all parameter values. + * @return {@link Collection} - A {@link Collection} containing all parameter values. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -204,9 +204,9 @@ protected Collection getParameterValues() { } /** - * A {@code void} that updates the value of an existing parameter. + * A {@code protected void} that updates the value of an existing parameter. *

          - * This method changes the value of a parameter identified by the specified key. If the key does not exist, an exception is thrown. + * This method changes the value of a parameter in {@link #parameters} that is identified by the specified key. If the key does not exist, an exception is thrown. *

          * @param pKey {@link String} - The key of the parameter to update. * @param pNewValue {@link Object} - The new value to set for the parameter. From 6f5fc5f902f4e45abc9ffc5fc503af52be610a55 Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 19 Sep 2024 10:58:46 +0200 Subject: [PATCH 22/62] Finished Proofreading Variantloader --- .../bluelib/entity/variant/VariantLoader.java | 58 ++++++++++++++----- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java index 510a429b..ccf853c0 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -17,13 +17,15 @@ import java.util.*; /** - * A {@code class} that loads and manages {@link VariantParameter} instances for entities by merging JSON data from multiple sources. + * A {@code public class} that implements the {@link IVariantEntityBase} {@code interface} that manages the loading and storage of entity variants. *

          - * The class handles loading of variant data from both the main mod and latest datapack, merging them, and parsing them into {@link VariantParameter} instances. + * The class handles loading and merging of JSON Data by utilizing the {@link JSONLoader} and {@link JSONMerger} classes.
          + * To load the Variants it loops thru all resources in a folder and merges them into a single {@link JsonObject}.
          + * The merged JSON data is then parsed into {@link VariantParameter} instances and stored in {@link #entityVariantsMap}.
          *

          * Key Methods: *
            - *
          • {@link #loadVariants(String, MinecraftServer, String)} - Loads and merges variant data from both the main mod and the latest datapack.
          • + *
          • {@link #loadVariants(String, MinecraftServer, String)} - Loads and merges variant data by looping thru all resources in a folder.
          • *
          • {@link #getVariantsFromEntity(String)} - Retrieves the list of loaded {@link VariantParameter} for a specific entity.
          • *
          • {@link #getVariantByName(String, String)} - Retrieves a specific {@link VariantParameter} by its name for a given entity.
          • *
          @@ -33,14 +35,42 @@ */ public class VariantLoader implements IVariantEntityBase { + /** + * A {@code private static final} {@link Map} to store entity variants as key-value pairs. + *

          + * This {@link Map} holds entity names and their corresponding list of {@link VariantParameter} instances. + *

          + * @Co-author MeAlam, Dan + * @since 1.0.0 + */ private static final Map> entityVariantsMap = new HashMap<>(); + + /** + * A {@code private static final} {@link JSONLoader} to load JSON data from resources. + *

          + * This {@link JSONLoader} instance is used to load JSON data from resources. + *

          + * @Co-author MeAlam, Dan + * @since 1.0.0 + */ private static final JSONLoader jsonLoader = new JSONLoader(); + + /** + * A {@code private static final} {@link JSONMerger} to merge JSON data. + *

          + * This {@link JSONMerger} instance is used to merge JSON data into a single {@link JsonObject}. + *

          + * @Co-author MeAlam, Dan + * @since 1.0.0 + */ private static final JSONMerger jsonMerger = new JSONMerger(); /** - * A {@code void} that loads and merges variant data from both the main mod and the latest datapack. + * A {@code public static void} that loads and merges variant data from JSON resources. *

          - * This method parses the merged JSON data into {@link VariantParameter} instances and stores them in the internal map. + * This method loads and merges JSON data from resources in the specified folder path.
          + * The method loops thru all resources in the folder and merges them into a single {@link JsonObject}.
          + * The merged JSON data is then parsed into {@link VariantParameter} instances and stored in {@link #entityVariantsMap}. *

          * @param folderPath {@link String} - The path to the folder containing JSON resources. * @param pServer {@link MinecraftServer} - The {@link MinecraftServer} instance used to access resources. @@ -73,7 +103,7 @@ public static void loadVariants(String folderPath, MinecraftServer pServer, Stri } /** - * A {@code void} that clears variants for a specific entity type from the internal map. + * A {@code private static void} that clears variants for a specific entity type from {@link #entityVariantsMap}. *

          * This method removes all variants associated with the given entity name. *

          @@ -85,9 +115,9 @@ private static void clearVariantsForEntity(String pEntityName) { } /** - * A {@code void} that parses the merged JSON data and converts it into {@link VariantParameter} instances. + * A {@code private static void} that parses the merged JSON data and converts it into {@link VariantParameter} instances. *

          - * This method processes each entry in the JSON object and stores the created {@link VariantParameter} instances in the internal map. + * This method processes each entry in the JSON object and stores the created {@link VariantParameter} instances in {@link #entityVariantsMap}. *

          * @param pJsonObject {@link JsonObject} - The merged {@link JsonObject} containing variant data. */ @@ -113,25 +143,25 @@ private static void parseVariants(JsonObject pJsonObject) { } /** - * A {@link VariantParameter} that creates a new {@link VariantParameter} instance from a JSON object. + * A {@code private static} {@link VariantParameter} that creates a new {@link VariantParameter} instance from a JSON object. *

          * This method wraps the creation of {@link VariantParameter} instances for easier management and potential modification. *

          * @param pJsonKey {@link String} - The key associated with this variant. * @param pJsonObject {@link JsonObject} - The {@link JsonObject} containing the variant data. - * @return A {@link VariantParameter} instance. + * @return {@link VariantParameter} - A {@link VariantParameter} instance. */ private static VariantParameter getEntityVariant(String pJsonKey, JsonObject pJsonObject) { return new VariantParameter(pJsonKey, pJsonObject); } /** - * A {@link List} that retrieves the {@link List} of loaded {@link VariantParameter} instances for a specific entity. + * A {@code public static} {@link List} that retrieves the {@link List} of loaded {@link VariantParameter} instances for a specific entity. *

          * This method returns a list of variants for the given entity name. If no variants are found, an empty list is returned. *

          * @param pEntityName {@link String} - The name of the entity to retrieve variants for. - * @return A {@link List} of {@link VariantParameter} instances for the specified entity. + * @return {@link List} - A {@link List} of {@link VariantParameter} instances for the specified entity. */ public static List getVariantsFromEntity(String pEntityName) { BaseLogger.bluelibLogInfo("Retrieving variants for entity: " + pEntityName); @@ -139,13 +169,13 @@ public static List getVariantsFromEntity(String pEntityName) { } /** - * A {@link VariantParameter} that retrieves a {@link VariantParameter} by its name for a specific entity. + * A {@code public static} {@link VariantParameter} that retrieves a {@link VariantParameter} by its name for a specific entity. *

          * This method searches for a variant with the specified name within the list of variants for the given entity. *

          * @param pEntityName {@link String} - The name of the entity to retrieve variants for. * @param pVariantName {@link String} - The name of the variant to retrieve. - * @return The {@link VariantParameter} with the specified name, or {@code null} if not found. + * @return {@link VariantParameter} - The {@link VariantParameter} with the specified name, or {@code null} if not found. */ public static VariantParameter getVariantByName(String pEntityName, String pVariantName) { BaseLogger.bluelibLogInfo("Retrieving variant by name: " + pVariantName + " for entity: " + pEntityName); From 8003e546e047947214372523c0ae1fa798474323 Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 26 Sep 2024 13:36:01 +0200 Subject: [PATCH 23/62] Refactored all Logging * Need to go thru all Files Fixing the Logging and Comments --- .../main/java/software/bluelib/BlueLib.java | 5 +- .../bluelib/entity/variant/VariantLoader.java | 21 ++- .../entity/variant/VariantParameter.java | 20 +-- .../entity/variant/base/ParameterBase.java | 27 ++-- .../bluelib/event/ReloadEventHandler.java | 8 +- .../example/entity/dragon/DragonEntity.java | 8 +- .../interfaces/variant/IVariantEntity.java | 4 +- .../variant/base/IVariantEntityBase.java | 2 +- .../software/bluelib/json/JSONLoader.java | 8 +- .../software/bluelib/json/JSONMerger.java | 10 +- .../utils/conversion/CaseConverterUtils.java | 30 ++-- .../utils/conversion/MathConverterUtils.java | 4 +- ...BlueLibLogLevel.java => BaseLogLevel.java} | 2 +- .../bluelib/utils/logging/BaseLogger.java | 128 +++--------------- .../logging/DefaultLogColorProvider.java | 20 +-- .../bluelib/utils/logging/LoggerConfig.java | 22 ++- .../bluelib/utils/math/AlgebraicUtils.java | 12 +- .../bluelib/utils/math/GeometricUtils.java | 20 +-- .../bluelib/utils/math/MatrixUtils.java | 8 +- .../bluelib/utils/math/MiscUtils.java | 8 +- .../bluelib/utils/math/RandomGenUtils.java | 8 +- .../bluelib/utils/math/StatisticalUtils.java | 28 ++-- .../bluelib/utils/minecraft/ChunkUtils.java | 22 ++- .../bluelib/utils/variant/ParameterUtils.java | 2 +- 24 files changed, 173 insertions(+), 254 deletions(-) rename NeoForge/src/main/java/software/bluelib/utils/logging/{BlueLibLogLevel.java => BaseLogLevel.java} (97%) diff --git a/NeoForge/src/main/java/software/bluelib/BlueLib.java b/NeoForge/src/main/java/software/bluelib/BlueLib.java index e390e67a..a2a53040 100644 --- a/NeoForge/src/main/java/software/bluelib/BlueLib.java +++ b/NeoForge/src/main/java/software/bluelib/BlueLib.java @@ -10,6 +10,7 @@ import net.neoforged.fml.loading.FMLEnvironment; import software.bluelib.example.event.ClientEvents; import software.bluelib.example.init.ModEntities; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.util.concurrent.Executors; @@ -120,9 +121,9 @@ public void onLoadComplete(FMLLoadCompleteEvent pEvent) { static boolean isDeveloperMode() { boolean isDevMode = !FMLEnvironment.production; if (isDevMode) { - BaseLogger.bluelibLogSuccess("Running in Developer mode."); + BaseLogger.log(BaseLogLevel.INFO ,"Running in Developer mode.", true); } else { - BaseLogger.bluelibLogSuccess("Running in Production mode."); + BaseLogger.log(BaseLogLevel.INFO ,"Running in Production mode.", true); } return isDevMode; } diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java index ccf853c0..1126248f 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -8,7 +8,6 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.packs.resources.ResourceManager; -import software.bluelib.BlueLib; import software.bluelib.interfaces.variant.base.IVariantEntityBase; import software.bluelib.json.JSONLoader; import software.bluelib.json.JSONMerger; @@ -77,7 +76,7 @@ public class VariantLoader implements IVariantEntityBase { * @param pEntityName {@link String} - The name of the entity whose variants should be cleared before loading new ones. */ public static void loadVariants(String folderPath, MinecraftServer pServer, String pEntityName) { - BaseLogger.bluelibLogInfo("Starting to load variants for entity: " + pEntityName); + BaseLogger.log("Starting to load variants for entity: " + pEntityName); clearVariantsForEntity(pEntityName); @@ -86,19 +85,19 @@ public static void loadVariants(String folderPath, MinecraftServer pServer, Stri Collection collection = resourceManager.listResources(folderPath, pFiles -> pFiles.getPath().endsWith(".json")).keySet(); - BaseLogger.bluelibLogSuccess("Found resources: " + collection); + BaseLogger.log("Found resources: " + collection); for (ResourceLocation resourceLocation : collection) { try { - BaseLogger.bluelibLogInfo("Loading JSON data from resource: " + resourceLocation.toString()); + BaseLogger.log("Loading JSON data from resource: " + resourceLocation.toString()); JsonObject jsonObject = jsonLoader.loadJson(resourceLocation, resourceManager); jsonMerger.mergeJsonObjects(mergedJsonObject, jsonObject); } catch (Exception pException) { - BaseLogger.logError("Failed to load JSON data from resource: " + resourceLocation.toString(), pException); + BaseLogger.log("Failed to load JSON data from resource: " + resourceLocation.toString(), pException); } } - BaseLogger.bluelibLogSuccess("Successfully loaded and merged JSON data for entity: " + pEntityName); + BaseLogger.log("Successfully loaded and merged JSON data for entity: " + pEntityName); parseVariants(mergedJsonObject); } @@ -110,7 +109,7 @@ public static void loadVariants(String folderPath, MinecraftServer pServer, Stri * @param pEntityName {@link String} - The name of the entity whose variants should be cleared. */ private static void clearVariantsForEntity(String pEntityName) { - BaseLogger.bluelibLogInfo("Clearing variants for entity: " + pEntityName); + BaseLogger.log("Clearing variants for entity: " + pEntityName); entityVariantsMap.remove(pEntityName); } @@ -126,7 +125,7 @@ private static void parseVariants(JsonObject pJsonObject) { String entityName = entry.getKey(); JsonArray textureArray = entry.getValue().getAsJsonArray(); - BaseLogger.bluelibLogInfo("Parsing variants for entity: " + entityName); + BaseLogger.log("Parsing variants for entity: " + entityName); List variantList = entityVariantsMap.computeIfAbsent(entityName, k -> new ArrayList<>()); for (JsonElement variant : textureArray) { @@ -164,7 +163,7 @@ private static VariantParameter getEntityVariant(String pJsonKey, JsonObject pJs * @return {@link List} - A {@link List} of {@link VariantParameter} instances for the specified entity. */ public static List getVariantsFromEntity(String pEntityName) { - BaseLogger.bluelibLogInfo("Retrieving variants for entity: " + pEntityName); + BaseLogger.log("Retrieving variants for entity: " + pEntityName); return entityVariantsMap.getOrDefault(pEntityName, new ArrayList<>()); } @@ -178,14 +177,14 @@ public static List getVariantsFromEntity(String pEntityName) { * @return {@link VariantParameter} - The {@link VariantParameter} with the specified name, or {@code null} if not found. */ public static VariantParameter getVariantByName(String pEntityName, String pVariantName) { - BaseLogger.bluelibLogInfo("Retrieving variant by name: " + pVariantName + " for entity: " + pEntityName); + BaseLogger.log("Retrieving variant by name: " + pVariantName + " for entity: " + pEntityName); List variants = getVariantsFromEntity(pEntityName); for (VariantParameter variant : variants) { if (variant.getVariantName().equals(pVariantName)) { return variant; } } - BaseLogger.logWarning("Variant with name: " + pVariantName + " not found for entity: " + pEntityName); + BaseLogger.log("Variant with name: " + pVariantName + " not found for entity: " + pEntityName); return null; } } diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java index 1dadbbd3..a3c1565f 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java @@ -62,17 +62,17 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { if (pJsonKey == null || pJsonObject == null) { Throwable throwable = new Throwable("JSON key or JSON object is null"); IllegalArgumentException exception = new IllegalArgumentException("JSON key and object must not be null"); - BaseLogger.logError(exception.toString(), throwable); + BaseLogger.log(exception.toString(), throwable); throw exception; } this.jsonKey = pJsonKey; - BaseLogger.bluelibLogInfo("Creating VariantParameter with JSON key: " + pJsonKey); + BaseLogger.log("Creating VariantParameter with JSON key: " + pJsonKey); Set> entryMap = pJsonObject.entrySet(); for (Map.Entry entry : entryMap) { JsonElement element = entry.getValue(); if (element.isJsonPrimitive()) { addParameter(entry.getKey(), element.getAsString()); - BaseLogger.bluelibLogInfo("Added primitive parameter: " + entry.getKey() + " = " + element.getAsString()); + BaseLogger.log("Added primitive parameter: " + entry.getKey() + " = " + element.getAsString()); } else if (element.isJsonArray()) { StringBuilder arrayValues = new StringBuilder(); element.getAsJsonArray().forEach(e -> arrayValues.append(e.getAsString()).append(",")); @@ -80,13 +80,13 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { arrayValues.setLength(arrayValues.length() - 1); // Remove trailing comma } addParameter(entry.getKey(), arrayValues.toString()); - BaseLogger.bluelibLogInfo("Added array parameter: " + entry.getKey() + " = " + arrayValues.toString()); + BaseLogger.log("Added array parameter: " + entry.getKey() + " = " + arrayValues.toString()); } else if (element.isJsonObject()) { addParameter(entry.getKey(), element.toString()); - BaseLogger.bluelibLogInfo("Added object parameter: " + entry.getKey() + " = " + element.toString()); + BaseLogger.log("Added object parameter: " + entry.getKey() + " = " + element.toString()); } else { addParameter(entry.getKey(), "null"); - BaseLogger.bluelibLogInfo("Added null parameter for key: " + entry.getKey()); + BaseLogger.log("Added null parameter for key: " + entry.getKey()); } } } @@ -106,10 +106,10 @@ public String getJsonKey() { if (this.jsonKey == null) { Throwable throwable = new Throwable("JSON key should not be null"); IllegalStateException exception = new IllegalStateException("JSON key is unexpectedly null when retrieving from VariantParameter."); - BaseLogger.logError(exception.toString(), throwable); + BaseLogger.log(exception.toString(), throwable); throw exception; } - BaseLogger.bluelibLogSuccess("Retrieved JSON key: " + this.jsonKey); + BaseLogger.log("Retrieved JSON key: " + this.jsonKey); return this.jsonKey; } @@ -125,7 +125,7 @@ public String getJsonKey() { */ public String getVariantName() { String variantName = getParameter("variantName"); - BaseLogger.bluelibLogSuccess("Retrieved variant name: " + variantName); + BaseLogger.log("Retrieved variant name: " + variantName); return variantName; } @@ -142,7 +142,7 @@ public String getVariantName() { */ public String getParameter(String pKey) { String value = (String) super.getParameter(pKey); - BaseLogger.bluelibLogSuccess("Retrieved parameter for key " + pKey + ": " + value); + BaseLogger.log("Retrieved parameter for key " + pKey + ": " + value); return value; } } diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java index 37fe902d..cf81e48d 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java @@ -2,6 +2,7 @@ package software.bluelib.entity.variant.base; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.util.Collection; @@ -57,7 +58,7 @@ public abstract class ParameterBase { */ protected void addParameter(String pKey, Object pValue) { parameters.put(pKey, pValue); - BaseLogger.bluelibLogSuccess(String.format("Parameter added: Key = %s, Value = %s", pKey, pValue)); + BaseLogger.log(BaseLogLevel.SUCCESS, String.format("Parameter added: Key = %s, Value = %s", pKey, pValue), true); } /** @@ -73,7 +74,7 @@ protected void addParameter(String pKey, Object pValue) { */ protected Object getParameter(String pKey) { Object value = parameters.get(pKey); - BaseLogger.bluelibLogSuccess(String.format("Parameter retrieved: Key = %s, Value = %s", pKey, value)); + BaseLogger.log(BaseLogLevel.INFO, String.format("Parameter retrieved: Key = %s, Value = %s", pKey, value), true); return value; } @@ -89,9 +90,9 @@ protected Object getParameter(String pKey) { */ protected void removeParameter(String pKey) { if (parameters.remove(pKey) != null) { - BaseLogger.bluelibLogSuccess(String.format("Parameter removed: Key = %s", pKey)); + BaseLogger.log(BaseLogLevel.SUCCESS, String.format("Parameter removed: Key = %s", pKey), true); } else { - BaseLogger.logWarning(String.format("Attempted to remove non-existent parameter: Key = %s", pKey)); + BaseLogger.log(BaseLogLevel.WARNING, String.format("Attempted to remove non-existent parameter: Key = %s", pKey), true); } } @@ -106,7 +107,7 @@ protected void removeParameter(String pKey) { * @since 1.0.0 */ protected Map getAllParameters() { - BaseLogger.bluelibLogSuccess("Retrieved all parameters."); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved all parameters.", true); return new HashMap<>(parameters); } @@ -123,7 +124,7 @@ protected Map getAllParameters() { */ protected boolean containsParameter(String pKey) { boolean exists = parameters.containsKey(pKey); - BaseLogger.bluelibLogInfo(String.format("Parameter existence check: Key = %s, Exists = %b", pKey, exists)); + BaseLogger.log(BaseLogLevel.INFO, String.format("Parameter existence check: Key = %s, Exists = %b", pKey, exists), true); return exists; } @@ -139,7 +140,7 @@ protected boolean containsParameter(String pKey) { */ protected boolean isEmpty() { boolean empty = parameters.isEmpty(); - BaseLogger.bluelibLogInfo("Checked if parameters are empty: " + empty); + BaseLogger.log(BaseLogLevel.INFO, "Checked if parameters are empty: " + empty, true); return empty; } @@ -154,7 +155,7 @@ protected boolean isEmpty() { */ protected void clearParameters() { parameters.clear(); - BaseLogger.bluelibLogSuccess("Cleared all parameters."); + BaseLogger.log(BaseLogLevel.SUCCESS, "Cleared all parameters.", true); } /** @@ -169,7 +170,7 @@ protected void clearParameters() { */ protected int getParameterCount() { int count = parameters.size(); - BaseLogger.bluelibLogSuccess("Retrieved parameter count: " + count); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter count: " + count, true); return count; } @@ -184,7 +185,7 @@ protected int getParameterCount() { * @since 1.0.0 */ protected Set getParameterKeys() { - BaseLogger.bluelibLogSuccess("Retrieved parameter keys."); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter keys.", true); return parameters.keySet(); } @@ -199,7 +200,7 @@ protected Set getParameterKeys() { * @since 1.0.0 */ protected Collection getParameterValues() { - BaseLogger.bluelibLogSuccess("Retrieved parameter values."); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter values.", true); return parameters.values(); } @@ -218,11 +219,11 @@ protected Collection getParameterValues() { protected void updateParameter(String pKey, Object pNewValue) { if (parameters.containsKey(pKey)) { parameters.put(pKey, pNewValue); - BaseLogger.bluelibLogInfo(String.format("Parameter updated: Key = %s, New Value = %s", pKey, pNewValue)); + BaseLogger.log(BaseLogLevel.SUCCESS, String.format("Parameter updated: Key = %s, New Value = %s", pKey, pNewValue), true); } else { Throwable throwable = new Throwable("Key does not exist: " + pKey); IllegalArgumentException exception = new IllegalArgumentException("Key does not exist: " + pKey); - BaseLogger.logError(String.format("Attempted to update non-existent parameter: Key = %s", pKey), throwable); + BaseLogger.log(BaseLogLevel.ERROR, String.format("Attempted to update non-existent parameter: Key = %s", pKey), throwable, true); throw exception; } } diff --git a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java index f66a0dad..c2c936e2 100644 --- a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -65,16 +65,16 @@ public class ReloadEventHandler { */ protected static void registerEntityVariants(String pFolderPath, MinecraftServer pServer, String pModID, String pEntityName) { - BaseLogger.bluelibLogInfo("Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID); + BaseLogger.log("Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID); try { VariantLoader.loadVariants(pFolderPath, pServer, pEntityName); - BaseLogger.bluelibLogSuccess("Successfully registered entity variants for " + pEntityName + " from ModID: " + pModID); + BaseLogger.log("Successfully registered entity variants for " + pEntityName + " from ModID: " + pModID); } catch (JsonParseException pException) { - BaseLogger.logError("Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); + BaseLogger.log("Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); throw pException; } catch (Exception pException) { - BaseLogger.logError("Unexpected error occurred while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); + BaseLogger.log("Unexpected error occurred while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); throw pException; } } diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 8078c6ae..67c62890 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -12,10 +12,8 @@ import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; -import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import software.bernie.geckolib.animatable.GeoEntity; @@ -24,12 +22,8 @@ import software.bernie.geckolib.util.GeckoLibUtil; import software.bluelib.interfaces.variant.IVariantEntity; import software.bluelib.utils.logging.BaseLogger; -import software.bluelib.utils.minecraft.ChunkUtils; import software.bluelib.utils.variant.ParameterUtils; -import java.util.Arrays; -import java.util.Collection; - /** * A {@code DragonEntity} class representing a dragon entity in the game, which extends {@link TamableAnimal} * and implements {@link IVariantEntity} and {@link GeoEntity}. @@ -165,7 +159,7 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul .withParameter("array") .connect(); } - BaseLogger.logSuccess("Dragon Spawned with Variant: " + getVariantName()); + BaseLogger.log("Dragon Spawned with Variant: " + getVariantName()); return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java index bc662430..65364163 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java @@ -49,12 +49,12 @@ public interface IVariantEntity extends IVariantEntityBase { */ default String getRandomVariant(List pVariantNamesList, String pDefaultVariant) { if (pVariantNamesList.isEmpty()) { - BaseLogger.logWarning("Variant names list is empty. Returning default variant: " + pDefaultVariant); + BaseLogger.log("Variant names list is empty. Returning default variant: " + pDefaultVariant); return pDefaultVariant; } int index = random.nextInt(pVariantNamesList.size()); String selectedVariant = pVariantNamesList.get(index); - BaseLogger.bluelibLogSuccess("Selected random variant: " + selectedVariant + " from list of size: " + pVariantNamesList.size()); + BaseLogger.log("Selected random variant: " + selectedVariant + " from list of size: " + pVariantNamesList.size()); return selectedVariant; } } diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index 2805eb3e..991a8184 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -62,7 +62,7 @@ default List getEntityVariants(String pEntityName) { List variantNames = variants.stream() .map(VariantParameter::getVariantName) .collect(Collectors.toList()); - BaseLogger.bluelibLogSuccess("Retrieved " + variantNames.size() + " variants for entity: " + pEntityName); + BaseLogger.log("Retrieved " + variantNames.size() + " variants for entity: " + pEntityName); return variantNames; } } diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java b/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java index 827cabe1..697924ec 100644 --- a/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java +++ b/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java @@ -50,13 +50,13 @@ public class JSONLoader { * @since 1.0.0 */ public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager pResourceManager) { - BaseLogger.bluelibLogInfo("Attempting to load JSON resource: " + pResourceLocation); + BaseLogger.log("Attempting to load JSON resource: " + pResourceLocation); try { Optional resource = pResourceManager.getResource(pResourceLocation); if (resource.isEmpty()) { - BaseLogger.logWarning("Resource not found: " + pResourceLocation); + BaseLogger.log("Resource not found: " + pResourceLocation); return new JsonObject(); } @@ -64,12 +64,12 @@ public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager p InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { JsonObject jsonObject = gson.fromJson(reader, JsonObject.class); - BaseLogger.bluelibLogSuccess("Successfully loaded JSON resource: " + pResourceLocation); + BaseLogger.log("Successfully loaded JSON resource: " + pResourceLocation); return jsonObject; } } catch (IOException pException) { RuntimeException exception = new RuntimeException("Failed to load JSON resource: " + pResourceLocation, pException); - BaseLogger.logError("Failed to load JSON resource: " + pResourceLocation, exception); + BaseLogger.log("Failed to load JSON resource: " + pResourceLocation, exception); throw exception; } } diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java b/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java index 551a368c..7291d942 100644 --- a/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java +++ b/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java @@ -39,7 +39,7 @@ public class JSONMerger { * @param pSource {@link JsonObject} - The source {@link JsonObject} to merge data from. This object is not modified by the operation. */ public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { - BaseLogger.bluelibLogInfo("Starting JSON merge operation."); + BaseLogger.log("Starting JSON merge operation."); for (Map.Entry entry : pSource.entrySet()) { String key = entry.getKey(); @@ -56,17 +56,17 @@ public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { targetArray.add(element); } - BaseLogger.bluelibLogInfo("Merged array for key: " + key); + BaseLogger.log("Merged array for key: " + key); } else { pTarget.add(key, sourceElement); - BaseLogger.bluelibLogInfo("Overwriting value for key: " + key); + BaseLogger.log("Overwriting value for key: " + key); } } else { pTarget.add(key, sourceElement); - BaseLogger.bluelibLogInfo("Adding new key: " + key); + BaseLogger.log("Adding new key: " + key); } } - BaseLogger.bluelibLogSuccess("JSON merge operation completed."); + BaseLogger.log("JSON merge operation completed."); } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java b/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java index 300375c4..2e9d6438 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java @@ -33,26 +33,26 @@ public class CaseConverterUtils { */ public static String toCamelCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.logWarning("Input for toCamelCase is null or empty."); + BaseLogger.log("Input for toCamelCase is null or empty."); return pInput; } if (Character.isUpperCase(pInput.charAt(0)) && !pInput.contains("_") && !pInput.contains("-")) { - BaseLogger.bluelibLogInfo("Input detected as PascalCase."); + BaseLogger.log("Input detected as PascalCase."); return pInput.substring(0, 1).toLowerCase() + pInput.substring(1); } if (pInput.contains("_")) { - BaseLogger.bluelibLogInfo("Input detected as snake_case."); + BaseLogger.log("Input detected as snake_case."); return convertUsingDelimiter(pInput, "_", true); } if (pInput.contains("-")) { - BaseLogger.bluelibLogInfo("Input detected as kebab-case."); + BaseLogger.log("Input detected as kebab-case."); return convertUsingDelimiter(pInput, "-", true); } - BaseLogger.logWarning("Input case is not recognized."); + BaseLogger.log("Input case is not recognized."); return pInput; } @@ -68,26 +68,26 @@ public static String toCamelCase(String pInput) { */ public static String toPascalCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.logWarning("Input for toPascalCase is null or empty."); + BaseLogger.log("Input for toPascalCase is null or empty."); return pInput; } if (!pInput.contains("_") && !pInput.contains("-") && Character.isLowerCase(pInput.charAt(0))) { - BaseLogger.bluelibLogInfo("Input detected as camelCase."); + BaseLogger.log("Input detected as camelCase."); return pInput.substring(0, 1).toUpperCase() + pInput.substring(1); } if (pInput.contains("_")) { - BaseLogger.bluelibLogInfo("Input detected as snake_case."); + BaseLogger.log("Input detected as snake_case."); return convertUsingDelimiter(pInput, "_", false); } if (pInput.contains("-")) { - BaseLogger.bluelibLogInfo("Input detected as kebab-case."); + BaseLogger.log("Input detected as kebab-case."); return convertUsingDelimiter(pInput, "-", false); } - BaseLogger.logWarning("Input case is not recognized."); + BaseLogger.log("Input case is not recognized."); return pInput; } @@ -103,7 +103,7 @@ public static String toPascalCase(String pInput) { */ public static String toSnakeCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.logWarning("Input for toSnakeCase is null or empty."); + BaseLogger.log("Input for toSnakeCase is null or empty."); return pInput; } @@ -113,7 +113,7 @@ public static String toSnakeCase(String pInput) { result = result.replace("-", "_"); - BaseLogger.bluelibLogSuccess("Converted to snake_case: " + result); + BaseLogger.log("Converted to snake_case: " + result); return result; } @@ -129,7 +129,7 @@ public static String toSnakeCase(String pInput) { */ public static String toKebabCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.logWarning("Input for toKebabCase is null or empty."); + BaseLogger.log("Input for toKebabCase is null or empty."); return pInput; } @@ -139,7 +139,7 @@ public static String toKebabCase(String pInput) { result = result.replace("_", "-"); - BaseLogger.bluelibLogSuccess("Converted to kebab-case: " + result); + BaseLogger.log("Converted to kebab-case: " + result); return result; } @@ -164,7 +164,7 @@ private static String convertUsingDelimiter(String pInput, String pDelimiter, bo } } String result = convertedString.toString(); - BaseLogger.bluelibLogSuccess("Converted: " + result); + BaseLogger.log("Converted: " + result); return result; } diff --git a/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java b/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java index b276ef93..f374af12 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java @@ -110,7 +110,7 @@ public static Date stringToDate(String pDateStr, String pFormat) throws ParseExc SimpleDateFormat formatter = new SimpleDateFormat(pFormat); return formatter.parse(pDateStr); } catch (ParseException pException) { - BaseLogger.logError("Error parsing date string: " + pDateStr + " with format: " + pFormat, pException); + BaseLogger.log("Error parsing date string: " + pDateStr + " with format: " + pFormat, pException); throw pException; } } @@ -129,7 +129,7 @@ public static String dateToString(Date pDate, String pFormat) { SimpleDateFormat formatter = new SimpleDateFormat(pFormat); return formatter.format(pDate); } catch (Exception pException) { - BaseLogger.logError("Error formatting date: " + pDate.toString() + " with format: " + pFormat, pException); + BaseLogger.log("Error formatting date: " + pDate.toString() + " with format: " + pFormat, pException); return pException.getMessage(); } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BlueLibLogLevel.java b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java similarity index 97% rename from NeoForge/src/main/java/software/bluelib/utils/logging/BlueLibLogLevel.java rename to NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java index 11f92169..c8fc618a 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/BlueLibLogLevel.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java @@ -19,7 +19,7 @@ * @author MeAlam * @since 1.0.0 */ -public class BlueLibLogLevel { +public class BaseLogLevel { public static final Level INFO = new Level("INFO: ", Level.INFO.intValue()) {}; public static final Level ERROR = new Level("ERROR: ", Level.SEVERE.intValue()) {}; public static final Level WARNING = new Level("WARNING: ", Level.WARNING.intValue()) {}; diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java index 29b11a70..37bffaf2 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -2,151 +2,63 @@ package software.bluelib.utils.logging; +import java.util.logging.Level; import java.util.logging.Logger; -/** - * A {@code class} class that provides a centralized logging mechanism for BlueLib, - * with support for custom log levels and colored output. - *

          - * The {@link BaseLogger} allows for enabling/disabling logging and includes methods - * for logging messages at different levels. It also supports conditional logging based - * on the {@code bluelibLogging} flag, which determines if BlueLib-specific logs should be output. - *

          - * Key Methods: - *

            - *
          • {@link #setBlueLibLoggingEnabled(boolean)} - Enables or disables BlueLib-specific logging.
          • - *
          • {@link #isBlueLibLoggingEnabled()} - Checks if BlueLib-specific logging is enabled.
          • - *
          • {@link #isLoggingEnabled()} - Checks if general logging is enabled.
          • - *
          • {@link #setLoggingEnabled(boolean)} - Enables or disables general logging.
          • - *
          • {@link #logError(String, Throwable)} - Logs an error message with an associated throwable.
          • - *
          • {@link #logWarning(String)} - Logs a warning message.
          • - *
          • {@link #logBlueLib(String)} - Logs a BlueLib-specific message.
          • - *
          • {@link #bluelibLogSuccess(String)} - Logs a success message if BlueLib-specific logging is enabled.
          • - *
          • {@link #bluelibLogInfo(String)} - Logs an info message if BlueLib-specific logging is enabled.
          • - *
          • {@link #logSuccess(String)} - Logs a success message if general logging is enabled.
          • - *
          • {@link #logInfo(String)} - Logs an info message if general logging is enabled.
          • - *
          - * @author MeAlam - * @since 1.0.0 - */ public class BaseLogger { private static final Logger logger = Logger.getLogger(BaseLogger.class.getName()); //FIXME: Set to false before release - private static boolean bluelibLogging = false; + private static boolean bluelibLogging = true; - private static boolean logging = true; + private static boolean isLoggingEnabled = true; - /** - * Enables or disables BlueLib-specific logging. - * - * @param pEnabled {@link boolean} - {@code true} to enable BlueLib logging, {@code false} to disable. - */ public static void setBlueLibLoggingEnabled(boolean pEnabled) { bluelibLogging = pEnabled; } - /** - * Checks if BlueLib-specific logging is enabled. - * - * @return {@link boolean} - {@code true} if BlueLib logging is enabled, {@code false} otherwise. - */ public static boolean isBlueLibLoggingEnabled() { return bluelibLogging; } - /** - * Checks if general logging is enabled. - * - * @return {@link boolean} - {@code true} if general logging is enabled, {@code false} otherwise. - */ public static boolean isLoggingEnabled() { - return logging; + return isLoggingEnabled; } - /** - * Enables or disables general logging. - * - * @param pEnabled {@link boolean} - {@code true} to enable logging, {@code false} to disable. - */ public static void setLoggingEnabled(boolean pEnabled) { - logging = pEnabled; + isLoggingEnabled = pEnabled; } static { LoggerConfig.configureLogger(logger, new DefaultLogColorProvider()); } - /** - * A {@code void} method that logs an error message with an associated {@link Throwable}. - * - * @param pMessage {@link String} - The error message to be logged. - * @param pThrowable {@link Throwable} - The throwable associated with the error. - */ - public static void logError(String pMessage, Throwable pThrowable) { - logger.log(BlueLibLogLevel.ERROR, pMessage, pThrowable); - } - - /** - * A {@code void} method that logs a warning message. - * - * @param pMessage {@link String} - The warning message to be logged. - */ - public static void logWarning(String pMessage) { - logger.log(BlueLibLogLevel.WARNING, pMessage); - } - - /** - * A {@code void} method that logs a BlueLib-specific message. - * - * @param pMessage {@link String} - The BlueLib-specific message to be logged. - */ - public static void logBlueLib(String pMessage) { - logger.log(BlueLibLogLevel.BLUELIB, pMessage); + public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, boolean pIsBlueLib) { + if (pIsBlueLib && bluelibLogging) { + logger.log(pLogLevel, pMessage, pThrowable); + } } - /** - * A {@code void} method that logs a success message if BlueLib-specific logging is enabled. - * - * @param pMessage {@link String} - The success message to be logged. - */ - public static void bluelibLogSuccess(String pMessage) { - if (bluelibLogging) { - logger.log(BlueLibLogLevel.SUCCESS, pMessage); + public static void log(Level pLogLevel,String pMessage, boolean pIsBlueLib) { + if (pIsBlueLib && bluelibLogging) { + logger.log(pLogLevel, pMessage); } } - /** - * A {@code void} method that logs an info message if BlueLib-specific logging is enabled. - * - * @param pMessage {@link String} - The info message to be logged. - */ - public static void bluelibLogInfo(String pMessage) { - if (bluelibLogging) { - logger.log(BlueLibLogLevel.INFO, pMessage); + public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { + if (isLoggingEnabled) { + logger.log(pLogLevel, pMessage, pThrowable); } } - /** - * A {@code void} method that logs a success message if general logging is enabled. - * - * @param pMessage {@link String} - The success message to be logged. - */ - public static void logSuccess(String pMessage) { - if (logging) { - logger.log(BlueLibLogLevel.SUCCESS, pMessage); + public static void log(Level pLogLevel,String pMessage) { + if (isLoggingEnabled) { + logger.log(pLogLevel, pMessage); } } - /** - * A {@code void} method that logs an info message if general logging is enabled. - * - * @param pMessage {@link String} - The info message to be logged. - */ - public static void logInfo(String pMessage) { - if (logging) { - logger.log(BlueLibLogLevel.INFO, pMessage); - } + public static void logBlueLib(String pMessage) { + logger.log(BaseLogLevel.BLUELIB, pMessage); } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java b/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java index 0e28411a..81d5f0a0 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java @@ -12,11 +12,11 @@ *

          * This implementation uses predefined colors for various log levels, including: *

            - *
          • {@link BlueLibLogLevel#ERROR} - Red color.
          • - *
          • {@link BlueLibLogLevel#WARNING} - Orange color.
          • - *
          • {@link BlueLibLogLevel#INFO} - Blue color.
          • - *
          • {@link BlueLibLogLevel#SUCCESS} - Green color.
          • - *
          • {@link BlueLibLogLevel#BLUELIB} - Green color.
          • + *
          • {@link BaseLogLevel#ERROR} - Red color.
          • + *
          • {@link BaseLogLevel#WARNING} - Orange color.
          • + *
          • {@link BaseLogLevel#INFO} - Blue color.
          • + *
          • {@link BaseLogLevel#SUCCESS} - Green color.
          • + *
          • {@link BaseLogLevel#BLUELIB} - Green color.
          • *
          * @author MeAlam * @since 1.0.0 @@ -34,15 +34,15 @@ public class DefaultLogColorProvider implements ILogColorProvider { */ @Override public String getColor(Level pLevel) { - if (pLevel == BlueLibLogLevel.ERROR) { + if (pLevel == BaseLogLevel.ERROR) { return LoggerConfig.RED; - } else if (pLevel == BlueLibLogLevel.WARNING) { + } else if (pLevel == BaseLogLevel.WARNING) { return LoggerConfig.ORANGE; - } else if (pLevel == BlueLibLogLevel.INFO) { + } else if (pLevel == BaseLogLevel.INFO) { return LoggerConfig.BLUE; - } else if (pLevel == BlueLibLogLevel.SUCCESS) { + } else if (pLevel == BaseLogLevel.SUCCESS) { return LoggerConfig.GREEN; - } else if (pLevel == BlueLibLogLevel.BLUELIB) { + } else if (pLevel == BaseLogLevel.BLUELIB) { return LoggerConfig.GREEN; } else { return LoggerConfig.RESET; diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java index a5954da7..f92a8f1e 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java @@ -4,7 +4,10 @@ import software.bluelib.interfaces.logging.ILogColorProvider; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.logging.ConsoleHandler; +import java.util.logging.LogRecord; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; @@ -37,12 +40,23 @@ public abstract class LoggerConfig { public static void configureLogger(Logger pLogger, ILogColorProvider pColorProvider) { ConsoleHandler handler = new ConsoleHandler(); handler.setFormatter(new SimpleFormatter() { - @Override - public synchronized String format(java.util.logging.LogRecord pRecord) { - String color = pColorProvider.getColor(pRecord.getLevel()); - return color + pRecord.getLevel().getName() + pRecord.getMessage() + RESET + "\n"; + @Override + public synchronized String format(LogRecord pRecord) { + String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + StringBuilder coloredMessage = new StringBuilder(pColorProvider.getColor(pRecord.getLevel()) + timestamp + " [" + pRecord.getLevel() + "] " + pRecord.getMessage()); + + if (pRecord.getThrown() != null) { + coloredMessage.append("\nException: ").append(pRecord.getThrown().getMessage()); + for (StackTraceElement element : pRecord.getThrown().getStackTrace()) { + coloredMessage.append("\n\tat ").append(element.toString()); + } + } + + coloredMessage.append(RESET); + return coloredMessage + "\n"; } }); + pLogger.setUseParentHandlers(false); pLogger.addHandler(handler); } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java index 960ffb9e..51eaaca8 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java @@ -39,7 +39,7 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { double discriminant = pB * pB - 4 * pA * pC; if (discriminant < 0) { - BaseLogger.logWarning("No real roots found for the quadratic equation."); + BaseLogger.log("No real roots found for the quadratic equation."); return new double[0]; } @@ -47,7 +47,7 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { double root1 = (-pB + sqrtDiscriminant) / (2 * pA); double root2 = (-pB - sqrtDiscriminant) / (2 * pA); - BaseLogger.bluelibLogInfo("Roots found: root1=" + root1 + ", root2=" + root2); + BaseLogger.log("Roots found: root1=" + root1 + ", root2=" + root2); return new double[] { root1, root2 }; } @@ -63,7 +63,7 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { public static long factorial(int pNumber) { if (pNumber < 0) { IllegalArgumentException exception = new IllegalArgumentException("Number must be non-negative."); - BaseLogger.logError("Attempted to calculate factorial of a negative number: " + pNumber, exception); + BaseLogger.log("Attempted to calculate factorial of a negative number: " + pNumber, exception); throw exception; } @@ -72,7 +72,7 @@ public static long factorial(int pNumber) { result *= i; } - BaseLogger.bluelibLogInfo("Factorial of " + pNumber + " is " + result); + BaseLogger.log("Factorial of " + pNumber + " is " + result); return result; } @@ -93,7 +93,7 @@ public static int calculateGCD(int pA, int pB) { pA = temp; } - BaseLogger.bluelibLogInfo("GCD found: " + pA); + BaseLogger.log("GCD found: " + pA); return pA; } @@ -120,7 +120,7 @@ public static List> generatePowerSet(Set pSet) { powerSet.addAll(newSubsets); } - BaseLogger.bluelibLogInfo("Power set generated with " + powerSet.size() + " subsets."); + BaseLogger.log("Power set generated with " + powerSet.size() + " subsets."); return powerSet; } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java index 2c5560f3..263c3326 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java @@ -75,7 +75,7 @@ public static double calculateDistance3D(double pX1, double pY1, double pZ1, dou public static double calculateCircleArea(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.logError("Error calculating circle area", throwable); + BaseLogger.log("Error calculating circle area", throwable); return Double.NaN; } return Math.PI * pRadius * pRadius; @@ -92,7 +92,7 @@ public static double calculateCircleArea(double pRadius) { public static double calculateCircleCircumference(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.logError("Error calculating circle circumference", throwable); + BaseLogger.log("Error calculating circle circumference", throwable); return Double.NaN; } return 2 * Math.PI * pRadius; @@ -110,7 +110,7 @@ public static double calculateCircleCircumference(double pRadius) { public static double calculateRectangleArea(double pWidth, double pHeight) { if (pWidth < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Width and height must be non-negative."); - BaseLogger.logError("Error calculating rectangle area", throwable); + BaseLogger.log("Error calculating rectangle area", throwable); return Double.NaN; } return pWidth * pHeight; @@ -128,7 +128,7 @@ public static double calculateRectangleArea(double pWidth, double pHeight) { public static double calculateRectanglePerimeter(double pWidth, double pHeight) { if (pWidth < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Width and height must be non-negative."); - BaseLogger.logError("Error calculating rectangle perimeter", throwable); + BaseLogger.log("Error calculating rectangle perimeter", throwable); return Double.NaN; } return 2 * (pWidth + pHeight); @@ -145,7 +145,7 @@ public static double calculateRectanglePerimeter(double pWidth, double pHeight) public static double calculateTriangleArea(double pBase, double pHeight) { if (pBase < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Base and height must be non-negative."); - BaseLogger.logError("Error calculating triangle area", throwable); + BaseLogger.log("Error calculating triangle area", throwable); return Double.NaN; } return 0.5 * pBase * pHeight; @@ -163,7 +163,7 @@ public static double calculateTriangleArea(double pBase, double pHeight) { public static double calculateTrianglePerimeter(double pSide1, double pSide2, double pSide3) { if (pSide1 < 0 || pSide2 < 0 || pSide3 < 0) { Throwable throwable = new IllegalArgumentException("Sides must be non-negative."); - BaseLogger.logError("Error calculating triangle perimeter", throwable); + BaseLogger.log("Error calculating triangle perimeter", throwable); return Double.NaN; } return pSide1 + pSide2 + pSide3; @@ -180,7 +180,7 @@ public static double calculateTrianglePerimeter(double pSide1, double pSide2, do public static double calculateSphereVolume(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.logError("Error calculating sphere volume", throwable); + BaseLogger.log("Error calculating sphere volume", throwable); return Double.NaN; } return (4.0 / 3.0) * Math.PI * Math.pow(pRadius, 3); @@ -197,7 +197,7 @@ public static double calculateSphereVolume(double pRadius) { public static double calculateCubeSurfaceArea(double pSideLength) { if (pSideLength < 0) { Throwable throwable = new IllegalArgumentException("Side length must be non-negative."); - BaseLogger.logError("Error calculating cube surface area", throwable); + BaseLogger.log("Error calculating cube surface area", throwable); return Double.NaN; } return 6 * Math.pow(pSideLength, 2); @@ -215,7 +215,7 @@ public static double calculateCubeSurfaceArea(double pSideLength) { public static double calculateCylinderVolume(double pRadius, double pHeight) { if (pRadius < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Radius and height must be non-negative."); - BaseLogger.logError("Error calculating cylinder volume", throwable); + BaseLogger.log("Error calculating cylinder volume", throwable); return Double.NaN; } return Math.PI * Math.pow(pRadius, 2) * pHeight; @@ -233,7 +233,7 @@ public static double calculateCylinderVolume(double pRadius, double pHeight) { public static double calculateConeSurfaceArea(double pRadius, double pSlantHeight) { if (pRadius < 0 || pSlantHeight < 0) { Throwable throwable = new IllegalArgumentException("Radius and slant height must be non-negative."); - BaseLogger.logError("Error calculating cone surface area", throwable); + BaseLogger.log("Error calculating cone surface area", throwable); return Double.NaN; } return Math.PI * pRadius * (pRadius + pSlantHeight); diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java index 974782d9..d2159294 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java @@ -35,7 +35,7 @@ public static double[][] multiplyMatrices(double[][] pMatrixA, double[][] pMatri int colsB = pMatrixB[0].length; if (colsA != pMatrixB.length) { Throwable throwable = new IllegalArgumentException("Number of columns in the first matrix must be equal to the number of rows in the second matrix."); - BaseLogger.logError("Error performing matrix multiplication", throwable); + BaseLogger.log("Error performing matrix multiplication", throwable); return new double[0][0]; } double[][] result = new double[rowsA][colsB]; @@ -81,7 +81,7 @@ public static double[][] transposeMatrix(double[][] pMatrix) { public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { if (pMatrix.length != 2 || pMatrix[0].length != 2) { Throwable throwable = new IllegalArgumentException("Matrix must be 2x2."); - BaseLogger.logError("Error calculating 2x2 matrix determinant", throwable); + BaseLogger.log("Error calculating 2x2 matrix determinant", throwable); return Double.NaN; } return pMatrix[0][0] * pMatrix[1][1] - pMatrix[0][1] * pMatrix[1][0]; @@ -99,13 +99,13 @@ public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { public static double[][] invert2x2Matrix(double[][] pMatrix) { if (pMatrix.length != 2 || pMatrix[0].length != 2) { Throwable throwable = new IllegalArgumentException("Matrix must be 2x2."); - BaseLogger.logError("Error inverting 2x2 matrix", throwable); + BaseLogger.log("Error inverting 2x2 matrix", throwable); return new double[0][0]; } double determinant = calculate2x2MatrixDeterminant(pMatrix); if (determinant == 0) { Throwable throwable = new IllegalArgumentException("Matrix is not invertible."); - BaseLogger.logError("Error inverting 2x2 matrix", throwable); + BaseLogger.log("Error inverting 2x2 matrix", throwable); return new double[0][0]; } double[][] inverse = new double[2][2]; diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java index 625fb336..687aea68 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java @@ -45,7 +45,7 @@ public static int stringToIntWithDefault(String pString, int pDefaultValue) { try { return Integer.parseInt(pString); } catch (NumberFormatException pException) { - BaseLogger.logError("Error converting string to integer", pException); + BaseLogger.log("Error converting string to integer", pException); return pDefaultValue; } } @@ -91,7 +91,7 @@ public static int calculateLevenshteinDistance(String pStr1, String pStr2) { public static int[] hexToRGB(String pHex) { if (pHex == null || pHex.isEmpty()) { Throwable throwable = new IllegalArgumentException("Hex color code cannot be null or empty."); - BaseLogger.logError("Error converting hex to RGB", throwable); + BaseLogger.log("Error converting hex to RGB", throwable); return new int[]{0, 0, 0}; } if (pHex.charAt(0) == '#') { @@ -99,7 +99,7 @@ public static int[] hexToRGB(String pHex) { } if (pHex.length() != 6) { Throwable throwable = new IllegalArgumentException("Invalid hex color code."); - BaseLogger.logError("Error converting hex to RGB", throwable); + BaseLogger.log("Error converting hex to RGB", throwable); return new int[]{0, 0, 0}; } try { @@ -108,7 +108,7 @@ public static int[] hexToRGB(String pHex) { int b = Integer.parseInt(pHex.substring(4, 6), 16); return new int[]{r, g, b}; } catch (NumberFormatException pException) { - BaseLogger.logError("Error parsing hex color code to RGB", pException); + BaseLogger.log("Error parsing hex color code to RGB", pException); return new int[]{0, 0, 0}; } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java index bd82e335..cb8316ba 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java @@ -43,7 +43,7 @@ public class RandomGenUtils { public static int generateRandomInt(int pMin, int pMax) { if (pMin > pMax) { Throwable throwable = new IllegalArgumentException("Minimum value must not be greater than maximum value."); - BaseLogger.logError("Error generating random integer", throwable); + BaseLogger.log("Error generating random integer", throwable); return 0; } return pMin + (int)(Math.random() * (pMax - pMin + 1)); @@ -61,7 +61,7 @@ public static int generateRandomInt(int pMin, int pMax) { public static double generateRandomDouble(double pMin, double pMax) { if (pMin > pMax) { Throwable throwable = new IllegalArgumentException("Minimum value must not be greater than maximum value."); - BaseLogger.logError("Error generating random double", throwable); + BaseLogger.log("Error generating random double", throwable); return 0; } return pMin + Math.random() * (pMax - pMin); @@ -90,7 +90,7 @@ public static boolean generateRandomBoolean() { public static String generateRandomString(int pLength) { if (pLength < 0) { Throwable throwable = new IllegalArgumentException("Length must be non-negative."); - BaseLogger.logError("Error generating random string", throwable); + BaseLogger.log("Error generating random string", throwable); return "unknown"; } String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -114,7 +114,7 @@ public static String generateRandomString(int pLength) { public static String generateRandomStringWithPrefix(String pPrefix, int pLength) { if (pLength < 0) { Throwable throwable = new IllegalArgumentException("Length must be non-negative."); - BaseLogger.logError("Error generating random string with prefix", throwable); + BaseLogger.log("Error generating random string with prefix", throwable); return "unknown"; } return pPrefix + generateRandomString(pLength - pPrefix.length()); diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java index bf1c5939..2f74eaa2 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java @@ -49,7 +49,7 @@ public class StatisticalUtils { */ public static double calculateMean(double[] pValues) { if (pValues.length == 0) { - BaseLogger.logWarning("Array is empty, mean calculation might fail."); + BaseLogger.log("Array is empty, mean calculation might fail."); return 0; } @@ -58,7 +58,7 @@ public static double calculateMean(double[] pValues) { sum += value; } double mean = sum / pValues.length; - BaseLogger.bluelibLogSuccess("Mean successfully calculated: " + mean); + BaseLogger.log("Mean successfully calculated: " + mean); return mean; } @@ -75,7 +75,7 @@ public static double calculateMean(double[] pValues) { */ public static double calculateMedian(double[] pValues) { if (pValues.length == 0) { - BaseLogger.logWarning("Array is empty, median calculation might fail."); + BaseLogger.log("Array is empty, median calculation might fail."); return 0; } @@ -86,7 +86,7 @@ public static double calculateMedian(double[] pValues) { (sorted[middle - 1] + sorted[middle]) / 2.0 : sorted[middle]; - BaseLogger.bluelibLogSuccess("Median successfully calculated: " + median); + BaseLogger.log("Median successfully calculated: " + median); return median; } @@ -103,7 +103,7 @@ public static double calculateMedian(double[] pValues) { */ public static double calculateMode(double[] pValues) { if (pValues.length == 0) { - BaseLogger.logWarning("Array is empty, mode calculation might fail."); + BaseLogger.log("Array is empty, mode calculation might fail."); return 0; } @@ -121,7 +121,7 @@ public static double calculateMode(double[] pValues) { } } - BaseLogger.bluelibLogSuccess("Mode successfully calculated: " + mode); + BaseLogger.log("Mode successfully calculated: " + mode); return mode; } @@ -138,7 +138,7 @@ public static double calculateMode(double[] pValues) { */ public static double calculateStandardDeviation(double[] pValues) { if (pValues.length == 0) { - BaseLogger.logWarning("Array is empty, standard deviation calculation might fail."); + BaseLogger.log("Array is empty, standard deviation calculation might fail."); return 0; } @@ -148,7 +148,7 @@ public static double calculateStandardDeviation(double[] pValues) { sumSquaredDifferences += Math.pow(value - mean, 2); } double stdDev = Math.sqrt(sumSquaredDifferences / pValues.length); - BaseLogger.bluelibLogSuccess("Standard deviation successfully calculated: " + stdDev); + BaseLogger.log("Standard deviation successfully calculated: " + stdDev); return stdDev; } @@ -165,7 +165,7 @@ public static double calculateStandardDeviation(double[] pValues) { */ public static double calculateVariance(double[] pValues) { if (pValues.length == 0) { - BaseLogger.logWarning("Array is empty, variance calculation might fail."); + BaseLogger.log("Array is empty, variance calculation might fail."); return 0; } @@ -175,7 +175,7 @@ public static double calculateVariance(double[] pValues) { sumSquaredDifferences += Math.pow(value - mean, 2); } double variance = sumSquaredDifferences / pValues.length; - BaseLogger.bluelibLogSuccess("Variance successfully calculated: " + variance); + BaseLogger.log("Variance successfully calculated: " + variance); return variance; } @@ -192,14 +192,14 @@ public static double calculateVariance(double[] pValues) { */ public static double calculateRange(double[] pValues) { if (pValues.length == 0) { - BaseLogger.logWarning("Array is empty, range calculation might fail."); + BaseLogger.log("Array is empty, range calculation might fail."); return 0; } double max = Arrays.stream(pValues).max().orElseThrow(); double min = Arrays.stream(pValues).min().orElseThrow(); double range = max - min; - BaseLogger.bluelibLogSuccess("Range successfully calculated: " + range); + BaseLogger.log("Range successfully calculated: " + range); return range; } @@ -216,14 +216,14 @@ public static double calculateRange(double[] pValues) { */ public static double calculateCoefficientOfVariation(double[] pValues) { if (pValues.length == 0) { - BaseLogger.logWarning("Array is empty, coefficient of variation calculation might fail."); + BaseLogger.log("Array is empty, coefficient of variation calculation might fail."); return 0; } double mean = calculateMean(pValues); double stdDev = calculateStandardDeviation(pValues); double coefficient = (stdDev / mean) * 100; - BaseLogger.bluelibLogSuccess("Coefficient of variation successfully calculated: " + coefficient); + BaseLogger.log("Coefficient of variation successfully calculated: " + coefficient); return coefficient; } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java b/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java index 5b7db46f..e84ba5ad 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java @@ -7,11 +7,9 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.status.ChunkStatus; import software.bluelib.utils.logging.BaseLogger; import java.util.Arrays; @@ -53,10 +51,10 @@ public class ChunkUtils { public static Biome getBiomeOfChunk(Level pLevel, ChunkPos pChunkPos) { try { Biome biome = pLevel.getBiome(pChunkPos.getWorldPosition()).value(); - BaseLogger.bluelibLogSuccess("Retrieved biome for chunk at position " + pChunkPos + ": " + biome); + BaseLogger.log("Retrieved biome for chunk at position " + pChunkPos + ": " + biome); return biome; } catch (Exception pException) { - BaseLogger.logError("Error retrieving biome for chunk at position " + pChunkPos, pException); + BaseLogger.log("Error retrieving biome for chunk at position " + pChunkPos, pException); throw pException; } } @@ -80,11 +78,11 @@ public static String getBiomeRegistryNameOfChunk(Level pLevel, ChunkPos pChunkPo if (biomeKey == null) { NullPointerException exception = new NullPointerException("Biome at chunk position " + pChunkPos + " is null"); - BaseLogger.logError("Error retrieving biome registry name of chunk at " + pChunkPos, exception); + BaseLogger.log("Error retrieving biome registry name of chunk at " + pChunkPos, exception); return "Biome at chunk position " + pChunkPos + " is null"; } - BaseLogger.bluelibLogSuccess("Retrieved biome registry name for chunk at position " + pChunkPos + ": " + biomeKey); + BaseLogger.log("Retrieved biome registry name for chunk at position " + pChunkPos + ": " + biomeKey); return biomeKey.toString(); } @@ -120,10 +118,10 @@ public static Collection getChunkTileEntities(Level pLevel, ChunkPo try { LevelChunk chunk = pLevel.getChunk(pChunkPos.x, pChunkPos.z); Collection tileEntities = chunk.getBlockEntities().values(); - BaseLogger.bluelibLogSuccess("Retrieved " + tileEntities.size() + " tile entities for chunk at position " + pChunkPos); + BaseLogger.log("Retrieved " + tileEntities.size() + " tile entities for chunk at position " + pChunkPos); return tileEntities; } catch (Exception pException) { - BaseLogger.logError("Error retrieving tile entities for chunk at position " + pChunkPos, pException); + BaseLogger.log("Error retrieving tile entities for chunk at position " + pChunkPos, pException); throw pException; } } @@ -153,10 +151,10 @@ public static String getChunkTileEntitiesRegistryNames(Level pLevel, ChunkPos pC }) .collect(Collectors.joining(", ")); - BaseLogger.bluelibLogSuccess("Tile entities for chunk at position " + pChunkPos + ": " + registryNames); + BaseLogger.log("Tile entities for chunk at position " + pChunkPos + ": " + registryNames); return registryNames; } catch (Exception pException) { - BaseLogger.logError("Error retrieving tile entity registry names for chunk at position " + pChunkPos, pException); + BaseLogger.log("Error retrieving tile entity registry names for chunk at position " + pChunkPos, pException); throw pException; } } @@ -207,10 +205,10 @@ public static int getChunkBlockCount(Level pLevel, ChunkPos pChunkPos) { } } - BaseLogger.bluelibLogSuccess("Non-air block count for chunk at position " + pChunkPos + ": " + blockCount); + BaseLogger.log("Non-air block count for chunk at position " + pChunkPos + ": " + blockCount); return blockCount; } catch (Exception pException) { - BaseLogger.logError("Error counting blocks for chunk at position " + pChunkPos, pException); + BaseLogger.log("Error counting blocks for chunk at position " + pChunkPos, pException); throw pException; } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java b/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java index d7c2c38b..03a1f079 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java @@ -178,7 +178,7 @@ public ParameterBuilder connect() { } else { Throwable cause = new Throwable("Variant or entity not found in the database"); NoSuchElementException exception = new NoSuchElementException("Variant '" + variantName + "' not found for entity '" + entityName + "'", cause); - BaseLogger.logError(exception.getMessage(), exception); + BaseLogger.log(exception.getMessage(), exception); } return this; } From f123d991f1cf04f61faaae58bf454459d6bab537 Mon Sep 17 00:00:00 2001 From: Aram Date: Fri, 27 Sep 2024 18:01:14 +0200 Subject: [PATCH 24/62] Created a Mixin Lowered the Files the Mod Owners need to use to create the Variant Loader --- .../main/java/software/bluelib/BlueLib.java | 4 + .../example/entity/dragon/DragonEntity.java | 85 ++---------------- .../bluelib/example/entity/rex/RexEntity.java | 89 ++----------------- .../interfaces/variant/IVariantAccessor.java | 7 ++ .../mixin/variant/LivingEntityMixin.java | 59 ++++++++++++ .../resources/META-INF/neoforge.mods.toml | 5 +- .../src/main/resources/bluelib.mixins.json | 14 +++ 7 files changed, 101 insertions(+), 162 deletions(-) create mode 100644 NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java create mode 100644 NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java create mode 100644 NeoForge/src/main/resources/bluelib.mixins.json diff --git a/NeoForge/src/main/java/software/bluelib/BlueLib.java b/NeoForge/src/main/java/software/bluelib/BlueLib.java index a2a53040..a834bef5 100644 --- a/NeoForge/src/main/java/software/bluelib/BlueLib.java +++ b/NeoForge/src/main/java/software/bluelib/BlueLib.java @@ -8,6 +8,9 @@ import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLLoadCompleteEvent; import net.neoforged.fml.loading.FMLEnvironment; +import org.spongepowered.asm.launch.MixinBootstrap; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.MixinEnvironment; import software.bluelib.example.event.ClientEvents; import software.bluelib.example.init.ModEntities; import software.bluelib.utils.logging.BaseLogLevel; @@ -72,6 +75,7 @@ public class BlueLib { */ public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { pModEventBus.register(this); + MixinBootstrap.init(); if (isDeveloperMode()) { ModEntities.REGISTRY.register(pModEventBus); if (FMLEnvironment.dist.isClient()) { diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 67c62890..3e48e535 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -3,8 +3,6 @@ package software.bluelib.example.entity.dragon; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.syncher.EntityDataAccessor; -import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; @@ -20,6 +18,7 @@ import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.util.GeckoLibUtil; +import software.bluelib.interfaces.variant.IVariantAccessor; import software.bluelib.interfaces.variant.IVariantEntity; import software.bluelib.utils.logging.BaseLogger; import software.bluelib.utils.variant.ParameterUtils; @@ -39,8 +38,6 @@ *
        • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
        • *
        • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
        • *
        • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
        • - *
        • {@link #setVariantName(String)} - Sets the variant name of the dragon.
        • - *
        • {@link #getVariantName()} - Retrieves the current variant name of the dragon.
        • * *

          * @@ -80,56 +77,12 @@ public DragonEntity(EntityType pEntityType, Level pLeve super(pEntityType, pLevel); } - /** - * Defines the synchronized data for this dragon entity, including the variant. - *

          - * This method initializes the {@link EntityDataAccessor} to handle the variant data. - *

          - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder) { - super.defineSynchedData(pBuilder); - pBuilder.define(VARIANT, "normal"); - } - - /** - * Adds custom data to the entity's NBT tag for saving. - *

          - * This method stores the variant name in the NBT data so it can be restored when loading the entity. - *

          - * - * @param pCompound {@link CompoundTag} - The NBT tag to which data should be added. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public void addAdditionalSaveData(@NotNull CompoundTag pCompound) { - super.addAdditionalSaveData(pCompound); - pCompound.putString("Variant", getVariantName()); + public void setVariantName(String pVariantName) { + ((IVariantAccessor) this).setEntityVariantName(pVariantName); } - /** - * Reads custom data from the entity's NBT tag for loading. - *

          - * This method retrieves the variant name from the NBT data and sets it for the entity. - *

          - * - * @param pCompound {@link CompoundTag} - The NBT tag from which data should be read. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { - super.readAdditionalSaveData(pCompound); - this.setVariantName(pCompound.getString("Variant")); + public String getVariantName() { + return ((IVariantAccessor) this).getEntityVariantName(); } /** @@ -151,7 +104,7 @@ public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { @Override public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { if (getVariantName() == null || getVariantName().isEmpty()) { - this.setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); + setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); ParameterUtils.ParameterBuilder.forVariant(entityName,this.getVariantName()) .withParameter("customParameter") .withParameter("int") @@ -163,31 +116,9 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } - /** - * Sets the variant name for the dragon entity. - * - * @param pName {@link String} - The name of the variant to set. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public void setVariantName(String pName) { - this.entityData.set(VARIANT, pName); - } - /** - * Retrieves the current variant name of the dragon entity. - * - * @return {@link String} - The current variant name. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public String getVariantName() { - return this.entityData.get(VARIANT); - } + + /** * All Code below this Fragment is not Library Related!!! diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index bacb1762..37d48f57 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -20,6 +20,7 @@ import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.animation.AnimatableManager; import software.bernie.geckolib.util.GeckoLibUtil; +import software.bluelib.interfaces.variant.IVariantAccessor; import software.bluelib.interfaces.variant.IVariantEntity; import software.bluelib.utils.variant.ParameterUtils; @@ -48,16 +49,6 @@ * @since 1.0.0 */ public class RexEntity extends TamableAnimal implements IVariantEntity, GeoEntity { - /** - * Entity data accessor for the variant of the Rex. - *

          - * This is used to store and retrieve the variant data for synchronization between server and client. - *

          - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - public static final EntityDataAccessor VARIANT = SynchedEntityData.defineId(RexEntity.class, EntityDataSerializers.STRING); - /** * The name of the entity. * @Co-author MeAlam, Dan @@ -79,56 +70,12 @@ public RexEntity(EntityType pEntityType, Level pLevel) super(pEntityType, pLevel); } - /** - * Defines the synchronized data for this Rex entity, including the variant. - *

          - * This method initializes the {@link EntityDataAccessor} to handle the variant data. - *

          - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder) { - super.defineSynchedData(pBuilder); - pBuilder.define(VARIANT, "normal"); - } - - /** - * Adds custom data to the entity's NBT tag for saving. - *

          - * This method stores the variant name in the NBT data so it can be restored when loading the entity. - *

          - * - * @param pCompound {@link CompoundTag} - The NBT tag to which data should be added. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public void addAdditionalSaveData(@NotNull CompoundTag pCompound) { - super.addAdditionalSaveData(pCompound); - pCompound.putString("Variant", getVariantName()); + public void setVariantName(String pVariantName) { + ((IVariantAccessor) this).setEntityVariantName(pVariantName); } - /** - * Reads custom data from the entity's NBT tag for loading. - *

          - * This method retrieves the variant name from the NBT data and sets it for the entity. - *

          - * - * @param pCompound {@link CompoundTag} - The NBT tag from which data should be read. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { - super.readAdditionalSaveData(pCompound); - this.setVariantName(pCompound.getString("Variant")); + public String getVariantName() { + return ((IVariantAccessor) this).getEntityVariantName(); } /** @@ -161,32 +108,6 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } - /** - * Sets the variant name for the Rex entity. - * - * @param pName {@link String} - The name of the variant to set. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public void setVariantName(String pName) { - this.entityData.set(VARIANT, pName); - } - - /** - * Retrieves the current variant name of the Rex entity. - * - * @return {@link String} - The current variant name. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public String getVariantName() { - return this.entityData.get(VARIANT); - } - /** * All Code below this Fragment is not Library Related!!! */ diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java new file mode 100644 index 00000000..bd4a4579 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java @@ -0,0 +1,7 @@ +package software.bluelib.interfaces.variant; + +public interface IVariantAccessor { + void setEntityVariantName(String pVariantName); + String getEntityVariantName(); +} + diff --git a/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java b/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java new file mode 100644 index 00000000..afb65d3c --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java @@ -0,0 +1,59 @@ +package software.bluelib.mixin.variant; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import software.bluelib.interfaces.variant.IVariantAccessor; + +@Mixin(LivingEntity.class) +public class LivingEntityMixin implements IVariantAccessor { + + @Unique + private static final EntityDataAccessor bluelib$VARIANT = + SynchedEntityData.defineId(LivingEntity.class, EntityDataSerializers.STRING); + + @Inject(method = "defineSynchedData", at = @At("HEAD")) + protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder, CallbackInfo pCi) { + pBuilder.define(bluelib$VARIANT, "normal"); + } + + @Inject(method = "addAdditionalSaveData", at = @At("HEAD")) + public void addAdditionalSaveData(@NotNull CompoundTag pCompound, CallbackInfo pCi) { + pCompound.putString("Variant", bluelib$getVariantName()); + } + + @Inject(method = "readAdditionalSaveData", at = @At("HEAD")) + public void readAdditionalSaveData(@NotNull CompoundTag pCompound, CallbackInfo pCi) { + bluelib$setVariantName(pCompound.getString("Variant")); + } + + @Unique + public void bluelib$setVariantName(String pName) { + ((Entity) (Object) this).getEntityData().set(bluelib$VARIANT, pName); + } + + @Unique + public String bluelib$getVariantName() { + return ((Entity) (Object) this).getEntityData().get(bluelib$VARIANT); + } + + @Override + public void setEntityVariantName(String pVariantName) { + bluelib$setVariantName(pVariantName); + } + + @Override + public String getEntityVariantName() { + return bluelib$getVariantName(); + } +} + diff --git a/NeoForge/src/main/resources/META-INF/neoforge.mods.toml b/NeoForge/src/main/resources/META-INF/neoforge.mods.toml index 711284af..ab68e198 100644 --- a/NeoForge/src/main/resources/META-INF/neoforge.mods.toml +++ b/NeoForge/src/main/resources/META-INF/neoforge.mods.toml @@ -28,4 +28,7 @@ description='''${mod_description}''' type="required" versionRange="${minecraft_version_range}" ordering="NONE" - side="BOTH" \ No newline at end of file + side="BOTH" + +[[mixins]] +config = "bluelib.mixins.json" \ No newline at end of file diff --git a/NeoForge/src/main/resources/bluelib.mixins.json b/NeoForge/src/main/resources/bluelib.mixins.json new file mode 100644 index 00000000..2b7ba604 --- /dev/null +++ b/NeoForge/src/main/resources/bluelib.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8.0", + "package": "software.bluelib.mixin", + "refmap": "bluelib.refmap.json", + "mixins": [ + "variant.LivingEntityMixin" + ], + "client": [], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} From 4f2b1643892a18a5c7f74957f5742a4836430624 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 30 Sep 2024 22:11:29 +0200 Subject: [PATCH 25/62] Fixed all Comments --- .../bluelib/entity/variant/VariantLoader.java | 21 +++++++------ .../entity/variant/VariantParameter.java | 25 ++++++++------- .../bluelib/event/ReloadEventHandler.java | 9 +++--- .../example/entity/dragon/DragonEntity.java | 13 ++------ .../interfaces/variant/IVariantEntity.java | 5 +-- .../variant/base/IVariantEntityBase.java | 3 +- .../software/bluelib/json/JSONLoader.java | 9 +++--- .../software/bluelib/json/JSONMerger.java | 11 ++++--- .../utils/conversion/CaseConverterUtils.java | 31 ++++++++++--------- .../utils/conversion/MathConverterUtils.java | 6 ++-- .../bluelib/utils/logging/BaseLogLevel.java | 10 +++--- .../bluelib/utils/logging/LoggerConfig.java | 4 +-- .../bluelib/utils/math/AlgebraicUtils.java | 13 ++++---- .../bluelib/utils/math/GeometricUtils.java | 21 +++++++------ .../bluelib/utils/math/MatrixUtils.java | 9 +++--- .../bluelib/utils/math/MiscUtils.java | 9 +++--- .../bluelib/utils/math/RandomGenUtils.java | 9 +++--- .../bluelib/utils/math/StatisticalUtils.java | 29 ++++++++--------- .../bluelib/utils/minecraft/ChunkUtils.java | 23 +++++++------- .../bluelib/utils/variant/ParameterUtils.java | 4 +-- 20 files changed, 136 insertions(+), 128 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java index 1126248f..dd08fd8b 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -11,6 +11,7 @@ import software.bluelib.interfaces.variant.base.IVariantEntityBase; import software.bluelib.json.JSONLoader; import software.bluelib.json.JSONMerger; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.util.*; @@ -76,7 +77,7 @@ public class VariantLoader implements IVariantEntityBase { * @param pEntityName {@link String} - The name of the entity whose variants should be cleared before loading new ones. */ public static void loadVariants(String folderPath, MinecraftServer pServer, String pEntityName) { - BaseLogger.log("Starting to load variants for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO,"Starting to load variants for entity: " + pEntityName); clearVariantsForEntity(pEntityName); @@ -85,19 +86,19 @@ public static void loadVariants(String folderPath, MinecraftServer pServer, Stri Collection collection = resourceManager.listResources(folderPath, pFiles -> pFiles.getPath().endsWith(".json")).keySet(); - BaseLogger.log("Found resources: " + collection); + BaseLogger.log(BaseLogLevel.INFO,"Found resources: " + collection); for (ResourceLocation resourceLocation : collection) { try { - BaseLogger.log("Loading JSON data from resource: " + resourceLocation.toString()); + BaseLogger.log(BaseLogLevel.INFO,"Loading JSON data from resource: " + resourceLocation.toString()); JsonObject jsonObject = jsonLoader.loadJson(resourceLocation, resourceManager); jsonMerger.mergeJsonObjects(mergedJsonObject, jsonObject); } catch (Exception pException) { - BaseLogger.log("Failed to load JSON data from resource: " + resourceLocation.toString(), pException); + BaseLogger.log(BaseLogLevel.ERROR,"Failed to load JSON data from resource: " + resourceLocation.toString(), pException); } } - BaseLogger.log("Successfully loaded and merged JSON data for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO,"Successfully loaded and merged JSON data for entity: " + pEntityName); parseVariants(mergedJsonObject); } @@ -109,7 +110,7 @@ public static void loadVariants(String folderPath, MinecraftServer pServer, Stri * @param pEntityName {@link String} - The name of the entity whose variants should be cleared. */ private static void clearVariantsForEntity(String pEntityName) { - BaseLogger.log("Clearing variants for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO,"Clearing variants for entity: " + pEntityName); entityVariantsMap.remove(pEntityName); } @@ -125,7 +126,7 @@ private static void parseVariants(JsonObject pJsonObject) { String entityName = entry.getKey(); JsonArray textureArray = entry.getValue().getAsJsonArray(); - BaseLogger.log("Parsing variants for entity: " + entityName); + BaseLogger.log(BaseLogLevel.INFO,"Parsing variants for entity: " + entityName); List variantList = entityVariantsMap.computeIfAbsent(entityName, k -> new ArrayList<>()); for (JsonElement variant : textureArray) { @@ -163,7 +164,7 @@ private static VariantParameter getEntityVariant(String pJsonKey, JsonObject pJs * @return {@link List} - A {@link List} of {@link VariantParameter} instances for the specified entity. */ public static List getVariantsFromEntity(String pEntityName) { - BaseLogger.log("Retrieving variants for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO,"Retrieving variants for entity: " + pEntityName); return entityVariantsMap.getOrDefault(pEntityName, new ArrayList<>()); } @@ -177,14 +178,14 @@ public static List getVariantsFromEntity(String pEntityName) { * @return {@link VariantParameter} - The {@link VariantParameter} with the specified name, or {@code null} if not found. */ public static VariantParameter getVariantByName(String pEntityName, String pVariantName) { - BaseLogger.log("Retrieving variant by name: " + pVariantName + " for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO,"Retrieving variant by name: " + pVariantName + " for entity: " + pEntityName); List variants = getVariantsFromEntity(pEntityName); for (VariantParameter variant : variants) { if (variant.getVariantName().equals(pVariantName)) { return variant; } } - BaseLogger.log("Variant with name: " + pVariantName + " not found for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO,"Variant with name: " + pVariantName + " not found for entity: " + pEntityName); return null; } } diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java index a3c1565f..fce2f18d 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java @@ -5,6 +5,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import software.bluelib.entity.variant.base.ParameterBase; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.util.Map; @@ -62,31 +63,31 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { if (pJsonKey == null || pJsonObject == null) { Throwable throwable = new Throwable("JSON key or JSON object is null"); IllegalArgumentException exception = new IllegalArgumentException("JSON key and object must not be null"); - BaseLogger.log(exception.toString(), throwable); + BaseLogger.log(BaseLogLevel.ERROR,exception.toString(), throwable); throw exception; } this.jsonKey = pJsonKey; - BaseLogger.log("Creating VariantParameter with JSON key: " + pJsonKey); + BaseLogger.log(BaseLogLevel.INFO,"Creating VariantParameter with JSON key: " + pJsonKey); Set> entryMap = pJsonObject.entrySet(); for (Map.Entry entry : entryMap) { JsonElement element = entry.getValue(); if (element.isJsonPrimitive()) { addParameter(entry.getKey(), element.getAsString()); - BaseLogger.log("Added primitive parameter: " + entry.getKey() + " = " + element.getAsString()); + BaseLogger.log(BaseLogLevel.SUCCESS,"Added primitive parameter: " + entry.getKey() + " = " + element.getAsString()); } else if (element.isJsonArray()) { StringBuilder arrayValues = new StringBuilder(); element.getAsJsonArray().forEach(e -> arrayValues.append(e.getAsString()).append(",")); - if (arrayValues.length() > 0) { - arrayValues.setLength(arrayValues.length() - 1); // Remove trailing comma + if (!arrayValues.isEmpty()) { + arrayValues.setLength(arrayValues.length() - 1); } addParameter(entry.getKey(), arrayValues.toString()); - BaseLogger.log("Added array parameter: " + entry.getKey() + " = " + arrayValues.toString()); + BaseLogger.log(BaseLogLevel.SUCCESS,"Added array parameter: " + entry.getKey() + " = " + arrayValues.toString()); } else if (element.isJsonObject()) { addParameter(entry.getKey(), element.toString()); - BaseLogger.log("Added object parameter: " + entry.getKey() + " = " + element.toString()); + BaseLogger.log(BaseLogLevel.SUCCESS,"Added object parameter: " + entry.getKey() + " = " + element.toString()); } else { addParameter(entry.getKey(), "null"); - BaseLogger.log("Added null parameter for key: " + entry.getKey()); + BaseLogger.log(BaseLogLevel.SUCCESS,"Added null parameter for key: " + entry.getKey()); } } } @@ -106,10 +107,10 @@ public String getJsonKey() { if (this.jsonKey == null) { Throwable throwable = new Throwable("JSON key should not be null"); IllegalStateException exception = new IllegalStateException("JSON key is unexpectedly null when retrieving from VariantParameter."); - BaseLogger.log(exception.toString(), throwable); + BaseLogger.log(BaseLogLevel.ERROR, "JSON key is unexpectedly null when retrieving from VariantParameter.", throwable); throw exception; } - BaseLogger.log("Retrieved JSON key: " + this.jsonKey); + BaseLogger.log(BaseLogLevel.INFO,"Retrieved JSON key: " + this.jsonKey); return this.jsonKey; } @@ -125,7 +126,7 @@ public String getJsonKey() { */ public String getVariantName() { String variantName = getParameter("variantName"); - BaseLogger.log("Retrieved variant name: " + variantName); + BaseLogger.log(BaseLogLevel.INFO,"Retrieved variant name: " + variantName); return variantName; } @@ -142,7 +143,7 @@ public String getVariantName() { */ public String getParameter(String pKey) { String value = (String) super.getParameter(pKey); - BaseLogger.log("Retrieved parameter for key " + pKey + ": " + value); + BaseLogger.log(BaseLogLevel.INFO,"Retrieved parameter for key " + pKey + ": " + value); return value; } } diff --git a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java index c2c936e2..6ba0a893 100644 --- a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -6,6 +6,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import software.bluelib.entity.variant.VariantLoader; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; /** @@ -65,16 +66,16 @@ public class ReloadEventHandler { */ protected static void registerEntityVariants(String pFolderPath, MinecraftServer pServer, String pModID, String pEntityName) { - BaseLogger.log("Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID); + BaseLogger.log(BaseLogLevel.INFO,"Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID); try { VariantLoader.loadVariants(pFolderPath, pServer, pEntityName); - BaseLogger.log("Successfully registered entity variants for " + pEntityName + " from ModID: " + pModID); + BaseLogger.log(BaseLogLevel.SUCCESS,"Successfully registered entity variants for " + pEntityName + " from ModID: " + pModID); } catch (JsonParseException pException) { - BaseLogger.log("Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); + BaseLogger.log(BaseLogLevel.ERROR,"Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); throw pException; } catch (Exception pException) { - BaseLogger.log("Unexpected error occurred while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); + BaseLogger.log(BaseLogLevel.ERROR,"Unexpected error occurred while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); throw pException; } } diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 3e48e535..0c3b6240 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -20,6 +20,7 @@ import software.bernie.geckolib.util.GeckoLibUtil; import software.bluelib.interfaces.variant.IVariantAccessor; import software.bluelib.interfaces.variant.IVariantEntity; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import software.bluelib.utils.variant.ParameterUtils; @@ -46,16 +47,6 @@ * @since 1.0.0 */ public class DragonEntity extends TamableAnimal implements IVariantEntity, GeoEntity { - /** - * Entity data accessor for the variant of the dragon. - *

          - * This is used to store and retrieve the variant data for synchronization between server and client. - *

          - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - public static final EntityDataAccessor VARIANT = SynchedEntityData.defineId(DragonEntity.class, EntityDataSerializers.STRING); - /** * The name of the entity. * @Co-author MeAlam, Dan @@ -112,7 +103,7 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul .withParameter("array") .connect(); } - BaseLogger.log("Dragon Spawned with Variant: " + getVariantName()); + BaseLogger.log(BaseLogLevel.SUCCESS,"Dragon Spawned with Variant: " + getVariantName()); return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java index 65364163..97c50daa 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java @@ -4,6 +4,7 @@ import net.minecraft.util.RandomSource; import software.bluelib.interfaces.variant.base.IVariantEntityBase; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.util.List; @@ -49,12 +50,12 @@ public interface IVariantEntity extends IVariantEntityBase { */ default String getRandomVariant(List pVariantNamesList, String pDefaultVariant) { if (pVariantNamesList.isEmpty()) { - BaseLogger.log("Variant names list is empty. Returning default variant: " + pDefaultVariant); + BaseLogger.log(BaseLogLevel.INFO,"Variant names list is empty. Returning default variant: " + pDefaultVariant); return pDefaultVariant; } int index = random.nextInt(pVariantNamesList.size()); String selectedVariant = pVariantNamesList.get(index); - BaseLogger.log("Selected random variant: " + selectedVariant + " from list of size: " + pVariantNamesList.size()); + BaseLogger.log(BaseLogLevel.SUCCESS,"Selected random variant: " + selectedVariant + " from list of size: " + pVariantNamesList.size()); return selectedVariant; } } diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index 991a8184..46c9ca2a 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -5,6 +5,7 @@ import net.minecraft.resources.ResourceLocation; import software.bluelib.entity.variant.VariantLoader; import software.bluelib.entity.variant.VariantParameter; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.util.List; @@ -62,7 +63,7 @@ default List getEntityVariants(String pEntityName) { List variantNames = variants.stream() .map(VariantParameter::getVariantName) .collect(Collectors.toList()); - BaseLogger.log("Retrieved " + variantNames.size() + " variants for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.SUCCESS,"Retrieved " + variantNames.size() + " variants for entity: " + pEntityName); return variantNames; } } diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java b/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java index 697924ec..55569689 100644 --- a/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java +++ b/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java @@ -7,6 +7,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.io.IOException; @@ -50,13 +51,13 @@ public class JSONLoader { * @since 1.0.0 */ public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager pResourceManager) { - BaseLogger.log("Attempting to load JSON resource: " + pResourceLocation); + BaseLogger.log(BaseLogLevel.INFO,"Attempting to load JSON resource: " + pResourceLocation); try { Optional resource = pResourceManager.getResource(pResourceLocation); if (resource.isEmpty()) { - BaseLogger.log("Resource not found: " + pResourceLocation); + BaseLogger.log(BaseLogLevel.ERROR,"Resource not found: " + pResourceLocation); return new JsonObject(); } @@ -64,12 +65,12 @@ public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager p InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { JsonObject jsonObject = gson.fromJson(reader, JsonObject.class); - BaseLogger.log("Successfully loaded JSON resource: " + pResourceLocation); + BaseLogger.log(BaseLogLevel.SUCCESS,"Successfully loaded JSON resource: " + pResourceLocation); return jsonObject; } } catch (IOException pException) { RuntimeException exception = new RuntimeException("Failed to load JSON resource: " + pResourceLocation, pException); - BaseLogger.log("Failed to load JSON resource: " + pResourceLocation, exception); + BaseLogger.log(BaseLogLevel.ERROR,"Failed to load JSON resource: " + pResourceLocation, exception); throw exception; } } diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java b/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java index 7291d942..d2518b0c 100644 --- a/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java +++ b/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java @@ -5,6 +5,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.util.Map; @@ -39,7 +40,7 @@ public class JSONMerger { * @param pSource {@link JsonObject} - The source {@link JsonObject} to merge data from. This object is not modified by the operation. */ public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { - BaseLogger.log("Starting JSON merge operation."); + BaseLogger.log(BaseLogLevel.INFO,"Starting JSON merge operation."); for (Map.Entry entry : pSource.entrySet()) { String key = entry.getKey(); @@ -56,17 +57,17 @@ public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { targetArray.add(element); } - BaseLogger.log("Merged array for key: " + key); + BaseLogger.log(BaseLogLevel.ERROR,"Merged array for key: " + key); } else { pTarget.add(key, sourceElement); - BaseLogger.log("Overwriting value for key: " + key); + BaseLogger.log(BaseLogLevel.WARNING,"Overwriting value for key: " + key); } } else { pTarget.add(key, sourceElement); - BaseLogger.log("Adding new key: " + key); + BaseLogger.log(BaseLogLevel.SUCCESS,"Added new key: " + key); } } - BaseLogger.log("JSON merge operation completed."); + BaseLogger.log(BaseLogLevel.SUCCESS,"JSON merge operation completed."); } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java b/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java index 2e9d6438..df767a73 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java @@ -2,6 +2,7 @@ package software.bluelib.utils.conversion; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; /** @@ -33,26 +34,26 @@ public class CaseConverterUtils { */ public static String toCamelCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log("Input for toCamelCase is null or empty."); + BaseLogger.log(BaseLogLevel.INFO,"Input for toCamelCase is null or empty."); return pInput; } if (Character.isUpperCase(pInput.charAt(0)) && !pInput.contains("_") && !pInput.contains("-")) { - BaseLogger.log("Input detected as PascalCase."); + BaseLogger.log(BaseLogLevel.INFO,"Input detected as PascalCase."); return pInput.substring(0, 1).toLowerCase() + pInput.substring(1); } if (pInput.contains("_")) { - BaseLogger.log("Input detected as snake_case."); + BaseLogger.log(BaseLogLevel.INFO,"Input detected as snake_case."); return convertUsingDelimiter(pInput, "_", true); } if (pInput.contains("-")) { - BaseLogger.log("Input detected as kebab-case."); + BaseLogger.log(BaseLogLevel.INFO,"Input detected as kebab-case."); return convertUsingDelimiter(pInput, "-", true); } - BaseLogger.log("Input case is not recognized."); + BaseLogger.log(BaseLogLevel.ERROR,"Input case is not recognized."); return pInput; } @@ -68,26 +69,26 @@ public static String toCamelCase(String pInput) { */ public static String toPascalCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log("Input for toPascalCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING,"Input for toPascalCase is null or empty."); return pInput; } if (!pInput.contains("_") && !pInput.contains("-") && Character.isLowerCase(pInput.charAt(0))) { - BaseLogger.log("Input detected as camelCase."); + BaseLogger.log(BaseLogLevel.INFO,"Input detected as camelCase."); return pInput.substring(0, 1).toUpperCase() + pInput.substring(1); } if (pInput.contains("_")) { - BaseLogger.log("Input detected as snake_case."); + BaseLogger.log(BaseLogLevel.INFO,"Input detected as snake_case."); return convertUsingDelimiter(pInput, "_", false); } if (pInput.contains("-")) { - BaseLogger.log("Input detected as kebab-case."); + BaseLogger.log(BaseLogLevel.INFO,"Input detected as kebab-case."); return convertUsingDelimiter(pInput, "-", false); } - BaseLogger.log("Input case is not recognized."); + BaseLogger.log(BaseLogLevel.ERROR,"Input case is not recognized."); return pInput; } @@ -103,7 +104,7 @@ public static String toPascalCase(String pInput) { */ public static String toSnakeCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log("Input for toSnakeCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING,"Input for toSnakeCase is null or empty."); return pInput; } @@ -113,7 +114,7 @@ public static String toSnakeCase(String pInput) { result = result.replace("-", "_"); - BaseLogger.log("Converted to snake_case: " + result); + BaseLogger.log(BaseLogLevel.SUCCESS,"Converted to snake_case: " + result); return result; } @@ -129,7 +130,7 @@ public static String toSnakeCase(String pInput) { */ public static String toKebabCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log("Input for toKebabCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING,"Input for toKebabCase is null or empty."); return pInput; } @@ -139,7 +140,7 @@ public static String toKebabCase(String pInput) { result = result.replace("_", "-"); - BaseLogger.log("Converted to kebab-case: " + result); + BaseLogger.log(BaseLogLevel.SUCCESS,"Converted to kebab-case: " + result); return result; } @@ -164,7 +165,7 @@ private static String convertUsingDelimiter(String pInput, String pDelimiter, bo } } String result = convertedString.toString(); - BaseLogger.log("Converted: " + result); + BaseLogger.log(BaseLogLevel.SUCCESS,"Converted: " + result); return result; } diff --git a/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java b/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java index f374af12..c20bad2b 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java @@ -5,6 +5,8 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; + +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; /** @@ -110,7 +112,7 @@ public static Date stringToDate(String pDateStr, String pFormat) throws ParseExc SimpleDateFormat formatter = new SimpleDateFormat(pFormat); return formatter.parse(pDateStr); } catch (ParseException pException) { - BaseLogger.log("Error parsing date string: " + pDateStr + " with format: " + pFormat, pException); + BaseLogger.log(BaseLogLevel.ERROR,"Error parsing date string: " + pDateStr + " with format: " + pFormat, pException); throw pException; } } @@ -129,7 +131,7 @@ public static String dateToString(Date pDate, String pFormat) { SimpleDateFormat formatter = new SimpleDateFormat(pFormat); return formatter.format(pDate); } catch (Exception pException) { - BaseLogger.log("Error formatting date: " + pDate.toString() + " with format: " + pFormat, pException); + BaseLogger.log(BaseLogLevel.ERROR,"Error formatting date: " + pDate.toString() + " with format: " + pFormat, pException); return pException.getMessage(); } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java index c8fc618a..e76e6768 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java @@ -20,10 +20,10 @@ * @since 1.0.0 */ public class BaseLogLevel { - public static final Level INFO = new Level("INFO: ", Level.INFO.intValue()) {}; - public static final Level ERROR = new Level("ERROR: ", Level.SEVERE.intValue()) {}; - public static final Level WARNING = new Level("WARNING: ", Level.WARNING.intValue()) {}; + public static final Level INFO = new Level("INFO", Level.INFO.intValue()) {}; + public static final Level ERROR = new Level("ERROR", Level.SEVERE.intValue()) {}; + public static final Level WARNING = new Level("WARNING", Level.WARNING.intValue()) {}; - public static final Level SUCCESS = new Level("SUCCESS: ", Level.INFO.intValue() + 50) {}; - public static final Level BLUELIB = new Level("", Level.INFO.intValue() + 50) {}; + public static final Level SUCCESS = new Level("SUCCESS", Level.INFO.intValue() + 50) {}; + public static final Level BLUELIB = new Level("BlueLib Developer", Level.INFO.intValue() + 50) {}; } diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java index f92a8f1e..6532f213 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java @@ -42,8 +42,8 @@ public static void configureLogger(Logger pLogger, ILogColorProvider pColorProvi handler.setFormatter(new SimpleFormatter() { @Override public synchronized String format(LogRecord pRecord) { - String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - StringBuilder coloredMessage = new StringBuilder(pColorProvider.getColor(pRecord.getLevel()) + timestamp + " [" + pRecord.getLevel() + "] " + pRecord.getMessage()); + String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")); + StringBuilder coloredMessage = new StringBuilder(pColorProvider.getColor(pRecord.getLevel()) + "[" + timestamp + "]" + " [" + pRecord.getLevel() + "]: " + pRecord.getMessage()); if (pRecord.getThrown() != null) { coloredMessage.append("\nException: ").append(pRecord.getThrown().getMessage()); diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java index 51eaaca8..2ed8a4e6 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java @@ -2,6 +2,7 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.util.ArrayList; @@ -39,7 +40,7 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { double discriminant = pB * pB - 4 * pA * pC; if (discriminant < 0) { - BaseLogger.log("No real roots found for the quadratic equation."); + BaseLogger.log(BaseLogLevel.WARNING,"No real roots found for the quadratic equation."); return new double[0]; } @@ -47,7 +48,7 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { double root1 = (-pB + sqrtDiscriminant) / (2 * pA); double root2 = (-pB - sqrtDiscriminant) / (2 * pA); - BaseLogger.log("Roots found: root1=" + root1 + ", root2=" + root2); + BaseLogger.log(BaseLogLevel.INFO,"Roots found: root1=" + root1 + ", root2=" + root2); return new double[] { root1, root2 }; } @@ -63,7 +64,7 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { public static long factorial(int pNumber) { if (pNumber < 0) { IllegalArgumentException exception = new IllegalArgumentException("Number must be non-negative."); - BaseLogger.log("Attempted to calculate factorial of a negative number: " + pNumber, exception); + BaseLogger.log(BaseLogLevel.INFO,"Attempted to calculate factorial of a negative number: " + pNumber, exception); throw exception; } @@ -72,7 +73,7 @@ public static long factorial(int pNumber) { result *= i; } - BaseLogger.log("Factorial of " + pNumber + " is " + result); + BaseLogger.log(BaseLogLevel.SUCCESS,"Factorial of " + pNumber + " is " + result); return result; } @@ -93,7 +94,7 @@ public static int calculateGCD(int pA, int pB) { pA = temp; } - BaseLogger.log("GCD found: " + pA); + BaseLogger.log(BaseLogLevel.SUCCESS,"GCD found: " + pA); return pA; } @@ -120,7 +121,7 @@ public static List> generatePowerSet(Set pSet) { powerSet.addAll(newSubsets); } - BaseLogger.log("Power set generated with " + powerSet.size() + " subsets."); + BaseLogger.log(BaseLogLevel.SUCCESS,"Power set generated with " + powerSet.size() + " subsets."); return powerSet; } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java index 263c3326..a1bca98f 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java @@ -2,6 +2,7 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; /** @@ -75,7 +76,7 @@ public static double calculateDistance3D(double pX1, double pY1, double pZ1, dou public static double calculateCircleArea(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.log("Error calculating circle area", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error calculating circle area", throwable); return Double.NaN; } return Math.PI * pRadius * pRadius; @@ -92,7 +93,7 @@ public static double calculateCircleArea(double pRadius) { public static double calculateCircleCircumference(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.log("Error calculating circle circumference", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error calculating circle circumference", throwable); return Double.NaN; } return 2 * Math.PI * pRadius; @@ -110,7 +111,7 @@ public static double calculateCircleCircumference(double pRadius) { public static double calculateRectangleArea(double pWidth, double pHeight) { if (pWidth < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Width and height must be non-negative."); - BaseLogger.log("Error calculating rectangle area", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error calculating rectangle area", throwable); return Double.NaN; } return pWidth * pHeight; @@ -128,7 +129,7 @@ public static double calculateRectangleArea(double pWidth, double pHeight) { public static double calculateRectanglePerimeter(double pWidth, double pHeight) { if (pWidth < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Width and height must be non-negative."); - BaseLogger.log("Error calculating rectangle perimeter", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error calculating rectangle perimeter", throwable); return Double.NaN; } return 2 * (pWidth + pHeight); @@ -145,7 +146,7 @@ public static double calculateRectanglePerimeter(double pWidth, double pHeight) public static double calculateTriangleArea(double pBase, double pHeight) { if (pBase < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Base and height must be non-negative."); - BaseLogger.log("Error calculating triangle area", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error calculating triangle area", throwable); return Double.NaN; } return 0.5 * pBase * pHeight; @@ -163,7 +164,7 @@ public static double calculateTriangleArea(double pBase, double pHeight) { public static double calculateTrianglePerimeter(double pSide1, double pSide2, double pSide3) { if (pSide1 < 0 || pSide2 < 0 || pSide3 < 0) { Throwable throwable = new IllegalArgumentException("Sides must be non-negative."); - BaseLogger.log("Error calculating triangle perimeter", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error calculating triangle perimeter", throwable); return Double.NaN; } return pSide1 + pSide2 + pSide3; @@ -180,7 +181,7 @@ public static double calculateTrianglePerimeter(double pSide1, double pSide2, do public static double calculateSphereVolume(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.log("Error calculating sphere volume", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error calculating sphere volume", throwable); return Double.NaN; } return (4.0 / 3.0) * Math.PI * Math.pow(pRadius, 3); @@ -197,7 +198,7 @@ public static double calculateSphereVolume(double pRadius) { public static double calculateCubeSurfaceArea(double pSideLength) { if (pSideLength < 0) { Throwable throwable = new IllegalArgumentException("Side length must be non-negative."); - BaseLogger.log("Error calculating cube surface area", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error calculating cube surface area", throwable); return Double.NaN; } return 6 * Math.pow(pSideLength, 2); @@ -215,7 +216,7 @@ public static double calculateCubeSurfaceArea(double pSideLength) { public static double calculateCylinderVolume(double pRadius, double pHeight) { if (pRadius < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Radius and height must be non-negative."); - BaseLogger.log("Error calculating cylinder volume", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error calculating cylinder volume", throwable); return Double.NaN; } return Math.PI * Math.pow(pRadius, 2) * pHeight; @@ -233,7 +234,7 @@ public static double calculateCylinderVolume(double pRadius, double pHeight) { public static double calculateConeSurfaceArea(double pRadius, double pSlantHeight) { if (pRadius < 0 || pSlantHeight < 0) { Throwable throwable = new IllegalArgumentException("Radius and slant height must be non-negative."); - BaseLogger.log("Error calculating cone surface area", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error calculating cone surface area", throwable); return Double.NaN; } return Math.PI * pRadius * (pRadius + pSlantHeight); diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java index d2159294..6f98d358 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java @@ -2,6 +2,7 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; /** @@ -35,7 +36,7 @@ public static double[][] multiplyMatrices(double[][] pMatrixA, double[][] pMatri int colsB = pMatrixB[0].length; if (colsA != pMatrixB.length) { Throwable throwable = new IllegalArgumentException("Number of columns in the first matrix must be equal to the number of rows in the second matrix."); - BaseLogger.log("Error performing matrix multiplication", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error performing matrix multiplication", throwable); return new double[0][0]; } double[][] result = new double[rowsA][colsB]; @@ -81,7 +82,7 @@ public static double[][] transposeMatrix(double[][] pMatrix) { public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { if (pMatrix.length != 2 || pMatrix[0].length != 2) { Throwable throwable = new IllegalArgumentException("Matrix must be 2x2."); - BaseLogger.log("Error calculating 2x2 matrix determinant", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error calculating 2x2 matrix determinant", throwable); return Double.NaN; } return pMatrix[0][0] * pMatrix[1][1] - pMatrix[0][1] * pMatrix[1][0]; @@ -99,13 +100,13 @@ public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { public static double[][] invert2x2Matrix(double[][] pMatrix) { if (pMatrix.length != 2 || pMatrix[0].length != 2) { Throwable throwable = new IllegalArgumentException("Matrix must be 2x2."); - BaseLogger.log("Error inverting 2x2 matrix", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error inverting 2x2 matrix", throwable); return new double[0][0]; } double determinant = calculate2x2MatrixDeterminant(pMatrix); if (determinant == 0) { Throwable throwable = new IllegalArgumentException("Matrix is not invertible."); - BaseLogger.log("Error inverting 2x2 matrix", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error inverting 2x2 matrix", throwable); return new double[0][0]; } double[][] inverse = new double[2][2]; diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java index 687aea68..b1bbd8ad 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java @@ -2,6 +2,7 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; /** @@ -45,7 +46,7 @@ public static int stringToIntWithDefault(String pString, int pDefaultValue) { try { return Integer.parseInt(pString); } catch (NumberFormatException pException) { - BaseLogger.log("Error converting string to integer", pException); + BaseLogger.log(BaseLogLevel.ERROR,"Error converting string to integer", pException); return pDefaultValue; } } @@ -91,7 +92,7 @@ public static int calculateLevenshteinDistance(String pStr1, String pStr2) { public static int[] hexToRGB(String pHex) { if (pHex == null || pHex.isEmpty()) { Throwable throwable = new IllegalArgumentException("Hex color code cannot be null or empty."); - BaseLogger.log("Error converting hex to RGB", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error converting hex to RGB", throwable); return new int[]{0, 0, 0}; } if (pHex.charAt(0) == '#') { @@ -99,7 +100,7 @@ public static int[] hexToRGB(String pHex) { } if (pHex.length() != 6) { Throwable throwable = new IllegalArgumentException("Invalid hex color code."); - BaseLogger.log("Error converting hex to RGB", throwable); + BaseLogger.log(BaseLogLevel.ERROR,"Error converting hex to RGB", throwable); return new int[]{0, 0, 0}; } try { @@ -108,7 +109,7 @@ public static int[] hexToRGB(String pHex) { int b = Integer.parseInt(pHex.substring(4, 6), 16); return new int[]{r, g, b}; } catch (NumberFormatException pException) { - BaseLogger.log("Error parsing hex color code to RGB", pException); + BaseLogger.log(BaseLogLevel.ERROR,"Error parsing hex color code to RGB", pException); return new int[]{0, 0, 0}; } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java index cb8316ba..1d0ebf7a 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java @@ -2,6 +2,7 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; /** @@ -43,7 +44,7 @@ public class RandomGenUtils { public static int generateRandomInt(int pMin, int pMax) { if (pMin > pMax) { Throwable throwable = new IllegalArgumentException("Minimum value must not be greater than maximum value."); - BaseLogger.log("Error generating random integer", throwable); + BaseLogger.log(BaseLogLevel.WARNING,"Error generating random integer", throwable); return 0; } return pMin + (int)(Math.random() * (pMax - pMin + 1)); @@ -61,7 +62,7 @@ public static int generateRandomInt(int pMin, int pMax) { public static double generateRandomDouble(double pMin, double pMax) { if (pMin > pMax) { Throwable throwable = new IllegalArgumentException("Minimum value must not be greater than maximum value."); - BaseLogger.log("Error generating random double", throwable); + BaseLogger.log(BaseLogLevel.WARNING,"Error generating random double", throwable); return 0; } return pMin + Math.random() * (pMax - pMin); @@ -90,7 +91,7 @@ public static boolean generateRandomBoolean() { public static String generateRandomString(int pLength) { if (pLength < 0) { Throwable throwable = new IllegalArgumentException("Length must be non-negative."); - BaseLogger.log("Error generating random string", throwable); + BaseLogger.log(BaseLogLevel.WARNING,"Error generating random string", throwable); return "unknown"; } String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -114,7 +115,7 @@ public static String generateRandomString(int pLength) { public static String generateRandomStringWithPrefix(String pPrefix, int pLength) { if (pLength < 0) { Throwable throwable = new IllegalArgumentException("Length must be non-negative."); - BaseLogger.log("Error generating random string with prefix", throwable); + BaseLogger.log(BaseLogLevel.WARNING,"Error generating random string with prefix", throwable); return "unknown"; } return pPrefix + generateRandomString(pLength - pPrefix.length()); diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java index 2f74eaa2..e8690b26 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java @@ -2,6 +2,7 @@ package software.bluelib.utils.math; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.util.Arrays; @@ -49,7 +50,7 @@ public class StatisticalUtils { */ public static double calculateMean(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log("Array is empty, mean calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, mean calculation might fail."); return 0; } @@ -58,7 +59,7 @@ public static double calculateMean(double[] pValues) { sum += value; } double mean = sum / pValues.length; - BaseLogger.log("Mean successfully calculated: " + mean); + BaseLogger.log(BaseLogLevel.SUCCESS,"Mean successfully calculated: " + mean); return mean; } @@ -75,7 +76,7 @@ public static double calculateMean(double[] pValues) { */ public static double calculateMedian(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log("Array is empty, median calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, median calculation might fail."); return 0; } @@ -86,7 +87,7 @@ public static double calculateMedian(double[] pValues) { (sorted[middle - 1] + sorted[middle]) / 2.0 : sorted[middle]; - BaseLogger.log("Median successfully calculated: " + median); + BaseLogger.log(BaseLogLevel.SUCCESS,"Median successfully calculated: " + median); return median; } @@ -103,7 +104,7 @@ public static double calculateMedian(double[] pValues) { */ public static double calculateMode(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log("Array is empty, mode calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, mode calculation might fail."); return 0; } @@ -121,7 +122,7 @@ public static double calculateMode(double[] pValues) { } } - BaseLogger.log("Mode successfully calculated: " + mode); + BaseLogger.log(BaseLogLevel.SUCCESS,"Mode successfully calculated: " + mode); return mode; } @@ -138,7 +139,7 @@ public static double calculateMode(double[] pValues) { */ public static double calculateStandardDeviation(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log("Array is empty, standard deviation calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, standard deviation calculation might fail."); return 0; } @@ -148,7 +149,7 @@ public static double calculateStandardDeviation(double[] pValues) { sumSquaredDifferences += Math.pow(value - mean, 2); } double stdDev = Math.sqrt(sumSquaredDifferences / pValues.length); - BaseLogger.log("Standard deviation successfully calculated: " + stdDev); + BaseLogger.log(BaseLogLevel.SUCCESS,"Standard deviation successfully calculated: " + stdDev); return stdDev; } @@ -165,7 +166,7 @@ public static double calculateStandardDeviation(double[] pValues) { */ public static double calculateVariance(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log("Array is empty, variance calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, variance calculation might fail."); return 0; } @@ -175,7 +176,7 @@ public static double calculateVariance(double[] pValues) { sumSquaredDifferences += Math.pow(value - mean, 2); } double variance = sumSquaredDifferences / pValues.length; - BaseLogger.log("Variance successfully calculated: " + variance); + BaseLogger.log(BaseLogLevel.SUCCESS,"Variance successfully calculated: " + variance); return variance; } @@ -192,14 +193,14 @@ public static double calculateVariance(double[] pValues) { */ public static double calculateRange(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log("Array is empty, range calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, range calculation might fail."); return 0; } double max = Arrays.stream(pValues).max().orElseThrow(); double min = Arrays.stream(pValues).min().orElseThrow(); double range = max - min; - BaseLogger.log("Range successfully calculated: " + range); + BaseLogger.log(BaseLogLevel.SUCCESS,"Range successfully calculated: " + range); return range; } @@ -216,14 +217,14 @@ public static double calculateRange(double[] pValues) { */ public static double calculateCoefficientOfVariation(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log("Array is empty, coefficient of variation calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, coefficient of variation calculation might fail."); return 0; } double mean = calculateMean(pValues); double stdDev = calculateStandardDeviation(pValues); double coefficient = (stdDev / mean) * 100; - BaseLogger.log("Coefficient of variation successfully calculated: " + coefficient); + BaseLogger.log(BaseLogLevel.SUCCESS,"Coefficient of variation successfully calculated: " + coefficient); return coefficient; } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java b/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java index e84ba5ad..f98a62b4 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java @@ -10,6 +10,7 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.chunk.LevelChunk; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.util.Arrays; @@ -51,10 +52,10 @@ public class ChunkUtils { public static Biome getBiomeOfChunk(Level pLevel, ChunkPos pChunkPos) { try { Biome biome = pLevel.getBiome(pChunkPos.getWorldPosition()).value(); - BaseLogger.log("Retrieved biome for chunk at position " + pChunkPos + ": " + biome); + BaseLogger.log(BaseLogLevel.INFO,"Retrieved biome for chunk at position " + pChunkPos + ": " + biome); return biome; } catch (Exception pException) { - BaseLogger.log("Error retrieving biome for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR,"Error retrieving biome for chunk at position " + pChunkPos, pException); throw pException; } } @@ -78,11 +79,11 @@ public static String getBiomeRegistryNameOfChunk(Level pLevel, ChunkPos pChunkPo if (biomeKey == null) { NullPointerException exception = new NullPointerException("Biome at chunk position " + pChunkPos + " is null"); - BaseLogger.log("Error retrieving biome registry name of chunk at " + pChunkPos, exception); - return "Biome at chunk position " + pChunkPos + " is null"; + BaseLogger.log(BaseLogLevel.ERROR,"Error retrieving biome registry name of chunk at " + pChunkPos, exception); + return exception.getMessage(); } - BaseLogger.log("Retrieved biome registry name for chunk at position " + pChunkPos + ": " + biomeKey); + BaseLogger.log(BaseLogLevel.SUCCESS,"Retrieved biome registry name for chunk at position " + pChunkPos + ": " + biomeKey); return biomeKey.toString(); } @@ -118,10 +119,10 @@ public static Collection getChunkTileEntities(Level pLevel, ChunkPo try { LevelChunk chunk = pLevel.getChunk(pChunkPos.x, pChunkPos.z); Collection tileEntities = chunk.getBlockEntities().values(); - BaseLogger.log("Retrieved " + tileEntities.size() + " tile entities for chunk at position " + pChunkPos); + BaseLogger.log(BaseLogLevel.INFO,"Retrieved " + tileEntities.size() + " tile entities for chunk at position " + pChunkPos); return tileEntities; } catch (Exception pException) { - BaseLogger.log("Error retrieving tile entities for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR,"Error retrieving tile entities for chunk at position " + pChunkPos, pException); throw pException; } } @@ -151,10 +152,10 @@ public static String getChunkTileEntitiesRegistryNames(Level pLevel, ChunkPos pC }) .collect(Collectors.joining(", ")); - BaseLogger.log("Tile entities for chunk at position " + pChunkPos + ": " + registryNames); + BaseLogger.log(BaseLogLevel.INFO,"Tile entities for chunk at position " + pChunkPos + ": " + registryNames); return registryNames; } catch (Exception pException) { - BaseLogger.log("Error retrieving tile entity registry names for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR,"Error retrieving tile entity registry names for chunk at position " + pChunkPos, pException); throw pException; } } @@ -205,10 +206,10 @@ public static int getChunkBlockCount(Level pLevel, ChunkPos pChunkPos) { } } - BaseLogger.log("Non-air block count for chunk at position " + pChunkPos + ": " + blockCount); + BaseLogger.log(BaseLogLevel.INFO,"Non-air block count for chunk at position " + pChunkPos + ": " + blockCount); return blockCount; } catch (Exception pException) { - BaseLogger.log("Error counting blocks for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR,"Error counting blocks for chunk at position " + pChunkPos, pException); throw pException; } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java b/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java index 03a1f079..875cf9be 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java @@ -4,6 +4,7 @@ import software.bluelib.entity.variant.VariantParameter; import software.bluelib.entity.variant.VariantLoader; +import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; import java.util.HashMap; @@ -177,8 +178,7 @@ public ParameterBuilder connect() { variantParametersMap.put(variantName, updatedParameters); } else { Throwable cause = new Throwable("Variant or entity not found in the database"); - NoSuchElementException exception = new NoSuchElementException("Variant '" + variantName + "' not found for entity '" + entityName + "'", cause); - BaseLogger.log(exception.getMessage(), exception); + BaseLogger.log(BaseLogLevel.ERROR, "Variant '" + variantName + "' not found for entity '" + entityName + "'", cause); } return this; } From db02629d53db649694a27968a31d54beb6ed3d48 Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 3 Oct 2024 15:33:15 +0200 Subject: [PATCH 26/62] Updated Logging! --- .../software/bluelib/utils/logging/LoggerConfig.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java index 6532f213..c0cf7361 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java @@ -48,8 +48,18 @@ public synchronized String format(LogRecord pRecord) { if (pRecord.getThrown() != null) { coloredMessage.append("\nException: ").append(pRecord.getThrown().getMessage()); for (StackTraceElement element : pRecord.getThrown().getStackTrace()) { - coloredMessage.append("\n\tat ").append(element.toString()); + String packageName = element.getClassName().substring(0, element.getClassName().lastIndexOf('.')); + String className = element.getClassName().substring(element.getClassName().lastIndexOf('.') + 1); + String methodName = element.getMethodName(); + int lineNumber = element.getLineNumber(); + + coloredMessage.append("\n\tat ") + .append(packageName).append(".") + .append(className).append(".") + .append(methodName).append("(Line: ") + .append(lineNumber).append(")"); } + } coloredMessage.append(RESET); From 9eff5e2c2c14dc6f45b0e7aca68bd2a129e2861d Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 3 Oct 2024 15:51:03 +0200 Subject: [PATCH 27/62] Updated Comments + Added More Cases --- .../utils/conversion/CaseConverterUtils.java | 153 +++++++++++++----- .../bluelib/utils/logging/BaseLogLevel.java | 26 +++ .../bluelib/utils/logging/BaseLogger.java | 112 ++++++++++++- .../bluelib/utils/logging/LoggerConfig.java | 49 +++++- 4 files changed, 289 insertions(+), 51 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java b/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java index df767a73..576caaa3 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java +++ b/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java @@ -6,8 +6,8 @@ import software.bluelib.utils.logging.BaseLogger; /** - * A {@code class} for converting strings between various naming conventions: - * camelCase, PascalCase, snake_case, and kebab-case. + * A {@code public class} for converting strings between various naming conventions: + * camelCase, PascalCase, snake_case, kebab-case, UPPER_SNAKE_CASE, Train-Case, flatcase, and COBOL-CASE. *

          * Key Methods: *

            @@ -15,6 +15,10 @@ *
          • {@link #toPascalCase(String)} - Converts input to PascalCase.
          • *
          • {@link #toSnakeCase(String)} - Converts input to snake_case.
          • *
          • {@link #toKebabCase(String)} - Converts input to kebab-case.
          • + *
          • {@link #toUpperSnakeCase(String)} - Converts input to UPPER_SNAKE_CASE.
          • + *
          • {@link #toTrainCase(String)} - Converts input to Train-Case.
          • + *
          • {@link #toFlatcase(String)} - Converts input to flatcase.
          • + *
          • {@link #toCobolCase(String)} - Converts input to COBOL-CASE.
          • *
          * * @author MeAlam @@ -34,26 +38,26 @@ public class CaseConverterUtils { */ public static String toCamelCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.INFO,"Input for toCamelCase is null or empty."); + BaseLogger.log(BaseLogLevel.INFO, "Input for toCamelCase is null or empty."); return pInput; } if (Character.isUpperCase(pInput.charAt(0)) && !pInput.contains("_") && !pInput.contains("-")) { - BaseLogger.log(BaseLogLevel.INFO,"Input detected as PascalCase."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as PascalCase."); return pInput.substring(0, 1).toLowerCase() + pInput.substring(1); } if (pInput.contains("_")) { - BaseLogger.log(BaseLogLevel.INFO,"Input detected as snake_case."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as snake_case."); return convertUsingDelimiter(pInput, "_", true); } if (pInput.contains("-")) { - BaseLogger.log(BaseLogLevel.INFO,"Input detected as kebab-case."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as kebab-case."); return convertUsingDelimiter(pInput, "-", true); } - BaseLogger.log(BaseLogLevel.ERROR,"Input case is not recognized."); + BaseLogger.log(BaseLogLevel.ERROR, "Input case is not recognized."); return pInput; } @@ -69,26 +73,26 @@ public static String toCamelCase(String pInput) { */ public static String toPascalCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.WARNING,"Input for toPascalCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING, "Input for toPascalCase is null or empty."); return pInput; } if (!pInput.contains("_") && !pInput.contains("-") && Character.isLowerCase(pInput.charAt(0))) { - BaseLogger.log(BaseLogLevel.INFO,"Input detected as camelCase."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as camelCase."); return pInput.substring(0, 1).toUpperCase() + pInput.substring(1); } if (pInput.contains("_")) { - BaseLogger.log(BaseLogLevel.INFO,"Input detected as snake_case."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as snake_case."); return convertUsingDelimiter(pInput, "_", false); } if (pInput.contains("-")) { - BaseLogger.log(BaseLogLevel.INFO,"Input detected as kebab-case."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as kebab-case."); return convertUsingDelimiter(pInput, "-", false); } - BaseLogger.log(BaseLogLevel.ERROR,"Input case is not recognized."); + BaseLogger.log(BaseLogLevel.ERROR, "Input case is not recognized."); return pInput; } @@ -104,17 +108,15 @@ public static String toPascalCase(String pInput) { */ public static String toSnakeCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.WARNING,"Input for toSnakeCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING, "Input for toSnakeCase is null or empty."); return pInput; } String result = pInput.replaceAll("([a-z])([A-Z])", "$1_$2"); - result = result.toLowerCase(); - result = result.replace("-", "_"); - BaseLogger.log(BaseLogLevel.SUCCESS,"Converted to snake_case: " + result); + BaseLogger.log(BaseLogLevel.SUCCESS, "Converted to snake_case: " + result); return result; } @@ -130,54 +132,125 @@ public static String toSnakeCase(String pInput) { */ public static String toKebabCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.WARNING,"Input for toKebabCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING, "Input for toKebabCase is null or empty."); return pInput; } String result = pInput.replaceAll("([a-z])([A-Z])", "$1-$2"); - result = result.toLowerCase(); - result = result.replace("_", "-"); - BaseLogger.log(BaseLogLevel.SUCCESS,"Converted to kebab-case: " + result); + BaseLogger.log(BaseLogLevel.SUCCESS, "Converted to kebab-case: " + result); return result; } /** - * A {@link String} helper method to convert a string by splitting it using a given delimiter, then converting each part. + * A {@link String} that converts a given {@link String} to UPPER_SNAKE_CASE. + *

          + * Converts camelCase, PascalCase, snake_case, and kebab-case to UPPER_SNAKE_CASE by adding underscores + * and converting all letters to uppercase. * * @param pInput {@link String} - The input string to be converted. - * @param pDelimiter {@link String} - The delimiter used for splitting the input string. - * @param pIsCamelCase {@code boolean} - Whether the result should be in camelCase (lowercase first letter). - * @return The converted string. + * @return The UPPER_SNAKE_CASE version of the input string. * @author MeAlam * @since 1.0.0 */ - private static String convertUsingDelimiter(String pInput, String pDelimiter, boolean pIsCamelCase) { - String[] parts = pInput.split(pDelimiter); - StringBuilder convertedString = new StringBuilder(); - for (int i = 0; i < parts.length; i++) { - if (i == 0 && pIsCamelCase) { - convertedString.append(parts[i].toLowerCase()); - } else { - convertedString.append(toProperCase(parts[i])); - } + public static String toUpperSnakeCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.log(BaseLogLevel.WARNING, "Input for toUpperSnakeCase is null or empty."); + return pInput; } - String result = convertedString.toString(); - BaseLogger.log(BaseLogLevel.SUCCESS,"Converted: " + result); - return result; + + String result = toSnakeCase(pInput); + return result.toUpperCase(); + } + + /** + * A {@link String} that converts a given {@link String} to Train-Case. + *

          + * Converts camelCase, PascalCase, snake_case, and kebab-case to Train-Case by adding hyphens and + * capitalizing each word. + * + * @param pInput {@link String} - The input string to be converted. + * @return The Train-Case version of the input string. + * @author MeAlam + * @since 1.0.0 + */ + public static String toTrainCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.log(BaseLogLevel.WARNING, "Input for toTrainCase is null or empty."); + return pInput; + } + + String result = toKebabCase(pInput).replace("-", " "); + return toCamelCase(result).replace(" ", "-"); + } + + /** + * A {@link String} that converts a given {@link String} to flatcase. + *

          + * Converts all cases to flatcase by removing any delimiters and converting to lowercase. + * + * @param pInput {@link String} - The input string to be converted. + * @return The flatcase version of the input string. + * @author MeAlam + * @since 1.0.0 + */ + public static String toFlatcase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.log(BaseLogLevel.WARNING, "Input for toFlatcase is null or empty."); + return pInput; + } + + return pInput.replaceAll("[_-]", "").toLowerCase(); } /** - * A {@link String} that converts a string to ProperCase, where the first letter is capitalized and the rest are lowercase. + * A {@link String} that converts a given {@link String} to COBOL-CASE. + *

          + * Converts camelCase, PascalCase, snake_case, and kebab-case to COBOL-CASE by making all letters uppercase + * and replacing spaces with hyphens. * * @param pInput {@link String} - The input string to be converted. - * @return The ProperCase version of the input string. + * @return The COBOL-CASE version of the input string. * @author MeAlam * @since 1.0.0 */ - private static String toProperCase(String pInput) { - return pInput.substring(0, 1).toUpperCase() + pInput.substring(1).toLowerCase(); + public static String toCobolCase(String pInput) { + if (pInput == null || pInput.isEmpty()) { + BaseLogger.log(BaseLogLevel.WARNING, "Input for toCobolCase is null or empty."); + return pInput; + } + + String result = toKebabCase(pInput); + return result.toUpperCase(); + } + + /** + * A helper method that converts strings using a specified delimiter. + *

          + * This method capitalizes the first letter of each word and joins them using the specified delimiter. + * + * @param pInput {@link String} - The input string to be converted. + * @param pDelim {@link String} - The delimiter used to split the input string. + * @param pCamel {@code boolean} - Indicates if the conversion is to camelCase. + * @return The converted string. + * @author MeAlam + * @since 1.0.0 + */ + private static String convertUsingDelimiter(String pInput, String pDelim, boolean pCamel) { + String[] parts = pInput.split(pDelim); + StringBuilder sb = new StringBuilder(); + + for (String part : parts) { + if (pCamel && sb.isEmpty()) { + sb.append(part.substring(0, 1).toLowerCase()); + } else { + sb.append(part.substring(0, 1).toUpperCase()); + } + sb.append(part.substring(1).toLowerCase()); + } + + return sb.toString(); } } diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java index e76e6768..15f8ab85 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java @@ -20,10 +20,36 @@ * @since 1.0.0 */ public class BaseLogLevel { + /** + * Standard informational log level. + * @Co-author MeAlam + * @since 1.0.0 + */ public static final Level INFO = new Level("INFO", Level.INFO.intValue()) {}; + /** + * Log level for error messages. + * @Co-author MeAlam + * @since 1.0.0 + */ public static final Level ERROR = new Level("ERROR", Level.SEVERE.intValue()) {}; + /** + * Log level for warning messages. + * @Co-author MeAlam + * @since 1.0.0 + */ public static final Level WARNING = new Level("WARNING", Level.WARNING.intValue()) {}; + /** + * Custom log level for indicating successful operations. + * @Co-author MeAlam + * @since 1.0.0 + */ public static final Level SUCCESS = new Level("SUCCESS", Level.INFO.intValue() + 50) {}; + + /** + * Custom log level specific to BlueLib. + * @Co-author MeAlam + * @since 1.0.0 + */ public static final Level BLUELIB = new Level("BlueLib Developer", Level.INFO.intValue() + 50) {}; } diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java index 37bffaf2..fcc6e141 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -4,28 +4,91 @@ import java.util.logging.Level; import java.util.logging.Logger; - +import software.bluelib.BlueLib; + +/** + * A {@code public class} responsible for logging messages + * with various logging levels and configurations for {@link BlueLib}. + *

          + * Key Methods: + *

            + *
          • {@link #setBlueLibLoggingEnabled(boolean)} - Enables or disables {@link BlueLib} specific logging.
          • + *
          • {@link #isBlueLibLoggingEnabled()} - Checks if {@link BlueLib} logging is enabled.
          • + *
          • {@link #log(Level, String, Throwable, boolean)} - Logs a message with an associated {@link Throwable}.
          • + *
          • {@link #log(Level, String, boolean)} - Logs a message with a specified logging level.
          • + *
          • {@link #log(Level, String, Throwable)} - Logs a message with an associated {@link Throwable}, if logging is enabled.
          • + *
          • {@link #log(Level, String)} - Logs a message with a specified logging level, if logging is enabled.
          • + *
          • {@link #logBlueLib(String)} - Logs a {@link BlueLib} specific message.
          • + *
          + * + * @author MeAlam + * @Co-author Dan + * @since 1.0.0 + */ public class BaseLogger { + /** + * A {@link Logger} instance for logging messages. + * @Co-author MeAlam + * @since 1.0.0 + */ private static final Logger logger = Logger.getLogger(BaseLogger.class.getName()); //FIXME: Set to false before release + /** + * A {@link Boolean} to enable or disable BlueLib specific logging. + * @Co-author MeAlam + * @since 1.0.0 + */ private static boolean bluelibLogging = true; + /** + * A {@link Boolean} to enable or disable general logging. + * @Co-author MeAlam + * @since 1.0.0 + */ private static boolean isLoggingEnabled = true; + /** + * A {@code void} to enable or disable {@link BlueLib} specific logging. + * + * @param pEnabled {@link boolean} - Indicates whether to enable or disable BlueLib logging. + * @Co-author MeAlam + * @since 1.0.0 + */ public static void setBlueLibLoggingEnabled(boolean pEnabled) { bluelibLogging = pEnabled; } + /** + * A {@link Boolean} method that checks if BlueLib logging is enabled. + * + * @return {@code true} if BlueLib logging is enabled, {@code false} otherwise. + * @Co-author MeAlam + * @since 1.0.0 + */ public static boolean isBlueLibLoggingEnabled() { return bluelibLogging; } + /** + * A {@link Boolean} method that checks if logging is enabled. + * + * @return {@code true} if general logging is enabled, {@code false} otherwise. + * @Co-author MeAlam + * @since 1.0.0 + */ public static boolean isLoggingEnabled() { return isLoggingEnabled; } + /** + * A {@code void} to enable or disable general logging. + * + * @param pEnabled {@link boolean} - Indicates whether to enable or disable general logging. + * @Co-author MeAlam + * @since 1.0.0 + */ public static void setLoggingEnabled(boolean pEnabled) { isLoggingEnabled = pEnabled; } @@ -34,30 +97,73 @@ public static void setLoggingEnabled(boolean pEnabled) { LoggerConfig.configureLogger(logger, new DefaultLogColorProvider()); } + /** + * A {@code void} that logs a message with an associated {@link Throwable} if {@link BlueLib} logging is enabled. + * + * @param pLogLevel {@link Level} - The logging level to use. + * @param pMessage {@link String} - The message to log. + * @param pThrowable {@link Throwable} - The throwable to log with the message. + * @param pIsBlueLib {@link boolean} - Indicates if the message is {@link BlueLib} specific. + * @Co-author MeAlam + * @since 1.0.0 + */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, boolean pIsBlueLib) { if (pIsBlueLib && bluelibLogging) { logger.log(pLogLevel, pMessage, pThrowable); } } - public static void log(Level pLogLevel,String pMessage, boolean pIsBlueLib) { + /** + * A {@code void} that logs a message if BlueLib logging is enabled. + * + * @param pLogLevel {@link Level} - The logging level to use. + * @param pMessage {@link String} - The message to log. + * @param pIsBlueLib {@link boolean} - Indicates if the message is {@link BlueLib} specific. + * @Co-author MeAlam + * @since 1.0.0 + */ + public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { if (pIsBlueLib && bluelibLogging) { logger.log(pLogLevel, pMessage); } } + /** + * A {@code void} that logs a message with an associated {@link Throwable} if general logging is enabled. + * + * @param pLogLevel {@link Level} - The logging level to use. + * @param pMessage {@link String} - The message to log. + * @param pThrowable {@link Throwable} - The throwable to log with the message. + * @Co-author MeAlam + * @since 1.0.0 + */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { if (isLoggingEnabled) { logger.log(pLogLevel, pMessage, pThrowable); } } - public static void log(Level pLogLevel,String pMessage) { + /** + * A {@code void} that logs a message if general logging is enabled. + * + * @param pLogLevel {@link Level} - The logging level to use. + * @param pMessage {@link String} - The message to log. + * @Co-author MeAlam + * @since 1.0.0 + */ + public static void log(Level pLogLevel, String pMessage) { if (isLoggingEnabled) { logger.log(pLogLevel, pMessage); } } + /** + * A {@code void} that logs a {@link BlueLib} specific message at the {@link BlueLib} log level. + * + * @param pMessage {@link String} - The {@link BlueLib} message to log. + * @Co-author MeAlam + * @since 1.0.0 + */ public static void logBlueLib(String pMessage) { logger.log(BaseLogLevel.BLUELIB, pMessage); } diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java index c0cf7361..dad4027d 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java +++ b/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java @@ -12,38 +12,72 @@ import java.util.logging.SimpleFormatter; /** - * A {@code class} responsible for configuring logging settings + * A {@code public abstract class} responsible for configuring logging settings, * including setting up custom colors for log levels. *

          * Key Methods: *

            - *
          • {@link #configureLogger(Logger, ILogColorProvider)} - Configures a {@link Logger} to use custom colors for log levels.
          • + *
          • {@link #configureLogger(Logger, ILogColorProvider)} - Configures a {@link Logger} + * to use custom colors for log levels.
          • *
          + * * @author MeAlam * @since 1.0.0 */ public abstract class LoggerConfig { + /** + * ANSI color codes for console output. + * @Co-author MeAlam + * @since 1.0.0 + */ protected static final String RESET = "\u001B[0m"; + + /** + * ANSI color codes for console output. + * @Co-author MeAlam + * @since 1.0.0 + */ protected static final String RED = "\u001B[31m"; + + /** + * ANSI color codes for console output. + * @Co-author MeAlam + * @since 1.0.0 + */ protected static final String ORANGE = "\u001B[38;5;214m"; + + /** + * ANSI color codes for console output. + * @Co-author MeAlam + * @since 1.0.0 + */ protected static final String BLUE = "\u001B[34m"; + + /** + * ANSI color codes for console output. + * @Co-author MeAlam + * @since 1.0.0 + */ protected static final String GREEN = "\u001B[38;5;10m"; /** - * A {@link Logger} configuration method that sets up a {@link ConsoleHandler} with custom color formatting - * based on log level using the provided {@link ILogColorProvider}. + * A {@link Logger} configuration method that sets up a {@link ConsoleHandler} + * with custom color formatting based on log level using the provided {@link ILogColorProvider}. * * @param pLogger {@link Logger} - The logger instance to be configured. * @param pColorProvider {@link ILogColorProvider} - Provides color codes for different log levels. + * @author MeAlam + * @since 1.0.0 */ public static void configureLogger(Logger pLogger, ILogColorProvider pColorProvider) { ConsoleHandler handler = new ConsoleHandler(); handler.setFormatter(new SimpleFormatter() { - @Override - public synchronized String format(LogRecord pRecord) { + @Override + public synchronized String format(LogRecord pRecord) { String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")); - StringBuilder coloredMessage = new StringBuilder(pColorProvider.getColor(pRecord.getLevel()) + "[" + timestamp + "]" + " [" + pRecord.getLevel() + "]: " + pRecord.getMessage()); + StringBuilder coloredMessage = new StringBuilder(pColorProvider.getColor(pRecord.getLevel()) + + "[" + timestamp + "]" + " [" + pRecord.getLevel() + "]: " + pRecord.getMessage()); if (pRecord.getThrown() != null) { coloredMessage.append("\nException: ").append(pRecord.getThrown().getMessage()); @@ -59,7 +93,6 @@ public synchronized String format(LogRecord pRecord) { .append(methodName).append("(Line: ") .append(lineNumber).append(")"); } - } coloredMessage.append(RESET); From db425c6f2ed3dffba3e5d2676f2a3080be3c61ef Mon Sep 17 00:00:00 2001 From: Aram Date: Sun, 6 Oct 2024 13:48:03 +0200 Subject: [PATCH 28/62] Update ParameterBase.java * Cleared up some comments Co-Authored-By: Justindraak1 <86565594+justindraak1@users.noreply.github.com> --- .../bluelib/entity/variant/base/ParameterBase.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java index cf81e48d..69d1682d 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java @@ -11,7 +11,7 @@ import java.util.Set; /** - * An {@code public abstract base class} for managing a collection of {@link #parameters}. + * A {@code public abstract base class} for managing a collection of {@link #parameters}. *

          * This {@code class} provides methods to add, retrieve, remove, and manipulate {@link #parameters} stored as key-value pairs. *

          @@ -117,7 +117,7 @@ protected Map getAllParameters() { * This method returns {@code true} if the parameter with the specified key exists in {@link #parameters}, {@code false} otherwise. *

          * @param pKey {@link String} - The key of the parameter to check. - * @return {@link Boolean} - {@code true} if the parameter exists, {@code false} otherwise. + * @return {@link Boolean} - {@code true} if the parameter exists and {@code false} if it doesn't. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -133,7 +133,7 @@ protected boolean containsParameter(String pKey) { *

          * This method returns {@code true} if {@link #parameters} contains no parameters, {@code false} otherwise. *

          - * @return {@link Boolean} - {@code true} if {@link #parameters} is empty, {@code false} otherwise. + * @return {@link Boolean} - {@code true} if {@link #parameters} is empty and {@code false} if it isn't. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -145,10 +145,7 @@ protected boolean isEmpty() { } /** - * A {@code protected void} that clears all parameters from {@link #parameters}. - *

          - * This method removes all parameters from {@link #parameters}. - *

          + * A {@code protected void} that removes all parameters from {@link #parameters}. * @author MeAlam * @Co-author Dan * @since 1.0.0 @@ -160,9 +157,6 @@ protected void clearParameters() { /** * A {@code protected} {@link Integer} that returns the number of parameters in {@link #parameters}. - *

          - * This method provides the count of parameters currently stored in {@link #parameters}. - *

          * @return {@link Integer} - The number of parameters in the collection. * @author MeAlam * @Co-author Dan From dad3a9e99faf8a5b7eb64c9e118ea10d5254f2c7 Mon Sep 17 00:00:00 2001 From: Aram Date: Sun, 6 Oct 2024 13:57:10 +0200 Subject: [PATCH 29/62] Update VariantLoader.java * Cleaned some comments Co-Authored-By: Justindraak1 <86565594+justindraak1@users.noreply.github.com> --- .../bluelib/entity/variant/VariantLoader.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java index dd08fd8b..b2c3971d 100644 --- a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -20,7 +20,7 @@ * A {@code public class} that implements the {@link IVariantEntityBase} {@code interface} that manages the loading and storage of entity variants. *

          * The class handles loading and merging of JSON Data by utilizing the {@link JSONLoader} and {@link JSONMerger} classes.
          - * To load the Variants it loops thru all resources in a folder and merges them into a single {@link JsonObject}.
          + * To load the Variants it loops through all resources in a folder and merges them into a single {@link JsonObject}.
          * The merged JSON data is then parsed into {@link VariantParameter} instances and stored in {@link #entityVariantsMap}.
          *

          * Key Methods: @@ -47,9 +47,6 @@ public class VariantLoader implements IVariantEntityBase { /** * A {@code private static final} {@link JSONLoader} to load JSON data from resources. - *

          - * This {@link JSONLoader} instance is used to load JSON data from resources. - *

          * @Co-author MeAlam, Dan * @since 1.0.0 */ @@ -66,10 +63,9 @@ public class VariantLoader implements IVariantEntityBase { private static final JSONMerger jsonMerger = new JSONMerger(); /** - * A {@code public static void} that loads and merges variant data from JSON resources. + * A {@code public static void} that loads and merges variant data from JSON resources in the specified folder path. *

          - * This method loads and merges JSON data from resources in the specified folder path.
          - * The method loops thru all resources in the folder and merges them into a single {@link JsonObject}.
          + * The method loops through all resources in the folder and merges them into a single {@link JsonObject}.
          * The merged JSON data is then parsed into {@link VariantParameter} instances and stored in {@link #entityVariantsMap}. *

          * @param folderPath {@link String} - The path to the folder containing JSON resources. @@ -169,7 +165,7 @@ public static List getVariantsFromEntity(String pEntityName) { } /** - * A {@code public static} {@link VariantParameter} that retrieves a {@link VariantParameter} by its name for a specific entity. + * A {@code public static} {@link VariantParameter} that retrieves a {@link VariantParameter} for a specific entity, by the variant's name. *

          * This method searches for a variant with the specified name within the list of variants for the given entity. *

          From 57d6a666bbb52f033f5efdcf80513be1056840da Mon Sep 17 00:00:00 2001 From: Aram Date: Sun, 6 Oct 2024 14:11:26 +0200 Subject: [PATCH 30/62] Cleaned some Comments Co-Authored-By: Justindraak1 <86565594+justindraak1@users.noreply.github.com> --- .../main/java/software/bluelib/BlueLib.java | 8 +- .../bluelib/event/ReloadEventHandler.java | 2 +- .../interfaces/logging/ILogColorProvider.java | 2 +- .../interfaces/variant/IVariantAccessor.java | 32 ++++++- .../interfaces/variant/IVariantEntity.java | 4 +- .../variant/base/IVariantEntityBase.java | 6 +- .../software/bluelib/json/JSONLoader.java | 6 +- .../software/bluelib/json/JSONMerger.java | 4 +- .../mixin/variant/LivingEntityMixin.java | 85 ++++++++++++++++++- 9 files changed, 130 insertions(+), 19 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/BlueLib.java b/NeoForge/src/main/java/software/bluelib/BlueLib.java index a834bef5..36612b6a 100644 --- a/NeoForge/src/main/java/software/bluelib/BlueLib.java +++ b/NeoForge/src/main/java/software/bluelib/BlueLib.java @@ -44,7 +44,7 @@ public class BlueLib { /** - * A {@link ScheduledExecutorService} used to schedule tasks, such as printing messages after a delay. + * A {@code public static final} {@link ScheduledExecutorService} used to schedule tasks, such as printing messages after a delay. *

          * This executor runs tasks on a single thread to ensure delayed tasks run in a separate thread from the main thread. *

          @@ -54,7 +54,7 @@ public class BlueLib { private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1); /** - * A {@link String} representing the Mod ID for the {@link BlueLib} mod. + * A {@code public static final} {@link String} representing the Mod ID for the {@link BlueLib} mod. *

          This serves as a unique identifier for the mod.

          * @Co-author MeAlam, Dan * @since 1.0.0 @@ -86,7 +86,7 @@ public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { } /** - * a {@code void} that handles the {@link FMLLoadCompleteEvent}, which occurs when the mod finishes loading. + * A {@code public void} that handles the {@link FMLLoadCompleteEvent}, which occurs when the mod finishes loading. *

          * If the mod is in developer mode, it schedules a task that prints a thank-you message after a short delay. *

          @@ -112,7 +112,7 @@ public void onLoadComplete(FMLLoadCompleteEvent pEvent) { } /** - * a {@code void} that checks if the mod is running in developer mode. + * A {@code static} {@link Boolean} that checks if the mod is running in developer mode. *

          * Developer mode is active when the mod is not running in a production environment. *

          diff --git a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java index 6ba0a893..53c35347 100644 --- a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -30,7 +30,7 @@ public class ReloadEventHandler { /** - * A {@code void} that registers entity variants from specified locations. + * A {@code protected static void} that registers entity variants from specified locations. *

          * This method attempts to load variants from both mod and datapack locations. It logs status information and * handles exceptions that occur during the loading process. diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java b/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java index ba85c030..c0a48b1c 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java @@ -5,7 +5,7 @@ import java.util.logging.Level; /** - * An {@code Interface} for providing color codes based on log levels. + * A {@code public Interface} for providing color codes based on log levels. *

          * This interface defines a method to retrieve color codes for various log levels. Implementations should provide * the appropriate color codes for each log level to enhance the readability of log messages. diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java index bd4a4579..b688ed28 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java @@ -1,7 +1,37 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.interfaces.variant; +/** + * A {@code public Interface} interface responsible for accessing and modifying + * variant-related properties of an entity within the BlueLib framework. + *

          + * Key Methods: + *

            + *
          • {@link #setEntityVariantName(String)} - Sets the variant name for an entity.
          • + *
          • {@link #getEntityVariantName()} - Retrieves the variant name of an entity.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ public interface IVariantAccessor { + + /** + * A {@code void} method that sets the variant name for the entity. + * + * @param pVariantName {@link String} - The variant name to assign to the entity. + * @author MeAlam + * @since 1.0.0 + */ void setEntityVariantName(String pVariantName); + + /** + * A {@link String} method that retrieves the variant name of the entity. + * + * @return {@link String} - The current variant name of the entity. + * @author MeAlam + * @since 1.0.0 + */ String getEntityVariantName(); } - diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java index 97c50daa..2b08cdac 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java @@ -10,7 +10,7 @@ import java.util.List; /** - * An {@code Interface} representing an entity that supports multiple variants. + * A {@code public Interface} representing an entity that supports multiple variants. *

          * This interface extends {@link IVariantEntityBase} to include methods specific to handling entity variants, including * random selection of variants. @@ -35,7 +35,7 @@ public interface IVariantEntity extends IVariantEntityBase { RandomSource random = RandomSource.create(); /** - * A {@link String} that selects a random variant name from the provided list of variant names. + * A {@code default} {@link String} that selects a random variant name from the provided list of variant names. *

          * This method uses the {@link RandomSource} to pick a random variant from the list. If the list is empty, the default * variant name is returned. diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index 46c9ca2a..d89c5499 100644 --- a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -12,7 +12,7 @@ import java.util.stream.Collectors; /** - * An {@code base Interface} providing fundamental methods for handling entity variants. + * A {@code public base Interface} providing fundamental methods for handling entity variants. *

          * This interface defines methods for retrieving texture locations and variant names associated with entities. *

          @@ -30,7 +30,7 @@ public interface IVariantEntityBase { /** - * A {@link ResourceLocation} that points to the texture of an entity. + * A {@code default} {@link ResourceLocation} that points to the texture of an entity. *

          * This method constructs a {@link ResourceLocation} using the provided mod ID and texture path. *

          @@ -47,7 +47,7 @@ default ResourceLocation getTextureLocation(String pModId, String pPath) { } /** - * A {@link List} of variant names associated with the specified entity. + * A {@code default} {@link List} of variant names associated with the specified entity. *

          * This method retrieves the names of all variants for a given entity by querying the {@link VariantLoader}. *

          diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java b/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java index 55569689..25a6f80b 100644 --- a/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java +++ b/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java @@ -17,7 +17,7 @@ import java.util.Optional; /** - * A {@code class} responsible for loading and parsing JSON data from + * A {@code public class} responsible for loading and parsing JSON data from * resources defined by {@link ResourceLocation} within a Minecraft mod environment.
          * It uses the {@link Gson} library to convert JSON strings into {@link JsonObject} instances. *

          @@ -32,13 +32,13 @@ public class JSONLoader { /** - * A {@link Gson} instance for parsing JSON data. + * A {@code private static} {@link Gson} instance for parsing JSON data. * @Co-author MeAlam, Dan */ private static final Gson gson = new Gson(); /** - * A {@link JsonObject} that loads JSON data from a {@link ResourceLocation}.
          + * A {@code public} {@link JsonObject} that loads JSON data from a {@link ResourceLocation}.
          * This method is typically used to load configuration files or other JSON-based resources * in a Minecraft mod environment. *

          diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java b/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java index d2518b0c..ac300db6 100644 --- a/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java +++ b/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java @@ -11,7 +11,7 @@ import java.util.Map; /** - * A {@code class} responsible for merging JSON data from a source {@link JsonObject} into a target {@link JsonObject}. + * A {@code public class} responsible for merging JSON data from a source {@link JsonObject} into a target {@link JsonObject}. *

          * This class provides functionality to combine JSON data where overlapping keys result in merging arrays, * and non-overlapping keys are simply added to the target. @@ -30,7 +30,7 @@ public class JSONMerger { /** - * A {@code void} method that merges data from a source {@link JsonObject} into a target {@link JsonObject}. + * A {@code public void} method that merges data from a source {@link JsonObject} into a target {@link JsonObject}. *

          * If the target JSON object already contains a key present in the source JSON object, the values are merged if they are arrays. * Otherwise, the source value is added to the target JSON object. diff --git a/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java b/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java index afb65d3c..68592587 100644 --- a/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java +++ b/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.mixin.variant; import net.minecraft.nbt.CompoundTag; @@ -14,46 +16,125 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import software.bluelib.interfaces.variant.IVariantAccessor; +/** + * A {@code public} {@link Mixin} class that injects functionality into the {@link LivingEntity} class to + * provide variant management support within the BlueLib framework. + *

          + * This mixin adds functionality to define, save, and retrieve an entity's variant information + * using NBT (Named Binary Tag) data. It implements the {@link IVariantAccessor} interface, which + * allows setting and getting the variant name of a {@link LivingEntity}. + *

          + * Key Methods: + *

            + *
          • {@link #bluelib$setVariantName(String)} - Sets the variant name of the entity.
          • + *
          • {@link #bluelib$getVariantName()} - Retrieves the variant name of the entity.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ @Mixin(LivingEntity.class) public class LivingEntityMixin implements IVariantAccessor { + /** + * A {@link EntityDataAccessor} to hold the entity's variant name, which is synchronized + * across clients and servers using {@link SynchedEntityData}. + * @Co-author MeAlam + * @since 1.0.0 + */ @Unique private static final EntityDataAccessor bluelib$VARIANT = SynchedEntityData.defineId(LivingEntity.class, EntityDataSerializers.STRING); + /** + * A {@code public void} that injects into the {@code defineSynchedData} method of {@link LivingEntity} to define + * the synchronized data that will hold the entity's variant information. + * + * @param pBuilder {@link SynchedEntityData.Builder} - The builder to define entity data. + * @param pCi {@link CallbackInfo} - Callback information for the injection process. + * @author MeAlam + * @since 1.0.0 + */ @Inject(method = "defineSynchedData", at = @At("HEAD")) protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder, CallbackInfo pCi) { - pBuilder.define(bluelib$VARIANT, "normal"); + pBuilder.define(bluelib$VARIANT, "normal"); // Default variant is "normal" } + /** + * A {@code public void} that injects into the {@code addAdditionalSaveData} method of {@link LivingEntity} to store + * the entity's variant in NBT data when saving the entity. + * + * @param pCompound {@link CompoundTag} - The NBT tag to save the entity's variant information. + * @param pCi {@link CallbackInfo} - Callback information for the injection process. + * @author MeAlam + * @since 1.0.0 + */ @Inject(method = "addAdditionalSaveData", at = @At("HEAD")) public void addAdditionalSaveData(@NotNull CompoundTag pCompound, CallbackInfo pCi) { pCompound.putString("Variant", bluelib$getVariantName()); } + /** + * A {@code public void} that injects into the {@code readAdditionalSaveData} method of {@link LivingEntity} to read + * the entity's variant from NBT data when loading the entity. + * + * @param pCompound {@link CompoundTag} - The NBT tag containing the entity's variant information. + * @param pCi {@link CallbackInfo} - Callback information for the injection process. + * @author MeAlam + * @since 1.0.0 + */ @Inject(method = "readAdditionalSaveData", at = @At("HEAD")) public void readAdditionalSaveData(@NotNull CompoundTag pCompound, CallbackInfo pCi) { bluelib$setVariantName(pCompound.getString("Variant")); } + /** + * A {@code public void} method that sets the entity's variant name. + * + * @param pName {@link String} - The variant name to assign to the entity. + * @author MeAlam + * @since 1.0.0 + */ @Unique public void bluelib$setVariantName(String pName) { ((Entity) (Object) this).getEntityData().set(bluelib$VARIANT, pName); } + /** + * A {@code public} {@link String} method that retrieves the entity's current variant name. + * + * @return The current variant name of the entity as a {@link String}. + * @author MeAlam + * @since 1.0.0 + */ @Unique public String bluelib$getVariantName() { return ((Entity) (Object) this).getEntityData().get(bluelib$VARIANT); } + /** + * A {@code public void} method that sets the variant name of the entity. This method overrides + * the {@link IVariantAccessor#setEntityVariantName(String)} interface method. + * + * @param pVariantName {@link String} - The variant name to set for the entity. + * @author MeAlam + * @since 1.0.0 + */ @Override public void setEntityVariantName(String pVariantName) { bluelib$setVariantName(pVariantName); } + /** + * A {@code public} {@link String} method that retrieves the variant name of the entity. This method overrides + * the {@link IVariantAccessor#getEntityVariantName()} interface method. + * + * @return The current variant name of the entity as a {@link String}. + * @author MeAlam + * @since 1.0.0 + */ @Override public String getEntityVariantName() { return bluelib$getVariantName(); } } - From 179672028577d08f5857602982cde99bd96c7f89 Mon Sep 17 00:00:00 2001 From: Aram Date: Sun, 6 Oct 2024 14:16:55 +0200 Subject: [PATCH 31/62] Update LivingEntityMixin.java * Cleaned some Comments Co-Authored-By: Justindraak1 <86565594+justindraak1@users.noreply.github.com> --- .../java/software/bluelib/mixin/variant/LivingEntityMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java b/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java index 68592587..ca1dfd26 100644 --- a/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java +++ b/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java @@ -57,7 +57,7 @@ public class LivingEntityMixin implements IVariantAccessor { */ @Inject(method = "defineSynchedData", at = @At("HEAD")) protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder, CallbackInfo pCi) { - pBuilder.define(bluelib$VARIANT, "normal"); // Default variant is "normal" + pBuilder.define(bluelib$VARIANT, "normal"); } /** From 3d9117deb06460b82a0ab0b112d189036e3a5ae1 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 01:54:47 +0200 Subject: [PATCH 32/62] Refactored Entire Codebase to MultiLoader --- .gitignore | 26 ++ Forge/.gitattributes | 5 - Forge/.gitignore | 25 -- Forge/build.gradle | 131 +++--- Forge/changelog.txt | 0 Forge/gradle.properties | 25 -- Forge/gradle/wrapper/gradle-wrapper.jar | Bin 62076 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - Forge/gradlew | 245 ----------- Forge/gradlew.bat | 92 ----- Forge/settings.gradle | 19 - .../main/java/software/bluelib/BlueLib.java | 96 +---- .../bluelib/entity/variant/VariantLoader.java | 169 -------- .../entity/variant/VariantParameter.java | 131 ------ .../entity/variant/base/ParameterBase.java | 179 -------- .../bluelib/event/ReloadEventHandler.java | 78 ---- .../example/entity/dragon/DragonEntity.java | 225 ---------- .../example/entity/dragon/DragonModel.java | 29 -- .../example/entity/dragon/DragonRender.java | 14 - .../bluelib/example/entity/rex/RexEntity.java | 225 ---------- .../bluelib/example/entity/rex/RexModel.java | 29 -- .../bluelib/example/entity/rex/RexRender.java | 14 - .../bluelib/example/event/ClientEvents.java | 21 - .../bluelib/example/event/CommonModEvent.java | 18 - .../bluelib/example/event/ReloadHandler.java | 141 ------- .../bluelib/example/init/ModEntities.java | 42 -- .../bluelib/example/proxy/ClientProxy.java | 19 - .../bluelib/example/proxy/CommonProxy.java | 13 - .../bluelib/exception/CouldNotLoadJSON.java | 64 --- .../interfaces/variant/IVariantEntity.java | 56 --- .../variant/base/IVariantEntityBase.java | 65 --- .../software/bluelib/json/JSONLoader.java | 69 ---- .../software/bluelib/json/JSONMerger.java | 64 --- .../bluelib/utils/ParameterUtils.java | 181 -------- Forge/src/main/resources/META-INF/mods.toml | 14 +- .../bluelib/animations/dragon.animation.json | 63 --- .../bluelib/animations/rex.animation.json | 51 --- .../assets/bluelib/geo/dragon.geo.json | 93 ----- .../resources/assets/bluelib/geo/rex.geo.json | 390 ------------------ .../resources/assets/bluelib/lang/en_us.json | 4 - .../bluelib/textures/entity/dragon/bright.png | Bin 676 -> 0 bytes .../bluelib/textures/entity/dragon/dark.png | Bin 676 -> 0 bytes .../bluelib/textures/entity/rex/brown.png | Bin 3454 -> 0 bytes .../bluelib/textures/entity/rex/green.png | Bin 1531 -> 0 bytes .../data/bluelib/variant/entity/dragon.json | 24 -- .../data/bluelib/variant/entity/rex.json | 24 -- Forge/src/main/resources/pack.mcmeta | 6 - NeoForge/.gitignore | 26 -- NeoForge/build.gradle | 134 +----- NeoForge/changelog.txt | 0 NeoForge/gradle.properties | 29 -- NeoForge/settings.gradle | 11 - .../main/java/software/bluelib/BlueLib.java | 82 +--- .../example/entity/dragon/DragonEntity.java | 149 ------- .../example/entity/dragon/DragonModel.java | 29 -- .../example/entity/dragon/DragonRender.java | 14 - .../bluelib/example/entity/rex/RexEntity.java | 146 ------- .../bluelib/example/entity/rex/RexModel.java | 29 -- .../bluelib/example/entity/rex/RexRender.java | 14 - .../bluelib/example/event/ClientEvents.java | 28 -- .../bluelib/example/event/ReloadHandler.java | 141 ------- .../bluelib/example/init/ModEntities.java | 40 -- .../resources/META-INF/neoforge.mods.toml | 35 +- .../bluelib/animations/dragon.animation.json | 63 --- .../bluelib/animations/rex.animation.json | 51 --- .../assets/bluelib/geo/dragon.geo.json | 93 ----- .../resources/assets/bluelib/geo/rex.geo.json | 390 ------------------ .../resources/assets/bluelib/lang/en_us.json | 4 - .../bluelib/textures/entity/dragon/blue.png | Bin 676 -> 0 bytes .../bluelib/textures/entity/dragon/bright.png | Bin 676 -> 0 bytes .../bluelib/textures/entity/dragon/dark.png | Bin 676 -> 0 bytes .../bluelib/textures/entity/dragon/pink.png | Bin 676 -> 0 bytes .../bluelib/textures/entity/rex/brown.png | Bin 3454 -> 0 bytes .../bluelib/textures/entity/rex/green.png | Bin 1531 -> 0 bytes NeoForge/src/main/resources/bluelib.png | Bin 145980 -> 0 bytes .../bluelib/variant/entity/dragon/blue.json | 14 - .../bluelib/variant/entity/dragon/dragon.json | 24 -- .../bluelib/variant/entity/dragon/pink.json | 14 - .../data/bluelib/variant/entity/rex/rex.json | 24 -- NeoForge/src/main/resources/pack.mcmeta | 6 - build.gradle | 6 + buildSrc/build.gradle | 3 + .../src/main/groovy/bluelib-common.gradle | 125 ++++++ .../src/main/groovy/bluelib-loader.gradle | 44 ++ common/build.gradle | 41 ++ .../java/software/bluelib/BlueLibCommon.java | 59 +++ .../software/bluelib/BlueLibConstants.java | 27 ++ .../bluelib/entity/variant/VariantLoader.java | 0 .../entity/variant/VariantParameter.java | 0 .../entity/variant/base/ParameterBase.java | 0 .../bluelib/event/ReloadEventHandler.java | 0 .../interfaces/logging/ILogColorProvider.java | 0 .../interfaces/platform/IPlatformHelper.java | 36 ++ .../interfaces/variant/IVariantAccessor.java | 0 .../interfaces/variant/IVariantEntity.java | 0 .../variant/base/IVariantEntityBase.java | 0 .../software/bluelib/json/JSONLoader.java | 0 .../software/bluelib/json/JSONMerger.java | 0 .../mixin/variant/LivingEntityMixin.java | 4 +- .../utils/conversion/CaseConverterUtils.java | 0 .../utils/conversion/MathConverterUtils.java | 6 +- .../bluelib/utils/logging/BaseLogLevel.java | 0 .../bluelib/utils/logging/BaseLogger.java | 25 +- .../logging/DefaultLogColorProvider.java | 0 .../bluelib/utils/logging/LoggerConfig.java | 0 .../bluelib/utils/math/AlgebraicUtils.java | 0 .../bluelib/utils/math/GeometricUtils.java | 0 .../bluelib/utils/math/MatrixUtils.java | 0 .../bluelib/utils/math/MiscUtils.java | 0 .../bluelib/utils/math/RandomGenUtils.java | 0 .../bluelib/utils/math/StatisticalUtils.java | 0 .../bluelib/utils/minecraft/ChunkUtils.java | 0 .../bluelib/utils/variant/ParameterUtils.java | 2 +- .../src/main/resources/bluelib.mixins.json | 0 .../src/main/resources/bluelib.png | Bin common/src/main/resources/pack.mcmeta | 6 + fabric/build.gradle | 37 ++ .../main/java/software/bluelib/BlueLib.java | 11 + .../platform/FabricPlatformHelper.java | 24 ++ ...luelib.interfaces.platform.IPlatformHelper | 1 + .../main/resources/bluelib.fabric.mixins.json | 13 + fabric/src/main/resources/fabric.mod.json | 36 ++ .../bluelib/platform/ForgePlatformHelper.java | 26 ++ ...luelib.interfaces.platform.IPlatformHelper | 1 + .../main/resources/bluelib.forge.mixins.json | 12 + gradle.properties | 44 ++ .../wrapper/gradle-wrapper.jar | Bin 43504 -> 43453 bytes .../wrapper/gradle-wrapper.properties | 2 +- NeoForge/gradlew => gradlew | 5 +- NeoForge/gradlew.bat => gradlew.bat | 2 - .../platform/NeoForgePlatformHelper.java | 25 ++ ...luelib.interfaces.platform.IPlatformHelper | 1 + settings.gradle | 61 +++ 133 files changed, 795 insertions(+), 4665 deletions(-) delete mode 100644 Forge/.gitattributes delete mode 100644 Forge/.gitignore delete mode 100644 Forge/changelog.txt delete mode 100644 Forge/gradle.properties delete mode 100644 Forge/gradle/wrapper/gradle-wrapper.jar delete mode 100644 Forge/gradle/wrapper/gradle-wrapper.properties delete mode 100644 Forge/gradlew delete mode 100644 Forge/gradlew.bat delete mode 100644 Forge/settings.gradle delete mode 100644 Forge/src/main/java/software/bluelib/entity/variant/VariantLoader.java delete mode 100644 Forge/src/main/java/software/bluelib/entity/variant/VariantParameter.java delete mode 100644 Forge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java delete mode 100644 Forge/src/main/java/software/bluelib/event/ReloadEventHandler.java delete mode 100644 Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java delete mode 100644 Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java delete mode 100644 Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java delete mode 100644 Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java delete mode 100644 Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java delete mode 100644 Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java delete mode 100644 Forge/src/main/java/software/bluelib/example/event/ClientEvents.java delete mode 100644 Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java delete mode 100644 Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java delete mode 100644 Forge/src/main/java/software/bluelib/example/init/ModEntities.java delete mode 100644 Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java delete mode 100644 Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java delete mode 100644 Forge/src/main/java/software/bluelib/exception/CouldNotLoadJSON.java delete mode 100644 Forge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java delete mode 100644 Forge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java delete mode 100644 Forge/src/main/java/software/bluelib/json/JSONLoader.java delete mode 100644 Forge/src/main/java/software/bluelib/json/JSONMerger.java delete mode 100644 Forge/src/main/java/software/bluelib/utils/ParameterUtils.java delete mode 100644 Forge/src/main/resources/assets/bluelib/animations/dragon.animation.json delete mode 100644 Forge/src/main/resources/assets/bluelib/animations/rex.animation.json delete mode 100644 Forge/src/main/resources/assets/bluelib/geo/dragon.geo.json delete mode 100644 Forge/src/main/resources/assets/bluelib/geo/rex.geo.json delete mode 100644 Forge/src/main/resources/assets/bluelib/lang/en_us.json delete mode 100644 Forge/src/main/resources/assets/bluelib/textures/entity/dragon/bright.png delete mode 100644 Forge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png delete mode 100644 Forge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png delete mode 100644 Forge/src/main/resources/assets/bluelib/textures/entity/rex/green.png delete mode 100644 Forge/src/main/resources/data/bluelib/variant/entity/dragon.json delete mode 100644 Forge/src/main/resources/data/bluelib/variant/entity/rex.json delete mode 100644 Forge/src/main/resources/pack.mcmeta delete mode 100644 NeoForge/.gitignore delete mode 100644 NeoForge/changelog.txt delete mode 100644 NeoForge/gradle.properties delete mode 100644 NeoForge/settings.gradle delete mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java delete mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java delete mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java delete mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java delete mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java delete mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java delete mode 100644 NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java delete mode 100644 NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java delete mode 100644 NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java delete mode 100644 NeoForge/src/main/resources/assets/bluelib/animations/dragon.animation.json delete mode 100644 NeoForge/src/main/resources/assets/bluelib/animations/rex.animation.json delete mode 100644 NeoForge/src/main/resources/assets/bluelib/geo/dragon.geo.json delete mode 100644 NeoForge/src/main/resources/assets/bluelib/geo/rex.geo.json delete mode 100644 NeoForge/src/main/resources/assets/bluelib/lang/en_us.json delete mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png delete mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/bright.png delete mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png delete mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png delete mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png delete mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/rex/green.png delete mode 100644 NeoForge/src/main/resources/bluelib.png delete mode 100644 NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/blue.json delete mode 100644 NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/dragon.json delete mode 100644 NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/pink.json delete mode 100644 NeoForge/src/main/resources/data/bluelib/variant/entity/rex/rex.json delete mode 100644 NeoForge/src/main/resources/pack.mcmeta create mode 100644 build.gradle create mode 100644 buildSrc/build.gradle create mode 100644 buildSrc/src/main/groovy/bluelib-common.gradle create mode 100644 buildSrc/src/main/groovy/bluelib-loader.gradle create mode 100644 common/build.gradle create mode 100644 common/src/main/java/software/bluelib/BlueLibCommon.java create mode 100644 common/src/main/java/software/bluelib/BlueLibConstants.java rename {NeoForge => common}/src/main/java/software/bluelib/entity/variant/VariantLoader.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/entity/variant/VariantParameter.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/event/ReloadEventHandler.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java (100%) create mode 100644 common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java rename {NeoForge => common}/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/json/JSONLoader.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/json/JSONMerger.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/logging/BaseLogger.java (87%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/logging/LoggerConfig.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/math/GeometricUtils.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/math/MatrixUtils.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/math/MiscUtils.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/math/RandomGenUtils.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/math/StatisticalUtils.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java (100%) rename {NeoForge => common}/src/main/java/software/bluelib/utils/variant/ParameterUtils.java (100%) rename {NeoForge => common}/src/main/resources/bluelib.mixins.json (100%) rename {Forge => common}/src/main/resources/bluelib.png (100%) create mode 100644 common/src/main/resources/pack.mcmeta create mode 100644 fabric/build.gradle create mode 100644 fabric/src/main/java/software/bluelib/BlueLib.java create mode 100644 fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java create mode 100644 fabric/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper create mode 100644 fabric/src/main/resources/bluelib.fabric.mixins.json create mode 100644 fabric/src/main/resources/fabric.mod.json create mode 100644 forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java create mode 100644 forge/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper create mode 100644 forge/src/main/resources/bluelib.forge.mixins.json create mode 100644 gradle.properties rename {NeoForge/gradle => gradle}/wrapper/gradle-wrapper.jar (78%) rename {NeoForge/gradle => gradle}/wrapper/gradle-wrapper.properties (94%) rename NeoForge/gradlew => gradlew (98%) rename NeoForge/gradlew.bat => gradlew.bat (98%) create mode 100644 neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java create mode 100644 neoforge/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore index d2091a56..91829bde 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,29 @@ replay_pid* # Default ignored files .idea/* +# BuildSrc +buildSrc/build/* +buildSrc/.gradle/* + +# Common +common/build/* +common/.gradle/* +common/out/* + +# Fabric +fabric/build/* +fabric/.gradle/* +fabric/runs/* +fabric/run/* + +# Forge +forge/build/* +forge/.gradle/* +forge/runs/* +forge/run/* + +# Neoforge +neoforge/build/* +neoforge/.gradle/* +neoforge/runs/* +neoforge/run/* diff --git a/Forge/.gitattributes b/Forge/.gitattributes deleted file mode 100644 index f811f6ae..00000000 --- a/Forge/.gitattributes +++ /dev/null @@ -1,5 +0,0 @@ -# Disable autocrlf on generated files, they always generate with LF -# Add any extra files or paths here to make git stop saying they -# are changed when only line endings change. -src/generated/**/.cache/cache text eol=lf -src/generated/**/*.json text eol=lf diff --git a/Forge/.gitignore b/Forge/.gitignore deleted file mode 100644 index 12f86447..00000000 --- a/Forge/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# eclipse -bin -*.launch -.settings -.metadata -.classpath -.project - -# idea -out -*.ipr -*.iws -*.iml -.idea - -# gradle -build -.gradle - -# other -eclipse -run - -# Files from Forge MDK -forge*changelog.txt diff --git a/Forge/build.gradle b/Forge/build.gradle index a60227c4..f2919988 100644 --- a/Forge/build.gradle +++ b/Forge/build.gradle @@ -1,122 +1,87 @@ plugins { - id 'eclipse' - id 'idea' - id 'maven-publish' + id 'bluelib-loader' id 'net.minecraftforge.gradle' version '[6.0.24,6.2)' - id 'org.spongepowered.mixin' version '0.7.+' + id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' } - -version = mod_version -group = mod_group_id - -repositories { - mavenLocal() - maven { - url "https://cursemaven.com" - } - mavenCentral() -} - base { - archivesName = "${mod_id}-forge-${minecraft_version}" + archivesName = "${mod_name}-forge-${minecraft_version}-${version}" +} +mixin { + config("${mod_id}.mixins.json") + config("${mod_id}.forge.mixins.json") } -java.toolchain.languageVersion = JavaLanguageVersion.of(java_version) - -println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" minecraft { - mappings channel: mapping_channel, version: mapping_version - reobf = false - copyIdeResources = true + mappings channel: 'official', version: minecraft_version - runs { - configureEach { - workingDirectory project.file('run') + copyIdeResources = true //Calls processResources when in dev - property 'forge.logging.markers', 'REGISTRIES' + reobf = false // Forge 1.20.6+ uses official mappings at runtime, so we shouldn't reobf from official to SRG - property 'forge.logging.console.level', 'debug' - } + // Automatically enable forge AccessTransformers if the file exists + // This location is hardcoded in Forge and can not be changed. + // https://github.com/MinecraftForge/MinecraftForge/blob/be1698bb1554f9c8fa2f58e32b9ab70bc4385e60/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java#L123 + // Forge still uses SRG names during compile time, so we cannot use the common AT's + def at = file('src/main/resources/META-INF/accesstransformer.cfg') + if (at.exists()) { + accessTransformer = at + } + runs { client { - property 'forge.enabledGameTestNamespaces', mod_id + workingDirectory file('runs/client') + ideaModule "${rootProject.name}.${project.name}.main" + taskName 'Client' mods { - geckolib { + modClientRun { source sourceSets.main } } } server { - property 'forge.enabledGameTestNamespaces', mod_id - args '--nogui' - } - - gameTestServer { - property 'forge.enabledGameTestNamespaces', mod_id + workingDirectory file('runs/server') + ideaModule "${rootProject.name}.${project.name}.main" + taskName 'Server' + mods { + modServerRun { + source sourceSets.main + } + } } data { - workingDirectory project.file('run-data') - + workingDirectory file('runs/data') + ideaModule "${rootProject.name}.${project.name}.main" args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') + taskName 'Data' + mods { + modDataRun { + source sourceSets.main + } + } } } } -sourceSets.main.resources { srcDir 'src/generated/resources' } +sourceSets.main.resources.srcDir 'src/generated/resources' dependencies { minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" - //compileOnly fg.deobf("software.bernie.geckolib:geckolib-forge-${minecraft_version}:${geckolib_version}") - //runtimeOnly fg.deobf("software.bernie.geckolib:geckolib-forge-${minecraft_version}:${geckolib_version}") - runtimeOnly "curse.maven:geckolib-388172:${geckolib_file}" - compileOnly "curse.maven:geckolib-388172:${geckolib_file}" - implementation('net.sf.jopt-simple:jopt-simple:5.0.4') { version { strictly '5.0.4' } } -} + annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT:processor") -tasks.named('processResources', ProcessResources).configure { - def replaceProperties = [ - minecraft_version: minecraft_version, - minecraft_version_range: minecraft_version_range, - forge_version: forge_version, - forge_version_range: forge_version_range, - loader_version_range: loader_version_range, - mod_id: mod_id, - mod_name: mod_name, - mod_license: mod_license, - mod_version: mod_version, - mod_authors: mod_authors, - mod_description: mod_description, - ] - inputs.properties replaceProperties - - filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) { - expand replaceProperties + [project: project] - } + // Forge's hack fix + implementation('net.sf.jopt-simple:jopt-simple:5.0.4') { version { strictly '5.0.4' } } } -tasks.named('jar', Jar).configure { - manifest { - attributes([ - 'Specification-Title' : mod_id, - 'Specification-Vendor' : mod_authors, - 'Specification-Version' : mod_version, - 'Implementation-Title' : project.name, - 'Implementation-Version' : project.jar.archiveVersion, - 'Implementation-Vendor' : mod_authors - ]) +publishing { + publications { + mavenJava(MavenPublication) { + fg.component(it) + } } } -tasks.withType(JavaCompile).configureEach { - options.encoding = 'UTF-8' -} - -eclipse { - synchronizationTasks 'genEclipseRuns' -} - sourceSets.each { def dir = layout.buildDirectory.dir("sourcesSets/$it.name") it.output.resourcesDir = dir diff --git a/Forge/changelog.txt b/Forge/changelog.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/Forge/gradle.properties b/Forge/gradle.properties deleted file mode 100644 index d5604c0f..00000000 --- a/Forge/gradle.properties +++ /dev/null @@ -1,25 +0,0 @@ -org.gradle.jvmargs=-Xmx3G -org.gradle.daemon=false - -## Environment Properties - -minecraft_version=1.21 -minecraft_version_range=[1.20,1.22) -forge_version=51.0.33 -forge_version_range=[0,) -loader_version_range=[0,) -mapping_channel=official -mapping_version=1.21 -geckolib_version=4.5.8 -geckolib_file=5605712 -java_version=21 - -## Mod Properties - -mod_id=bluelib -mod_name=BlueLib -mod_license=MIT License -mod_version=1.0.0 -mod_group_id=software.bluelib -mod_authors=Dan, Aram -mod_description=BlueLib is an All round Minecraft mod library that offers data-driven features, allowing users to implement and customize its features with full freedom. \nIt supports both Resource and Datapacks, ensuring seamless integration and flexibility. \ No newline at end of file diff --git a/Forge/gradle/wrapper/gradle-wrapper.jar b/Forge/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index c1962a79e29d3e0ab67b14947c167a862655af9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62076 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 diff --git a/Forge/gradle/wrapper/gradle-wrapper.properties b/Forge/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 54f3c9ac..00000000 --- a/Forge/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Tue Sep 03 15:47:51 SAST 2024 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/Forge/gradlew b/Forge/gradlew deleted file mode 100644 index aeb74cbb..00000000 --- a/Forge/gradlew +++ /dev/null @@ -1,245 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/Forge/gradlew.bat b/Forge/gradlew.bat deleted file mode 100644 index 93e3f59f..00000000 --- a/Forge/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/Forge/settings.gradle b/Forge/settings.gradle deleted file mode 100644 index ba32d060..00000000 --- a/Forge/settings.gradle +++ /dev/null @@ -1,19 +0,0 @@ -pluginManagement { - repositories { - gradlePluginPortal() - maven { - name = 'MinecraftForge' - url = 'https://maven.minecraftforge.net/' - } - } -} - -buildscript { - repositories { - maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } - } -} - -plugins { - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0' -} \ No newline at end of file diff --git a/Forge/src/main/java/software/bluelib/BlueLib.java b/Forge/src/main/java/software/bluelib/BlueLib.java index 1b47ff5e..64ed593c 100644 --- a/Forge/src/main/java/software/bluelib/BlueLib.java +++ b/Forge/src/main/java/software/bluelib/BlueLib.java @@ -2,24 +2,19 @@ package software.bluelib; -import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.loading.FMLEnvironment; -import software.bluelib.example.event.ReloadHandler; -import software.bluelib.example.init.ModEntities; -import software.bluelib.example.proxy.ClientProxy; -import software.bluelib.example.proxy.CommonProxy; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import static software.bluelib.BlueLibConstants.SCHEDULER; + /** * The main class of the {@link BlueLib} mod. *

          @@ -31,8 +26,7 @@ * Key Methods: *

            *
          • {@link #BlueLib()} - Constructs the {@link BlueLib} instance and registers the mod event bus.
          • - *
          • {@link #onLoadComplete(FMLLoadCompleteEvent)} - Handles the event when the mod loading is complete and prints a thank-you message if in developer mode.
          • - *
          • {@link #isDeveloperMode()} - Determines if the mod is running in developer mode.
          • + *
          • {@link #onLoadComplete(FMLLoadCompleteEvent)} - Handles the event when the mod loading is complete.
          • *
          *

          * @@ -41,30 +35,9 @@ * @Co-author All Contributors of BlueLib! * @since 1.0.0 */ -@Mod(BlueLib.MODID) +@Mod(BlueLibConstants.MOD_ID) public class BlueLib { - /** - * A {@link ScheduledExecutorService} used for scheduling tasks, such as printing messages after a delay. - *

          - * This is initialized with a single-threaded pool to handle delayed tasks in a separate thread. - *

          - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - - /** - * The Mod ID for {@link BlueLib}. This serves as a unique identifier for the mod. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - public static final String MODID = "bluelib"; - - public static CommonProxy PROXY = DistExecutor.safeRunForDist(() -> ClientProxy::new, () -> CommonProxy::new); - - // public static final Logger LOGGER = LogUtils.getLogger(); - /** * Constructs a new {@link BlueLib} instance and registers the mod event bus. * @@ -72,70 +45,21 @@ public class BlueLib { * @Co-author Dan * @since 1.0.0 */ - public BlueLib() - { + public BlueLib() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); modEventBus.register(this); - - if (isDeveloperMode()) { - ModEntities.register(modEventBus); - MinecraftForge.EVENT_BUS.register(ReloadHandler.class); - modEventBus.addListener(this::setupComplete); - modEventBus.addListener(this::setupClient); - } - } - - private void setupClient(final FMLClientSetupEvent event) { - event.enqueueWork(() -> { - PROXY.clientInit(); - }); - } - - private void setupComplete(final FMLLoadCompleteEvent event) { - PROXY.postInit(); } /** - * Handles the {@link FMLLoadCompleteEvent}, which is triggered when the mod loading process is complete. - *

          - * If the mod is running in developer mode, it schedules a task to print a thank-you message to the console after a short delay. - *

          + * A {@code public void} that handles the {@link FMLLoadCompleteEvent}, which occurs when the mod finishes loading. * - * @param pEvent {@link FMLLoadCompleteEvent} - The event triggered upon the completion of the mod loading process. + * @param pEvent {@link FMLLoadCompleteEvent} - The event fired after the mod loading process completes. * @author MeAlam * @Co-author Dan * @since 1.0.0 */ @SubscribeEvent public void onLoadComplete(FMLLoadCompleteEvent pEvent) { - if (isDeveloperMode()) { - scheduler.schedule(() -> { - System.out.println(""" - - ************************************************** - * * - * Thank you for using BlueLib! * - * We appreciate your support. * - * * - ************************************************** - """); - scheduler.shutdown(); - }, 3, TimeUnit.SECONDS); - } - } - - /** - * Checks if the mod is running in developer mode. - *

          - * Developer mode is determined by checking if the mod is not running in a production environment. - *

          - * - * @return {@code true} if the mod is running in developer mode, {@code false} otherwise. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - static boolean isDeveloperMode() { - return !FMLEnvironment.production; + BlueLibCommon.init(); } } diff --git a/Forge/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/Forge/src/main/java/software/bluelib/entity/variant/VariantLoader.java deleted file mode 100644 index 3dc0034b..00000000 --- a/Forge/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.entity.variant; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.packs.resources.ResourceManager; -import software.bluelib.interfaces.variant.base.IVariantEntityBase; -import software.bluelib.json.JSONLoader; -import software.bluelib.json.JSONMerger; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * A {@link VariantLoader} class that loads and manages {@link VariantParameter} for entities by merging JSON data from multiple sources. - *

          - * Key Methods: - *

            - *
          • {@link #loadVariants(ResourceLocation, ResourceLocation, MinecraftServer, String)} - Loads and merges variant data from both the main mod and the latest datapack.
          • - *
          • {@link #getVariantsFromEntity(String)} - Retrieves the list of loaded {@link VariantParameter} for a specific entity.
          • - *
          • {@link #getVariantByName(String, String)} - Retrieves a specific {@link VariantParameter} by its name for a given entity.
          • - *
          - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public class VariantLoader implements IVariantEntityBase { - - /** - * A {@link Map} to store loaded {@link VariantParameter} for each entity type. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private static final Map> entityVariantsMap = new HashMap<>(); - - /** - * A {@link JSONLoader} instance to load JSON data. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private static final JSONLoader jsonLoader = new JSONLoader(); - - /** - * A {@link JSONMerger} instance to merge JSON data. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private static final JSONMerger jsonMerger = new JSONMerger(); - - /** - * A {@code void} method that loads and merges variant data from both the Main Mod and the Latest Datapack. - * Parses the merged data into {@link VariantParameter}. - * - * @param pJSONLocationMod {@link ResourceLocation} - The {@link ResourceLocation} of the Mod's JSON data. - * @param pJSONLocationData {@link ResourceLocation} - The {@link ResourceLocation} of the Latest DataPack's JSON data. - * @param pServer {@link MinecraftServer} - The {@link MinecraftServer} instance. - * @param pEntityName {@link String} - The name of the entity whose variants should be cleared before loading new ones. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public static void loadVariants(ResourceLocation pJSONLocationMod, ResourceLocation pJSONLocationData, MinecraftServer pServer, String pEntityName) { - clearVariantsForEntity(pEntityName); - ResourceManager resourceManager = pServer.getResourceManager(); - JsonObject mergedJsonObject = new JsonObject(); - - JsonObject modJson = jsonLoader.loadJson(pJSONLocationMod, resourceManager); - JsonObject dataJson = jsonLoader.loadJson(pJSONLocationData, resourceManager); - - jsonMerger.mergeJsonObjects(mergedJsonObject, modJson); - jsonMerger.mergeJsonObjects(mergedJsonObject, dataJson); - - parseVariants(mergedJsonObject); - } - - /** - * A {@code void} method that clears variants for a specific entity type from the map. - * - * @param pEntityName {@link String} - The name of the entity whose variants should be cleared. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - private static void clearVariantsForEntity(String pEntityName) { - entityVariantsMap.remove(pEntityName); - } - - /** - * A {@code void} method that parses the merged JSON data and converts it into {@link VariantParameter} instances. - * - * @param pJsonObject {@link JsonObject} - The merged {@link JsonObject} containing variant data. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - private static void parseVariants(JsonObject pJsonObject) { - for (Map.Entry entry : pJsonObject.entrySet()) { - String entityName = entry.getKey(); - JsonArray textureArray = entry.getValue().getAsJsonArray(); - - List variantList = entityVariantsMap.computeIfAbsent(entityName, k -> new ArrayList<>()); - - for (JsonElement variant : textureArray) { - VariantParameter newVariant = getEntityVariant(entityName, variant.getAsJsonObject()); - - boolean variantExists = variantList.stream() - .anyMatch(v -> v.equals(newVariant)); - - if (!variantExists) { - variantList.add(newVariant); - } - } - } - } - - /** - * A {@link VariantParameter} method that creates a new {@link VariantParameter} instance from a JSON object. - * - * @param pJsonKey {@link String} - The key associated with this variant. - * @param pJsonObject {@link JsonObject} - The {@link JsonObject} containing the variant data. - * @return A {@link VariantParameter} instance. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - private static VariantParameter getEntityVariant(String pJsonKey, JsonObject pJsonObject) { - return new VariantParameter(pJsonKey, pJsonObject); - } - - /** - * A {@link List} method that retrieves the {@link List} of loaded {@link VariantParameter} - * for a specific entity. - * - * @param pEntityName {@link String} - The name of the entity to retrieve variants for. - * @return A {@link List} of {@link VariantParameter} instances for the specified entity. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public static List getVariantsFromEntity(String pEntityName) { - return entityVariantsMap.getOrDefault(pEntityName, new ArrayList<>()); - } - - /** - * A {@link VariantParameter} method that retrieves a {@link VariantParameter} by its name for a specific entity. - * - * @param pEntityName {@link String} - The name of the entity to retrieve variants for. - * @param pVariantName {@link String} - The name of the variant to retrieve. - * @return The {@link VariantParameter} with the specified name, or {@code null} if not found. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public static VariantParameter getVariantByName(String pEntityName, String pVariantName) { - List variants = getVariantsFromEntity(pEntityName); - for (VariantParameter variant : variants) { - if (variant.getVariantName().equals(pVariantName)) { - return variant; - } - } - return null; - } -} diff --git a/Forge/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/Forge/src/main/java/software/bluelib/entity/variant/VariantParameter.java deleted file mode 100644 index db3d3319..00000000 --- a/Forge/src/main/java/software/bluelib/entity/variant/VariantParameter.java +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.entity.variant; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import software.bluelib.entity.variant.base.ParameterBase; - -import java.util.Map; -import java.util.Set; - -/** - * A {@code VariantParameter} class that represents the parameters associated with a specific variant of an entity. - *

          - * This class extends {@link ParameterBase} to store and manage variant-specific parameters parsed from a JSON object. - *

          - * The class is designed to handle various JSON element types, including {@code JsonPrimitive}, {@code JsonArray}, and {@code JsonObject}. - *

          - * Key Methods: - *
            - *
          • {@link #getJsonKey()} - Retrieves the key of the JSON object that identifies this entity.
          • - *
          • {@link #getVariantName()} - Retrieves the name of the variant.
          • - *
          • {@link #getParameter(String)} - Retrieves the value of a specific parameter by its key.
          • - *
          - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public class VariantParameter extends ParameterBase { - - /** - * A {@link String} that represents the key of the JSON object that identifies this entity. - *

          - * This key is used to map the entity to its corresponding parameters within a {@link JsonObject}. - *

          - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private final String jsonKey; - - /** - * Constructs a new {@code VariantParameter} instance by extracting parameters from a given JSON object. - *

          - * This constructor processes different types of {@link JsonElement} values: - *

            - *
          • {@code JsonPrimitive}: Stored directly as a string.
          • - *
          • {@code JsonArray}: Converts array elements into a single comma-separated string.
          • - *
          • {@code JsonObject}: Converts the nested JSON object to a string representation.
          • - *
          • {@code Other Types}: Stores "null" for unhandled JSON types.
          • - *
          - *

          - * @param pJsonKey {@link String} - The key that identifies this entity within the {@link JsonObject}. - * @param pJsonObject {@link JsonObject} - The {@link JsonObject} containing the variant parameters. - * @throws IllegalArgumentException if {@code pJsonKey} or {@code pJsonObject} is null. - * @see ParameterBase - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public VariantParameter(String pJsonKey, JsonObject pJsonObject) { - if (pJsonKey == null || pJsonObject == null) { - throw new IllegalArgumentException("JSON key and object must not be null"); - } - this.jsonKey = pJsonKey; - Set> entryMap = pJsonObject.entrySet(); - for (Map.Entry entry : entryMap) { - JsonElement element = entry.getValue(); - if (element.isJsonPrimitive()) { - addParameter(entry.getKey(), element.getAsString()); - } else if (element.isJsonArray()) { - StringBuilder arrayValues = new StringBuilder(); - element.getAsJsonArray().forEach(e -> arrayValues.append(e.getAsString()).append(",")); - if (!arrayValues.isEmpty()) { - arrayValues.setLength(arrayValues.length() - 1); - } - addParameter(entry.getKey(), arrayValues.toString()); - } else if (element.isJsonObject()) { - addParameter(entry.getKey(), element.toString()); - } else { - addParameter(entry.getKey(), "null"); - } - } - } - - /** - * A {@link String} method that returns the key of the {@link JsonObject} that identifies this entity. - *

          - * This key is typically used to retrieve or map the entity within a broader data structure. - *

          - * @return The key of the JSON object representing this entity. - * @throws IllegalStateException if the key is unexpectedly null. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public String getJsonKey() { - if (this.jsonKey == null) { - throw new IllegalStateException("JSON key should not be null"); - } - return this.jsonKey; - } - - /** - * A {@link String} method that retrieves the name of the variant. - *

          - * The variant name is expected to be stored under the key {@code "variantName"} in the parameters/JSON Files. - *

          - * @return The name of the variant, or {@code null} if the variant name is not found. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public String getVariantName() { - return getParameter("variantName"); - } - - /** - * A {@link String} method that retrieves the value of a specific parameter by its key. - *

          - * This method looks up the parameter's value within the internal data structure. - *

          - * @param pKey {@link String} - The key of the parameter to retrieve. - * @return The value of the parameter, or {@code null} if the key does not exist. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public String getParameter(String pKey) { - return (String) super.getParameter(pKey); - } -} diff --git a/Forge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/Forge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java deleted file mode 100644 index 2f1af3a1..00000000 --- a/Forge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.entity.variant.base; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -/** - * An {@code Abstract base class} for managing a collection of parameters. - *

          - * Key Methods: - *

            - *
          • {@link #addParameter(String, Object)} - Adds a parameter to the collection.
          • - *
          • {@link #getParameter(String)} - Retrieves a parameter from the collection.
          • - *
          • {@link #removeParameter(String)} - Removes a parameter from the collection.
          • - *
          • {@link #getAllParameters()} - Returns all parameters in the collection.
          • - *
          • {@link #containsParameter(String)} - Checks if a parameter exists by its key.
          • - *
          • {@link #isEmpty()} - Checks if the collection of parameters is empty.
          • - *
          • {@link #clearParameters()} - Clears all parameters from the collection.
          • - *
          • {@link #getParameterCount()} - Returns the number of parameters in the collection.
          • - *
          • {@link #getParameterKeys()} - Returns a set of all parameter keys.
          • - *
          • {@link #getParameterValues()} - Returns a collection of all parameter values.
          • - *
          • {@link #updateParameter(String, Object)} - Updates the value of an existing parameter.
          • - *
          - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public abstract class ParameterBase { - - /** - * A {@link Map} to store parameters as key-value pairs. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private final Map parameters = new HashMap<>(); - - /** - * A {@code void} method to add a parameter to the collection. - * - * @param pKey {@link String} - The key under which the parameter is stored. - * @param pValue {@link Object} - The value of the parameter. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected void addParameter(String pKey, Object pValue) { - parameters.put(pKey, pValue); - } - - /** - * An {@link Object} method to retrieve a parameter from the collection by its key. - * - * @param pKey {@link String} - The key of the parameter to retrieve. - * @return The value associated with the key, or {@code null} if the key does not exist. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected Object getParameter(String pKey) { - return parameters.get(pKey); - } - - /** - * A {@code Void} that removes a parameter from the collection by its key. - * - * @param pKey {@link String} - The key of the parameter to remove. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected void removeParameter(String pKey) { - parameters.remove(pKey); - } - - /** - * A {@link Map} method that returns all parameters in the collection. - * - * @return A {@link Map} containing all parameters. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected Map getAllParameters() { - return new HashMap<>(parameters); - } - - /** - * A {@link Boolean} method that checks if a parameter exists by its key. - * - * @param pKey {@link String} - The key of the parameter to check. - * @return {@code true} if the parameter exists, {@code false} otherwise. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected boolean containsParameter(String pKey) { - return parameters.containsKey(pKey); - } - - /** - * A {@link Boolean} method that checks if the collection of parameters is empty. - * - * @return {@code true} if the collection is empty, {@code false} otherwise. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected boolean isEmpty() { - return parameters.isEmpty(); - } - - /** - * A {@code void} method that clears all parameters from the collection. - * - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected void clearParameters() { - parameters.clear(); - } - - /** - * An {@link Integer} method that returns the number of parameters in the collection. - * - * @return The number of parameters in the collection. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected int getParameterCount() { - return parameters.size(); - } - - /** - * A {@link Set} method that returns a set of all parameter keys. - * - * @return A {@link Set} containing all parameter keys. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected Set getParameterKeys() { - return parameters.keySet(); - } - - /** - * A {@link Collection} method that returns a collection of all parameter values. - * - * @return A {@link Collection} containing all parameter values. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected Collection getParameterValues() { - return parameters.values(); - } - - /** - * A {@code void} method that updates the value of an existing parameter. - * - * @param pKey {@link String} - The key of the parameter to update. - * @param pNewValue {@link Object} - The new value to set for the parameter. - * @throws IllegalArgumentException if the key does not exist. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected void updateParameter(String pKey, Object pNewValue) { - if (parameters.containsKey(pKey)) { - parameters.put(pKey, pNewValue); - } else { - throw new IllegalArgumentException("Key does not exist: " + pKey); - } - } -} diff --git a/Forge/src/main/java/software/bluelib/event/ReloadEventHandler.java b/Forge/src/main/java/software/bluelib/event/ReloadEventHandler.java deleted file mode 100644 index 9da36f9a..00000000 --- a/Forge/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.event; - -import com.google.gson.JsonParseException; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import software.bluelib.entity.variant.VariantLoader; - -/** - * A {@code ReloadEventHandler} class responsible for handling events related to reloading entity variants. - *

          - * This class includes methods for registering entity variants when the server starts. - *

          - *

          - * Key Features: - *

            - *
          • {@link #registerEntityVariants(MinecraftServer, String, String, String, String)} - Registers entity variants from specified locations.
          • - *
          - *

          - * @see VariantLoader - * @see MinecraftServer - * @see ResourceLocation - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public class ReloadEventHandler { - - /** - * A {@code void} method that registers entity variants from specified locations. - *

          - * This method attempts to load variants from both mod and datapack locations, providing status information - * and handling any exceptions that occur during the loading process. - *

          - *

          - * Parameters: - *

            - *
          • {@code pServer} - The server instance of the current world.
          • - *
          • {@code pEntityName} - The entity name to load.
          • - *
          • {@code pModID} - The mod ID used to locate the entity variant resources. (Use your Mod's ID)
          • - *
          • {@code pModPathLocation} - The path location within the mod where variants are stored.
          • - *
          • {@code pDataPathLocation} - The path location within the resource pack where variants are stored.
          • - *
          - *

          - *

          - * Exception Handling: - *

            - *
          • {@code JsonParseException} - Thrown when there is an error parsing the JSON files.
          • - *
          • {@code RuntimeException} - Thrown for unexpected errors during the registration process.
          • - *
          - *

          - * @param pServer {@link MinecraftServer} - The server instance of the current world. - * @param pEntityName {@link String} - The entity name to load. - * @param pModID {@link String} - The mod ID used to locate the entity variant resources. (Use your Mod's ID) - * @param pModPathLocation {@link String} - The path location within the mod where variants are stored. - * @param pDataPathLocation {@link String} - The path location within the datapack where variants are stored. - * @throws JsonParseException if there is an error parsing the JSON files. - * @throws RuntimeException if an unexpected error occurs during the registration process. - * @see MinecraftServer - * @see ResourceLocation - * @see VariantLoader - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - protected static void registerEntityVariants(MinecraftServer pServer, String pEntityName, String pModID, String pModPathLocation, String pDataPathLocation) { - ResourceLocation modLocation = ResourceLocation.fromNamespaceAndPath(pModID, pModPathLocation); - ResourceLocation dataLocation = ResourceLocation.fromNamespaceAndPath(pModID, pDataPathLocation); - try { - VariantLoader.loadVariants(modLocation, dataLocation, pServer, pEntityName); - } catch (JsonParseException pException) { - throw new RuntimeException("Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from Mod with ModID: " + pModID, pException); - } catch (Exception pException) { - throw new RuntimeException("Unexpected error occurred while registering entity variants for " + pEntityName + " from Mod with ModID: " + pModID, pException); - } - } -} diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java deleted file mode 100644 index 56a55393..00000000 --- a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.dragon; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.syncher.EntityDataAccessor; -import net.minecraft.network.syncher.EntityDataSerializers; -import net.minecraft.network.syncher.SynchedEntityData; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.entity.*; -import net.minecraft.world.entity.ai.attributes.AttributeSupplier; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.ServerLevelAccessor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import software.bernie.geckolib.animatable.GeoEntity; -import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; -import software.bernie.geckolib.animation.AnimatableManager; -import software.bernie.geckolib.util.GeckoLibUtil; -import software.bluelib.interfaces.variant.IVariantEntity; -import software.bluelib.utils.ParameterUtils; - -/** - * A {@code DragonEntity} class representing a dragon entity in the game, which extends {@link TamableAnimal} - * and implements {@link IVariantEntity} and {@link GeoEntity}. - *

          - * This class manages the dragon's variant system, its data synchronization, and integrates with the GeckoLib - * animation system. - *

          - * - *

          - * Key Methods: - *

            - *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
          • - *
          • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
          • - *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • - *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • - *
          • {@link #setVariantName(String)} - Sets the variant name of the dragon.
          • - *
          • {@link #getVariantName()} - Retrieves the current variant name of the dragon.
          • - *
          - *

          - * - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public class DragonEntity extends TamableAnimal implements IVariantEntity, GeoEntity { - /** - * Entity data accessor for the variant of the dragon. - *

          - * This is used to store and retrieve the variant data for synchronization between server and client. - *

          - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - public static final EntityDataAccessor VARIANT = SynchedEntityData.defineId(DragonEntity.class, EntityDataSerializers.STRING); - - /** - * The name of the entity. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - protected final String entityName = "dragon"; - - /** - * Constructs a new {@link DragonEntity} instance with the specified entity type and level. - * - * @param pEntityType {@link EntityType} - The type of the entity. - * @param pLevel {@link Level} - The level in which the entity is created. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public DragonEntity(EntityType pEntityType, Level pLevel) { - super(pEntityType, pLevel); - } - - /** - * Defines the synchronized data for this dragon entity, including the variant. - *

          - * This method initializes the {@link EntityDataAccessor} to handle the variant data. - *

          - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder) { - super.defineSynchedData(pBuilder); - pBuilder.define(VARIANT, "normal"); - } - - /** - * Adds custom data to the entity's NBT tag for saving. - *

          - * This method stores the variant name in the NBT data so it can be restored when loading the entity. - *

          - * - * @param pCompound {@link CompoundTag} - The NBT tag to which data should be added. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public void addAdditionalSaveData(@NotNull CompoundTag pCompound) { - super.addAdditionalSaveData(pCompound); - pCompound.putString("Variant", getVariantName()); - } - - /** - * Reads custom data from the entity's NBT tag for loading. - *

          - * This method retrieves the variant name from the NBT data and sets it for the entity. - *

          - * - * @param pCompound {@link CompoundTag} - The NBT tag from which data should be read. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { - super.readAdditionalSaveData(pCompound); - this.setVariantName(pCompound.getString("Variant")); - } - - /** - * Finalizes the spawning of the dragon entity. - *

          - * This method sets up the variant for the entity and connects parameters if needed. - *

          - * - * @param pLevel {@link ServerLevelAccessor} - The level in which the entity is spawned. - * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. - * @param pReason {@link MobSpawnType} - The reason for spawning the entity. - * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. - * @return {@link SpawnGroupData} - Updated spawn data. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { - if (getVariantName() == null || getVariantName().isEmpty()) { - this.setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); - ParameterUtils.ParameterBuilder.forVariant(entityName,this.getVariantName()) - .withParameter("customParameter") - .withParameter("int") - .withParameter("bool") - .withParameter("array") - .connect(); - } - return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); - } - - /** - * Sets the variant name for the dragon entity. - * - * @param pName {@link String} - The name of the variant to set. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public void setVariantName(String pName) { - this.entityData.set(VARIANT, pName); - } - - /** - * Retrieves the current variant name of the dragon entity. - * - * @return {@link String} - The current variant name. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public String getVariantName() { - return this.entityData.get(VARIANT); - } - - /** - * All Code below this Fragment is not Library Related!!! - */ - - private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); - - public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes() - .add(Attributes.MOVEMENT_SPEED, 0.3) - .add(Attributes.MAX_HEALTH, 10) - .add(Attributes.ARMOR, 0) - .add(Attributes.ATTACK_DAMAGE, 3) - .add(Attributes.FOLLOW_RANGE, 16) - .add(Attributes.FLYING_SPEED, 0.3); - } - - @Override - public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { - } - - @Override - public AnimatableInstanceCache getAnimatableInstanceCache() { - return cache; - } - - @Nullable - @Override - public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { - return null; - } - - @Override - public boolean isFood(@NotNull ItemStack pItemStack) { - return false; - } -} diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java deleted file mode 100644 index 49db6249..00000000 --- a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.dragon; - -import net.minecraft.resources.ResourceLocation; -import software.bernie.geckolib.model.GeoModel; -import software.bluelib.BlueLib; - -public class DragonModel extends GeoModel { - - - // Get the Model Location - @Override - public ResourceLocation getModelResource(DragonEntity pObject) { - return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "geo/dragon.geo.json"); - } - - // Get the Texture Location - @Override - public ResourceLocation getTextureResource(DragonEntity pObject) { - return pObject.getTextureLocation(BlueLib.MODID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); - } - - // Get the Animation Location - @Override - public ResourceLocation getAnimationResource(DragonEntity pAnimatable) { - return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "animations/dragon.animation.json"); - } -} diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java deleted file mode 100644 index c770ac48..00000000 --- a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.dragon; - -import net.minecraft.client.renderer.entity.EntityRendererProvider; -import software.bernie.geckolib.renderer.GeoEntityRenderer; - -public class DragonRender extends GeoEntityRenderer { - - // Render the entity - public DragonRender(EntityRendererProvider.Context pRenderManager) { - super(pRenderManager, new DragonModel()); - } -} diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java deleted file mode 100644 index fdd27cb4..00000000 --- a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.rex; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.syncher.EntityDataAccessor; -import net.minecraft.network.syncher.EntityDataSerializers; -import net.minecraft.network.syncher.SynchedEntityData; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.entity.*; -import net.minecraft.world.entity.ai.attributes.AttributeSupplier; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.ServerLevelAccessor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import software.bernie.geckolib.animatable.GeoEntity; -import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; -import software.bernie.geckolib.animation.AnimatableManager; -import software.bernie.geckolib.util.GeckoLibUtil; -import software.bluelib.interfaces.variant.IVariantEntity; -import software.bluelib.utils.ParameterUtils; - -/** - * A {@code RexEntity} class representing a Rex entity in the game, which extends {@link TamableAnimal} - * and implements {@link IVariantEntity} and {@link GeoEntity}. - *

          - * This class manages the Rex's variant system, its data synchronization, and integrates with the GeckoLib - * animation system. - *

          - * - *

          - * Key Methods: - *

            - *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
          • - *
          • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
          • - *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • - *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • - *
          • {@link #setVariantName(String)} - Sets the variant name of the Rex.
          • - *
          • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
          • - *
          - *

          - * - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public class RexEntity extends TamableAnimal implements IVariantEntity, GeoEntity { - /** - * Entity data accessor for the variant of the Rex. - *

          - * This is used to store and retrieve the variant data for synchronization between server and client. - *

          - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - public static final EntityDataAccessor VARIANT = SynchedEntityData.defineId(RexEntity.class, EntityDataSerializers.STRING); - - /** - * The name of the entity. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - protected final String entityName = "rex"; - - /** - * Constructs a new {@link RexEntity} instance with the specified entity type and level. - * - * @param pEntityType {@link EntityType} - The type of the entity. - * @param pLevel {@link Level} - The level in which the entity is created. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public RexEntity(EntityType pEntityType, Level pLevel) { - super(pEntityType, pLevel); - } - - /** - * Defines the synchronized data for this Rex entity, including the variant. - *

          - * This method initializes the {@link EntityDataAccessor} to handle the variant data. - *

          - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder) { - super.defineSynchedData(pBuilder); - pBuilder.define(VARIANT, "normal"); - } - - /** - * Adds custom data to the entity's NBT tag for saving. - *

          - * This method stores the variant name in the NBT data so it can be restored when loading the entity. - *

          - * - * @param pCompound {@link CompoundTag} - The NBT tag to which data should be added. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public void addAdditionalSaveData(@NotNull CompoundTag pCompound) { - super.addAdditionalSaveData(pCompound); - pCompound.putString("Variant", getVariantName()); - } - - /** - * Reads custom data from the entity's NBT tag for loading. - *

          - * This method retrieves the variant name from the NBT data and sets it for the entity. - *

          - * - * @param pCompound {@link CompoundTag} - The NBT tag from which data should be read. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public void readAdditionalSaveData(@NotNull CompoundTag pCompound) { - super.readAdditionalSaveData(pCompound); - this.setVariantName(pCompound.getString("Variant")); - } - - /** - * Finalizes the spawning of the Rex entity. - *

          - * This method sets up the variant for the entity and connects parameters if needed. - *

          - * - * @param pLevel {@link ServerLevelAccessor} - The level in which the entity is spawned. - * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. - * @param pReason {@link MobSpawnType} - The reason for spawning the entity. - * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. - * @return {@link SpawnGroupData} - Updated spawn data. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { - if (getVariantName() == null || getVariantName().isEmpty()) { - this.setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); - ParameterUtils.ParameterBuilder.forVariant(entityName,this.getVariantName()) - .withParameter("customParameter") - .withParameter("int") - .withParameter("bool") - .withParameter("array") - .connect(); - } - return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); - } - - /** - * Sets the variant name for the Rex entity. - * - * @param pName {@link String} - The name of the variant to set. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public void setVariantName(String pName) { - this.entityData.set(VARIANT, pName); - } - - /** - * Retrieves the current variant name of the Rex entity. - * - * @return {@link String} - The current variant name. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public String getVariantName() { - return this.entityData.get(VARIANT); - } - - /** - * All Code below this Fragment is not Library Related!!! - */ - - private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); - - public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes() - .add(Attributes.MOVEMENT_SPEED, 0.3) - .add(Attributes.MAX_HEALTH, 10) - .add(Attributes.ARMOR, 0) - .add(Attributes.ATTACK_DAMAGE, 3) - .add(Attributes.FOLLOW_RANGE, 16) - .add(Attributes.FLYING_SPEED, 0.3); - } - - @Override - public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { - } - - @Override - public AnimatableInstanceCache getAnimatableInstanceCache() { - return cache; - } - - @Nullable - @Override - public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { - return null; - } - - @Override - public boolean isFood(@NotNull ItemStack pItemStack) { - return false; - } -} diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java deleted file mode 100644 index 1e0f85e3..00000000 --- a/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.rex; - -import net.minecraft.resources.ResourceLocation; -import software.bernie.geckolib.model.GeoModel; -import software.bluelib.BlueLib; - -public class RexModel extends GeoModel { - - - // Get the Model Location - @Override - public ResourceLocation getModelResource(RexEntity pObject) { - return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "geo/rex.geo.json"); - } - - // Get the Texture Location - @Override - public ResourceLocation getTextureResource(RexEntity pObject) { - return pObject.getTextureLocation(BlueLib.MODID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); - } - - // Get the Animation Location - @Override - public ResourceLocation getAnimationResource(RexEntity pAnimatable) { - return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "animations/rex.animation.json"); - } -} diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java deleted file mode 100644 index 776c5920..00000000 --- a/Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.rex; - -import net.minecraft.client.renderer.entity.EntityRendererProvider; -import software.bernie.geckolib.renderer.GeoEntityRenderer; - -public class RexRender extends GeoEntityRenderer { - - // Render the entity - public RexRender(EntityRendererProvider.Context pRenderManager) { - super(pRenderManager, new RexModel()); - } -} diff --git a/Forge/src/main/java/software/bluelib/example/event/ClientEvents.java b/Forge/src/main/java/software/bluelib/example/event/ClientEvents.java deleted file mode 100644 index 187fc9ab..00000000 --- a/Forge/src/main/java/software/bluelib/example/event/ClientEvents.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.event; - -import net.minecraft.client.renderer.entity.EntityRenderers; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.common.Mod; -import software.bluelib.BlueLib; -import software.bluelib.example.entity.dragon.DragonRender; -import software.bluelib.example.entity.rex.RexRender; -import software.bluelib.example.init.ModEntities; - -@Mod.EventBusSubscriber(modid = BlueLib.MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) -public class ClientEvents { - - public static void registerRenderers() { - // Register the renderer for all the Entities - EntityRenderers.register(ModEntities.DRAGON.get(), DragonRender::new); - EntityRenderers.register(ModEntities.REX.get(), RexRender::new); - } -} diff --git a/Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java b/Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java deleted file mode 100644 index c45cfb03..00000000 --- a/Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -package software.bluelib.example.event; - -import net.minecraftforge.event.entity.EntityAttributeCreationEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import software.bluelib.BlueLib; -import software.bluelib.example.entity.dragon.DragonEntity; -import software.bluelib.example.entity.rex.RexEntity; -import software.bluelib.example.init.ModEntities; - -@Mod.EventBusSubscriber(modid = BlueLib.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) -public class CommonModEvent { - @SubscribeEvent - public static void onAttributeCreate(EntityAttributeCreationEvent pEvent) { - pEvent.put(ModEntities.DRAGON.get(), DragonEntity.createAttributes().build()); - pEvent.put(ModEntities.REX.get(), RexEntity.createAttributes().build()); - } - } diff --git a/Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java b/Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java deleted file mode 100644 index 24ed12b0..00000000 --- a/Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.event; - -import net.minecraft.server.MinecraftServer; -import net.minecraftforge.event.AddReloadListenerEvent; -import net.minecraftforge.event.server.ServerStartingEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import software.bluelib.BlueLib; -import software.bluelib.event.ReloadEventHandler; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -/** - * A {@code ReloadHandler} class that handles server start and reload events related to entity variants. - *

          - * This class extends {@link ReloadEventHandler} and implements event handling for server starting and reloading, - * ensuring that entity variant data is properly loaded and refreshed. - *

          - * - *

          - * Key Methods: - *

            - *
          • {@link #onServerStart(ServerStartingEvent)} - Handles server starting events to initialize entity variants.
          • - *
          • {@link #onReload(AddReloadListenerEvent)} - Handles reload events to refresh entity variants.
          • - *
          • {@link #LoadEntityVariants(MinecraftServer)} - Loads entity variants from JSON files into the server.
          • - *
          - *

          - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ -public class ReloadHandler extends ReloadEventHandler { - - /** - * The {@link MinecraftServer} instance for the server handling the events. - *

          - * This is initialized when the server starts and used to load entity variants. - *

          - * - * @since 1.0.0 - * @Co-author MeAlam, Dan - */ - private static MinecraftServer server; - - /** - * Handles the server starting event to initialize the {@link MinecraftServer} instance - * and load entity variants. - * - * @param pEvent {@link ServerStartingEvent} - The event triggered when the server starts. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @SubscribeEvent - public static void onServerStart(ServerStartingEvent pEvent) { - server = pEvent.getServer(); - ReloadHandler.LoadEntityVariants(server); - } - - /** - * The {@link ScheduledExecutorService} used to schedule tasks for reloading entity variants. - * - * @since 1.0.0 - * @Co-author MeAlam, Dan - */ - private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - - /** - * Handles the reload event by scheduling a task to reload entity variants. - *

          - * This method schedules the {@code LoadEntityVariants} method to run after a short delay. - *

          - * - * @param pEvent {@link AddReloadListenerEvent} - The event triggered when a reload occurs. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @SubscribeEvent - public static void onReload(AddReloadListenerEvent pEvent) { - if (server != null) { - scheduler.schedule(() -> { - server.execute(() -> { - ReloadHandler.LoadEntityVariants(server); - }); - }, 1, TimeUnit.SECONDS); - } - } - - /** - * The base path for entity variant JSON files. - *

          - * This path is used to locate the files that contain variant data for entities. - *

          - * - * @since 1.0.0 - * @Co-author MeAlam, Dan - */ - private static final String basePath = "variant/entity/"; - - /** - * A {@link List} of entity names for which variants will be loaded. - *

          - * This list defines which entities will have their variants loaded from JSON files. - *

          - * - * @since 1.0.0 - * @Co-author MeAlam, Dan - */ - private static final List entityNames = Arrays.asList("dragon", "rex"); - - /** - * Loads entity variants from JSON files into the {@link MinecraftServer}. - *

          - * This method iterates through the list of entity names, constructs file paths, and registers - * entity variants using the {@link ReloadEventHandler}. - *

          - * - * @param pServer {@link MinecraftServer} - The server on which the entity variants will be loaded. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public static void LoadEntityVariants(MinecraftServer pServer) { - for (String entityName : entityNames) { - String modPath = basePath + entityName + ".json"; - String dataPath = basePath + entityName + "data.json"; - ReloadEventHandler.registerEntityVariants(pServer, entityName, BlueLib.MODID, modPath, dataPath); - } - } -} diff --git a/Forge/src/main/java/software/bluelib/example/init/ModEntities.java b/Forge/src/main/java/software/bluelib/example/init/ModEntities.java deleted file mode 100644 index 6f82f193..00000000 --- a/Forge/src/main/java/software/bluelib/example/init/ModEntities.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.init; - -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.MobCategory; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; -import software.bluelib.BlueLib; -import software.bluelib.example.entity.dragon.DragonEntity; -import software.bluelib.example.entity.rex.RexEntity; - -public class ModEntities { - public static final DeferredRegister> REGISTER = - DeferredRegister.create(ForgeRegistries.ENTITY_TYPES, BlueLib.MODID); - - // List of Entities - public static final RegistryObject> DRAGON = - REGISTER.register("example_one", () -> EntityType.Builder.of(DragonEntity::new, MobCategory.AMBIENT) - .setShouldReceiveVelocityUpdates(true) - .setTrackingRange(64) - .setUpdateInterval(3) - .fireImmune() - .sized(0.6f, 1.8f) - .build(ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "dragon").toString())); - - public static final RegistryObject> REX = - REGISTER.register("example_two", () -> EntityType.Builder.of(RexEntity::new, MobCategory.AMBIENT) - .setShouldReceiveVelocityUpdates(true) - .setTrackingRange(64) - .setUpdateInterval(3) - .fireImmune() - .sized(0.6f, 1.8f) - .build(ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "rex").toString())); - - public static void register(IEventBus eventBus) { - REGISTER.register(eventBus); - } -} diff --git a/Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java b/Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java deleted file mode 100644 index 4b0778aa..00000000 --- a/Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java +++ /dev/null @@ -1,19 +0,0 @@ -package software.bluelib.example.proxy; - -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.common.Mod; -import software.bluelib.BlueLib; -import software.bluelib.example.event.ClientEvents; - -@Mod.EventBusSubscriber(modid = BlueLib.MODID, value = Dist.CLIENT) -public class ClientProxy extends CommonProxy { - - @Override - public void postInit() {} - - @Override - public void clientInit() { - super.clientInit(); - ClientEvents.registerRenderers(); - } -} diff --git a/Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java b/Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java deleted file mode 100644 index ad07e974..00000000 --- a/Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java +++ /dev/null @@ -1,13 +0,0 @@ -package software.bluelib.example.proxy; - -import net.minecraftforge.fml.common.Mod; -import software.bluelib.BlueLib; - -@Mod.EventBusSubscriber(modid = BlueLib.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) -public class CommonProxy { - - public void postInit() {} - - public void clientInit() { - } -} diff --git a/Forge/src/main/java/software/bluelib/exception/CouldNotLoadJSON.java b/Forge/src/main/java/software/bluelib/exception/CouldNotLoadJSON.java deleted file mode 100644 index c93d1015..00000000 --- a/Forge/src/main/java/software/bluelib/exception/CouldNotLoadJSON.java +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.exception; - -/** - * A {@code RuntimeException} that represents an error when a JSON file could not be loaded. - *

          - * This exception provides additional context by including the {@link #getResourceId()} of the JSON file that failed to load. - *

          - *

          - * Key Features: - *

            - *
          • {@link #getResourceId()} - Retrieves the ID of the resource that could not be loaded.
          • - *
          - *

          - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public class CouldNotLoadJSON extends RuntimeException { - - /** - * A {@link String} that represents the ID of the resource that could not be loaded. - *

          - * This ID is used to provide additional context for the error. - *

          - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private final String resourceId; - - /** - * Constructs a new {@code CouldNotLoadJSON} exception with the specified detail message and resource ID. - *

          - * The detail message provides information about the nature of the error, while the resource ID indicates - * which specific resource could not be loaded. - *

          - * - * @param pMessage {@link String} - The detail message explaining the reason for the exception. - * @param pResourceId {@link String} - The ID of the resource that could not be loaded. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public CouldNotLoadJSON(String pMessage, String pResourceId) { - super(pMessage); - this.resourceId = pResourceId; - } - - /** - * A {@link String} that retrieves the resource ID of the JSON file that could not be loaded. - *

          - * This method provides access to the ID of the resource that caused the exception. - *

          - * - * @return The resource ID as a {@link String}. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public String getResourceId() { - return resourceId; - } -} diff --git a/Forge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java b/Forge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java deleted file mode 100644 index 5273ec4e..00000000 --- a/Forge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.interfaces.variant; - -import software.bluelib.interfaces.variant.base.IVariantEntityBase; - -import java.util.List; -import java.util.Random; - -/** - * An {@code Interface} representing an entity that supports multiple variants. - *

          - * This interface extends {@link IVariantEntityBase} to include methods specific to handling entity variants, including - * random selection of variants. - *

          - *

          - * Key Methods: - *

            - *
          • {@link #getRandomVariant(List, String)} - Retrieves a random variant name from a provided list or defaults if the list is empty.
          • - *
          - *

          - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public interface IVariantEntity extends IVariantEntityBase { - - /** - * A {@link Random} instance used for generating random variants. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - Random random = new Random(); - - /** - * A {@link String} that selects a random variant name from the provided list of variant names. - *

          - * This method uses the {@link Random} to pick a random variant from the list. If the list is empty, the default - * variant name is returned. - *

          - * - * @param pVariantNamesList {@link List} - A {@link List} of variant names available for the entity. - * @param pDefaultVariant {@link String} - The default variant name to return if {@code pVariantNamesList} is empty. - * @return A random variant name from the list, or the default variant if the list is empty. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - default String getRandomVariant(List pVariantNamesList, String pDefaultVariant) { - List spawnableVariants = List.copyOf(pVariantNamesList); - if (!spawnableVariants.isEmpty()) { - return spawnableVariants.get(random.nextInt(spawnableVariants.size())); - } - return pDefaultVariant; - } -} diff --git a/Forge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/Forge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java deleted file mode 100644 index baecfe62..00000000 --- a/Forge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.interfaces.variant.base; - -import net.minecraft.resources.ResourceLocation; -import software.bluelib.entity.variant.VariantLoader; -import software.bluelib.entity.variant.VariantParameter; - -import java.util.List; -import java.util.stream.Collectors; - -/** - * A {@code base Interface} providing fundamental methods for handling entity variants. - *

          - * This interface defines methods for retrieving texture locations and variant names associated with entities. - *

          - *

          - * Key Methods: - *

            - *
          • {@link #getTextureLocation(String, String)} - Retrieves the {@link ResourceLocation} for the entity texture.
          • - *
          • {@link #getEntityVariants(String)} - Retrieves a {@link List} of variant names for a specified entity.
          • - *
          - *

          - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public interface IVariantEntityBase { - - /** - * A {@link ResourceLocation} that points to the texture of an entity. - *

          - * This method constructs a {@link ResourceLocation} using the provided mod ID and texture path. - *

          - * - * @param pModId {@link String} - The mod ID used to locate the texture. - * @param pPath {@link String} - The path to the texture within the mod. - * @return A {@link ResourceLocation} pointing to the specified texture. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - default ResourceLocation getTextureLocation(String pModId, String pPath) { - return ResourceLocation.fromNamespaceAndPath(pModId, pPath); - } - - /** - * A {@link List} of variant names associated with the specified entity. - *

          - * This method retrieves the names of all variants for a given entity by querying the {@link VariantLoader}. - *

          - * - * @param pEntityName {@link String} - The name of the entity whose variant names are to be retrieved. - * @return A {@link List} containing the names of variants associated with the specified entity. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - default List getEntityVariants(String pEntityName) { - List variants = VariantLoader.getVariantsFromEntity(pEntityName); - return variants.stream() - .map(VariantParameter::getVariantName) - .collect(Collectors.toList()); - } -} diff --git a/Forge/src/main/java/software/bluelib/json/JSONLoader.java b/Forge/src/main/java/software/bluelib/json/JSONLoader.java deleted file mode 100644 index f046903c..00000000 --- a/Forge/src/main/java/software/bluelib/json/JSONLoader.java +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.json; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.Resource; -import net.minecraft.server.packs.resources.ResourceManager; -import software.bluelib.exception.CouldNotLoadJSON; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.Optional; - -/** - * The {@code JSONLoader} class is responsible for loading and parsing JSON data from - * resources defined by {@link ResourceLocation} within a Minecraft mod environment.
          - * It uses the {@link Gson} library to convert JSON strings into {@link JsonObject} instances. - *

          - * Key methods: - *

            - *
          • {@link #loadJson(ResourceLocation, ResourceManager)} - Loads a JSON resource.
          • - *
          - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public class JSONLoader { - - /** - * A {@link Gson} instance for parsing JSON data. - * @Co-author MeAlam, Dan - */ - private static final Gson gson = new Gson(); - - /** - * A {@link JsonObject} that loads JSON data from a {@link ResourceLocation}.
          - * This method is typically used to load configuration files or other JSON-based resources - * in a Minecraft mod environment. - *

          - * @param pResourceLocation {@link ResourceLocation} - The {@link ResourceLocation} of the JSON resource. - * @param pResourceManager {@link ResourceManager} - The {@link ResourceManager} to load the resource. - * @return The loaded {@link JsonObject}. - * @throws CouldNotLoadJSON If the JSON could not be loaded. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager pResourceManager) throws CouldNotLoadJSON { - try { - Optional resource = pResourceManager.getResource(pResourceLocation); - - if (resource.isEmpty()) { - return new JsonObject(); - } - - try (InputStream inputStream = resource.get().open(); - InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { - - return gson.fromJson(reader, JsonObject.class); - } - } catch (IOException pException) { - throw new CouldNotLoadJSON("Failed to load JSON from resource: " + pResourceLocation + ". Error: " + pException.getMessage(), pResourceLocation.toString()); - } - } -} diff --git a/Forge/src/main/java/software/bluelib/json/JSONMerger.java b/Forge/src/main/java/software/bluelib/json/JSONMerger.java deleted file mode 100644 index 918ed2cf..00000000 --- a/Forge/src/main/java/software/bluelib/json/JSONMerger.java +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.json; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import java.util.Map; - -/** - * A {@code Class} responsible for merging JSON data from a source {@link JsonObject} into a target {@link JsonObject}. - *

          - * This class provides functionality to combine JSON data where overlapping keys result in merging arrays, - * and non-overlapping keys are simply added to the target. - *

          - * - *

          - * Key Methods: - *

            - *
          • {@link #mergeJsonObjects(JsonObject, JsonObject)} - Merges the data from the source JSON object into the target JSON object.
          • - *
          - *

          - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public class JSONMerger { - - /** - * Merges data from a source {@link JsonObject} into a target {@link JsonObject}. - *

          - * If the target JSON object already contains a key present in the source JSON object, the values are merged if they are arrays. - * Otherwise, the source value is added to the target JSON object. - *

          - * - * @param pTarget {@link JsonObject} - The target {@link JsonObject} to merge data into. This object will be modified by adding or updating its values. - * @param pSource {@link JsonObject} - The source {@link JsonObject} to merge data from. This object is not modified by the operation. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { - for (Map.Entry entry : pSource.entrySet()) { - if (pTarget.has(entry.getKey())) { - JsonElement targetElement = pTarget.get(entry.getKey()); - JsonElement sourceElement = entry.getValue(); - - if (targetElement.isJsonArray() && sourceElement.isJsonArray()) { - JsonArray targetArray = targetElement.getAsJsonArray(); - JsonArray sourceArray = sourceElement.getAsJsonArray(); - - for (JsonElement element : sourceArray) { - targetArray.add(element); - } - } else { - pTarget.add(entry.getKey(), sourceElement); - } - } else { - pTarget.add(entry.getKey(), entry.getValue()); - } - } - } -} diff --git a/Forge/src/main/java/software/bluelib/utils/ParameterUtils.java b/Forge/src/main/java/software/bluelib/utils/ParameterUtils.java deleted file mode 100644 index 3994cdf5..00000000 --- a/Forge/src/main/java/software/bluelib/utils/ParameterUtils.java +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.utils; - -import software.bluelib.entity.variant.VariantParameter; -import software.bluelib.entity.variant.VariantLoader; - -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; - -/** - * A {@code Class} for managing custom parameters associated with entity variants. - *

          - * This class provides methods to retrieve custom parameters for variants and allows - * for building and connecting parameters to specific variants using the {@link ParameterBuilder}. - *

          - *

          - * Key Methods: - *

            - *
          • {@link #getParameter(String, String)} - Retrieves the value of a custom parameter for a specific variant.
          • - *
          - *

          - * Nested Classes: - *
            - *
          • {@link ParameterBuilder} - A builder class for creating and associating custom parameters with a specific variant.
          • - *
          - *

          - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ -public class ParameterUtils { - - /** - * A {@link Map} holding custom parameters for each variant. - *

          - * The outer map's key is the variant's name, and the inner map contains key-value pairs - * of custom parameters for that variant. - *

          - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private static final Map> variantParametersMap = new HashMap<>(); - - /** - * Retrieves the value of a custom parameter for a specific variant. - *

          - * If the parameter is not found, "null" is returned. - *

          - * - * @param pVariantName {@link String} - The name of the variant. - * @param pParameterKey {@link String} - The key of the parameter to retrieve. - * @return The value of the custom parameter for the specified variant. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public static String getParameter(String pVariantName, String pParameterKey) { - return variantParametersMap.getOrDefault(pVariantName, new HashMap<>()).getOrDefault(pParameterKey, "null"); - } - - /** - * A {@code Builder} class for creating and associating custom parameters with a specific variant. - *

          - * This class allows chaining methods to build and connect parameters to a variant. - *

          - * - *

          - * Key Methods: - *

            - *
          • {@link #forVariant(String, String)} - Creates a new instance of {@link ParameterBuilder} for the specified entity and variant.
          • - *
          • {@link #withParameter(String)} - Adds a parameter to the parameters map with a default value of "null".
          • - *
          • {@link #connect()} - Adds parameters to the variant and updates the static {@link VariantParameter} with these parameters.
          • - *
          - *

          - *

          - * **Note:** The "null" value is used only if the parameter is not specified in the JSON files. - *

          - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public static class ParameterBuilder { - /** - * The name of the variant for which parameters are being built. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private final String variantName; - - /** - * The name of the entity for which parameters are being built. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private final String entityName; - - /** - * A {@link Map} to store parameters for the variant. - *

          - * Each key-value pair represents a parameter name and its default value. - *

          - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private final Map parameters = new HashMap<>(); - - /** - * Constructor to initialize the builder with a specific entity name and variant name. - * - * @param pEntityName {@link String} - The name of the entity. - * @param pVariantName {@link String} - The name of the variant. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - private ParameterBuilder(String pEntityName, String pVariantName) { - this.variantName = pVariantName; - this.entityName = pEntityName; - } - - /** - * Creates a new instance of {@link ParameterBuilder} for the specified entity and variant. - * - * @param pEntityName {@link String} - The name of the entity. - * @param pVariantName {@link String} - The name of the variant. - * @return A new instance of {@link ParameterBuilder}. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public static ParameterBuilder forVariant(String pEntityName, String pVariantName) { - return new ParameterBuilder(pEntityName, pVariantName); - } - - /** - * Adds a parameter to the parameters map with a default value of "null".
          - *

          - * **Note:** The "null" value is used only if the parameter is not specified in the JSON files. - *

          - * - * @param pParameter {@link String} - The key of the parameter to add. - * @return The current instance of {@link ParameterBuilder} for method chaining. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public ParameterBuilder withParameter(String pParameter) { - parameters.put(pParameter, "null"); - return this; - } - - /** - * Adds a parameter to the parameters map with a specified default value. - *

          - * Connects the parameters built with this builder to the specified variant. - * Updates the static {@link VariantParameter} with the parameters for the specified variant. - *

          - * - * @return The current instance of {@link ParameterBuilder} for method chaining. - * @throws NoSuchElementException if the specified variant is not found for the entity. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - public ParameterBuilder connect() { - VariantParameter variant = VariantLoader.getVariantByName(entityName, variantName); - if (variant != null) { - Map updatedParameters = new HashMap<>(); - for (String key : parameters.keySet()) { - updatedParameters.put(key, variant.getParameter(key)); - } - variantParametersMap.put(variantName, updatedParameters); - } else { - throw new NoSuchElementException("Variant '" + variantName + "' not found for entity '" + entityName + "'"); - } - return this; - } - } -} diff --git a/Forge/src/main/resources/META-INF/mods.toml b/Forge/src/main/resources/META-INF/mods.toml index cf09a122..4ce9fb30 100644 --- a/Forge/src/main/resources/META-INF/mods.toml +++ b/Forge/src/main/resources/META-INF/mods.toml @@ -1,25 +1,25 @@ modLoader="javafml" -loaderVersion="${loader_version_range}" -license="${mod_license}" +loaderVersion="${forge_loader_version_range}" +license="${license}" [[mods]] modId="${mod_id}" -version="${mod_version}" +version="${version}" displayName="${mod_name}" displayURL="https://mealam1.github.io/BlueLib/" logoFile="bluelib.png" credits="Anyone who contributed to the Source Code of BlueLib!" -authors="${mod_authors}" -description='''${mod_description}''' +authors="${mod_author}" +description='''${description}''' -[[dependencies.${mod_id}]] +[[dependencies.bluelib]] modId="forge" mandatory=true versionRange="${forge_version_range}" ordering="NONE" side="BOTH" -[[dependencies.${mod_id}]] +[[dependencies.bluelib]] modId="minecraft" mandatory=true versionRange="${minecraft_version_range}" diff --git a/Forge/src/main/resources/assets/bluelib/animations/dragon.animation.json b/Forge/src/main/resources/assets/bluelib/animations/dragon.animation.json deleted file mode 100644 index 0b02f765..00000000 --- a/Forge/src/main/resources/assets/bluelib/animations/dragon.animation.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "format_version": "1.8.0", - "animations": { - "test": { - "loop": true, - "bones": { - "Body": { - "rotation": { - "vector": [-20.44582, 11.73507, -4.3361], - "easing": "linear" - }, - "position": { - "vector": [0, -1, 0], - "easing": "linear" - } - }, - "leftleg": { - "rotation": { - "vector": [0, 22.5, 0], - "easing": "linear" - } - }, - "rightleg": { - "rotation": { - "vector": [0, -22.5, 0], - "easing": "linear" - } - }, - "rightwing1": { - "rotation": { - "vector": [0, 0, -20], - "easing": "linear" - } - }, - "leftwing": { - "rotation": { - "vector": [0, 0, -10], - "easing": "linear" - } - }, - "leftwing1": { - "rotation": { - "vector": [0, 0, 30], - "easing": "linear" - } - }, - "neck": { - "rotation": { - "vector": [-40, 0, 0], - "easing": "linear" - } - }, - "Head": { - "rotation": { - "vector": [72.5, 0, 0], - "easing": "linear" - } - } - } - } - }, - "geckolib_format_version": 2 -} \ No newline at end of file diff --git a/Forge/src/main/resources/assets/bluelib/animations/rex.animation.json b/Forge/src/main/resources/assets/bluelib/animations/rex.animation.json deleted file mode 100644 index 5d8891b4..00000000 --- a/Forge/src/main/resources/assets/bluelib/animations/rex.animation.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "format_version": "1.8.0", - "animations": { - "animation2": { - "loop": true, - "bones": { - "body": { - "rotation": { - "vector": [0, -15, 0] - } - }, - "tail2": { - "rotation": { - "vector": [0, 20, 0] - } - }, - "tail3": { - "rotation": { - "vector": [0, 20, 0] - } - }, - "tail4": { - "rotation": { - "vector": [0, 20, 0] - } - }, - "tail5": { - "rotation": { - "vector": [0, 20, 0] - } - }, - "tail6": { - "rotation": { - "vector": [0, 20, 0] - } - }, - "neck": { - "rotation": { - "vector": [0, -2.5, 0] - } - }, - "head": { - "rotation": { - "vector": [0, -20, 0] - } - } - } - } - }, - "geckolib_format_version": 2 -} \ No newline at end of file diff --git a/Forge/src/main/resources/assets/bluelib/geo/dragon.geo.json b/Forge/src/main/resources/assets/bluelib/geo/dragon.geo.json deleted file mode 100644 index 8f038886..00000000 --- a/Forge/src/main/resources/assets/bluelib/geo/dragon.geo.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "format_version": "1.12.0", - "minecraft:geometry": [ - { - "description": { - "identifier": "geometry.unknown", - "texture_width": 64, - "texture_height": 64, - "visible_bounds_width": 4, - "visible_bounds_height": 2.5, - "visible_bounds_offset": [0, 0.75, 0] - }, - "bones": [ - { - "name": "Body", - "pivot": [-0.16667, 5, -1], - "cubes": [ - {"origin": [-2, 4, 1], "size": [4, 2, 4], "uv": [17, 10]}, - {"origin": [-3, 4, -4], "size": [6, 2, 5], "uv": [0, 14]} - ] - }, - { - "name": "leftleg", - "parent": "Body", - "pivot": [1.5, 5, 5], - "cubes": [ - {"origin": [1.5, 3, 4.5], "size": [0, 4, 3], "pivot": [1.5, 5, 6], "rotation": [90, 0, 90], "uv": [0, 0]} - ] - }, - { - "name": "rightleg", - "parent": "Body", - "pivot": [-1.5, 5, 5], - "cubes": [ - {"origin": [-1.5, 3, 4.5], "size": [0, 4, 3], "pivot": [-1.5, 5, 6], "rotation": [90, 0, -90], "uv": [0, 0], "mirror": true} - ] - }, - { - "name": "rightwing", - "parent": "Body", - "pivot": [-2.5, 5, -3.5], - "cubes": [ - {"origin": [-10, 5, -5], "size": [7, 0, 7], "uv": [-7, 28], "mirror": true} - ] - }, - { - "name": "rightwing1", - "parent": "rightwing", - "pivot": [-9.5, 5, -1.5], - "cubes": [ - {"origin": [-17, 5, -5], "size": [7, 0, 7], "uv": [43, 0], "mirror": true} - ] - }, - { - "name": "leftwing", - "parent": "Body", - "pivot": [2.5, 5, -3.5], - "cubes": [ - {"origin": [3, 5, -5], "size": [7, 0, 7], "uv": [-7, 28]} - ] - }, - { - "name": "leftwing1", - "parent": "leftwing", - "pivot": [9.5, 5, -1.5], - "cubes": [ - {"origin": [10, 5, -5], "size": [7, 0, 7], "uv": [43, 0]} - ] - }, - { - "name": "neck", - "parent": "Body", - "pivot": [0, 5, -4], - "cubes": [ - {"origin": [-1, 4, -8], "size": [2, 2, 4], "uv": [10, 21]} - ] - }, - { - "name": "Head", - "parent": "neck", - "pivot": [0, 4.8, -7.5], - "cubes": [ - {"origin": [-1.5, 4, -12], "size": [3, 3, 4], "uv": [18, 17]}, - {"origin": [0, 6, -15], "size": [0, 3, 7], "uv": [0, 14]}, - {"origin": [-1, 4, -16], "size": [2, 2, 4], "uv": [21, 0]}, - {"origin": [-1, 3, -16], "size": [2, 1, 1], "uv": [29, 0]}, - {"origin": [0, 7, -8], "size": [0, 1, 3], "uv": [0, 23]} - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/Forge/src/main/resources/assets/bluelib/geo/rex.geo.json b/Forge/src/main/resources/assets/bluelib/geo/rex.geo.json deleted file mode 100644 index 3d18bac7..00000000 --- a/Forge/src/main/resources/assets/bluelib/geo/rex.geo.json +++ /dev/null @@ -1,390 +0,0 @@ -{ - "format_version": "1.12.0", - "minecraft:geometry": [ - { - "description": { - "identifier": "geometry.unknown", - "texture_width": 512, - "texture_height": 512, - "visible_bounds_width": 29, - "visible_bounds_height": 7.5, - "visible_bounds_offset": [0, 3.25, 0] - }, - "bones": [ - { - "name": "Tyrannosaurus", - "pivot": [0, 0, 0] - }, - { - "name": "body", - "parent": "Tyrannosaurus", - "pivot": [0, 72, 0], - "cubes": [ - {"origin": [-19, 47, -8], "size": [38, 45, 34], "uv": [124, 51]}, - {"origin": [-15.475, 51.23327, -14.01496], "size": [31, 45, 35], "pivot": [0.025, 74.40827, 4.38504], "rotation": [-12.75, 0, 0], "uv": [130, 50]}, - {"origin": [-16, 40, -22.525], "size": [32, 16, 40], "inflate": -0.05, "pivot": [0, 72, 0.275], "rotation": [17.5, 0, 0], "uv": [0, 160]}, - {"origin": [-16, 54, -54], "size": [32, 37, 46], "uv": [1, 1]}, - {"origin": [-16, 71.46448, -54.53145], "size": [32, 30, 48], "inflate": -0.25, "pivot": [0, 89.46448, 3.46855], "rotation": [8.75, 0, 0], "uv": [-1, -1]}, - {"origin": [-16, 28.37894, -42.36923], "size": [32, 21, 49], "inflate": -0.025, "pivot": [0, 73.37894, 12.63077], "rotation": [-24, 0, 0], "uv": [0, 85]} - ] - }, - { - "name": "arm2", - "parent": "body", - "pivot": [13.56731, 58.46159, -45.9607], - "rotation": [29.07337, 19.05681, -20.20848], - "cubes": [ - {"origin": [12.56731, 47.46159, -47.9607], "size": [3, 11, 5], "uv": [111, 0]} - ] - }, - { - "name": "bone2", - "parent": "arm2", - "pivot": [15.06274, 49.29312, -45.32771], - "rotation": [-27.154, -2.96386, 4.54476], - "cubes": [ - {"origin": [13.13695, 39.306, -44.80271], "size": [2, 6, 2], "inflate": -0.075, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [0, 0]}, - {"origin": [14.86195, 37.306, -44.75271], "size": [0, 3, 2], "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [36, 26]}, - {"origin": [12.13695, 44.306, -47.52771], "size": [3, 5, 5], "inflate": -0.125, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [165, 257]} - ] - }, - { - "name": "bone3", - "parent": "bone2", - "pivot": [13.25685, 45.11756, -46.37771], - "rotation": [-14.50257, -2.95519, -2.10666], - "cubes": [ - {"origin": [13.13695, 41.306, -47.37771], "size": [2, 4, 2], "inflate": -0.075, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [0, 28]}, - {"origin": [14.86195, 39.306, -47.37771], "size": [0, 3, 2], "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [36, 29]} - ] - }, - { - "name": "arm3", - "parent": "body", - "pivot": [-13.56731, 58.46159, -45.9607], - "rotation": [29.07337, -19.05681, 20.20848], - "cubes": [ - {"origin": [-15.56731, 47.46159, -47.9607], "size": [3, 11, 5], "uv": [111, 0], "mirror": true} - ] - }, - { - "name": "bone4", - "parent": "arm3", - "pivot": [-15.06274, 49.29312, -45.32771], - "rotation": [-27.154, 2.96386, -4.54476], - "cubes": [ - {"origin": [-15.13695, 39.306, -44.80271], "size": [2, 6, 2], "inflate": -0.075, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [0, 0], "mirror": true}, - {"origin": [-14.86195, 37.306, -44.75271], "size": [0, 3, 2], "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [36, 26], "mirror": true}, - {"origin": [-15.13695, 44.306, -47.52771], "size": [3, 5, 5], "inflate": -0.125, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [165, 257], "mirror": true} - ] - }, - { - "name": "bone5", - "parent": "bone4", - "pivot": [-13.25685, 45.11756, -46.37771], - "rotation": [-14.50257, 2.95519, 2.10666], - "cubes": [ - {"origin": [-15.13695, 41.306, -47.37771], "size": [2, 4, 2], "inflate": -0.075, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [0, 28], "mirror": true}, - {"origin": [-14.86195, 39.306, -47.37771], "size": [0, 3, 2], "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [36, 29], "mirror": true} - ] - }, - { - "name": "tail1", - "parent": "body", - "pivot": [0, 82.97049, 21.3522], - "cubes": [ - {"origin": [-15, 55.74549, 21.0272], "size": [30, 30, 39], "uv": [123, 128]}, - {"origin": [-15, 71.63781, 17.37365], "size": [30, 28, 35], "inflate": -0.2, "pivot": [0, 60.21281, -16.55135], "rotation": [-10.75, 0, 0], "uv": [127, 132]}, - {"origin": [-15, 39.02049, 26.7772], "size": [30, 13, 37], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [16, 0, 0], "uv": [159, 1]} - ] - }, - { - "name": "tail2", - "parent": "tail1", - "pivot": [0, 82.97049, 56.3522], - "cubes": [ - {"origin": [-10, 62.97049, 56.3522], "size": [20, 21, 38], "uv": [106, 199]}, - {"origin": [-9, 41.02049, 63.3522], "size": [18, 14, 35], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [13, 0, 0], "uv": [173, 3]} - ] - }, - { - "name": "tail3", - "parent": "tail2", - "pivot": [0, 82.97049, 93.3522], - "cubes": [ - {"origin": [-7, 66.97049, 93.3522], "size": [14, 14, 37], "uv": [0, 216]}, - {"origin": [-7, 54.52049, 94.3522], "size": [14, 7, 38], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [5.5, 0, 0], "uv": [174, 0]} - ] - }, - { - "name": "tail4", - "parent": "tail3", - "pivot": [0, 82.97049, 129.3522], - "cubes": [ - {"origin": [-5, 69.97049, 129.3522], "size": [10, 9, 37], "uv": [255, 14]}, - {"origin": [-5, 64.82049, 132.6022], "size": [10, 4, 37], "inflate": -0.025, "pivot": [0, 30.97049, 109.3522], "rotation": [4.75, 0, 0], "uv": [255, 14]} - ] - }, - { - "name": "tail5", - "parent": "tail4", - "pivot": [0, 82.97049, 158.3522], - "cubes": [ - {"origin": [-3, 70.97049, 158.3522], "size": [6, 6, 37], "uv": [149, 257]}, - {"origin": [-3, 69.22961, 165.59014], "size": [6, 3, 30], "inflate": -0.1, "pivot": [0, 70.15461, 147.99014], "rotation": [0.5, 0, 0], "uv": [266, 21]} - ] - }, - { - "name": "tail6", - "parent": "tail5", - "pivot": [0, 82.97049, 182.3522], - "cubes": [ - {"origin": [-2, 71.97049, 182.3522], "size": [4, 4, 37], "uv": [0, 285]}, - {"origin": [-2, 66.99549, 197.7022], "size": [4, 4, 25], "inflate": -0.175, "pivot": [0, 30.97049, 162.3522], "rotation": [4.75, 0, 0], "uv": [12, 297]} - ] - }, - { - "name": "neck", - "parent": "body", - "pivot": [0, 74.22605, -48.50511], - "cubes": [ - {"origin": [-15, 55, -67], "size": [30, 31, 17], "uv": [251, 113]}, - {"origin": [-14.25, 80.39311, -64.98257], "size": [30, 11, 17], "inflate": -1, "pivot": [0.75, 82.39311, -53.98257], "rotation": [24.25, 0, 0], "uv": [251, 113]}, - {"origin": [-10, 66.05, -70.125], "size": [20, 34, 25], "inflate": -0.225, "pivot": [0, 87.575, -69.125], "rotation": [-39.25, 0, 0], "uv": [221, 200]}, - {"origin": [-10, 59.575, -78.125], "size": [20, 13, 25], "inflate": -1.325, "pivot": [0, 87.575, -69.125], "rotation": [-14.25, 0, 0], "uv": [235, 259]}, - {"origin": [-9, 71.2, -85.125], "size": [18, 19, 24], "inflate": -0.325, "pivot": [0, 85.2, -69.125], "rotation": [7.5, 0, 0], "uv": [268, 61]}, - {"origin": [-8, 83.89159, -88.09601], "size": [16, 12, 13], "inflate": -0.275, "pivot": [0, 89.89159, -79.09601], "rotation": [42.5, 0, 0], "uv": [198, 259]}, - {"origin": [-8, 86.39159, -80.39601], "size": [16, 11, 19], "inflate": -0.25, "pivot": [0, 89.89159, -68.09601], "rotation": [2.5, 0, 0], "uv": [111, 0]} - ] - }, - { - "name": "head", - "parent": "neck", - "pivot": [0, 83.05369, -83.57238], - "cubes": [ - {"origin": [-8.725, 71, -101], "size": [17, 19, 19], "uv": [286, 165]}, - {"origin": [-8.775, 84, -101], "size": [17, 2, 7], "inflate": 0.225, "uv": [104, 155]}, - {"origin": [-7, 93.5819, -99.5906], "size": [14, 5, 10], "inflate": -0.05, "pivot": [0, 90.5819, -77.5906], "rotation": [21.5, 0, 0], "uv": [0, 111]}, - {"origin": [-7, 81.46532, -93.49693], "size": [14, 5, 9], "inflate": -0.075, "pivot": [0, 78.46532, -74.49693], "rotation": [-25, 0, 0], "uv": [111, 30]}, - {"origin": [-7, 88.64032, -92.02193], "size": [14, 5, 4], "inflate": -0.125, "uv": [0, 191]}, - {"origin": [9, 86, -102], "size": [4, 3, 13], "inflate": -0.025, "pivot": [7, 80.5, -90.5], "rotation": [0, 0, -17.5], "uv": [149, 277]}, - {"origin": [4.59053, 84.6097, -93.1055], "size": [4, 3, 9], "inflate": -0.05, "pivot": [2.59053, 79.1097, -81.6055], "rotation": [0, -27.5, -17.5], "uv": [255, 23]}, - {"origin": [-8.59053, 84.6097, -93.1055], "size": [4, 3, 9], "inflate": -0.05, "pivot": [-2.59053, 79.1097, -81.6055], "rotation": [0, 27.5, 17.5], "uv": [184, 225]}, - {"origin": [12.62776, 90.52364, -107.52067], "size": [4, 3, 11], "inflate": -0.1, "pivot": [10.62776, 85.02364, -91.02067], "rotation": [27.87149, 36.42355, -5.95346], "uv": [0, 239]}, - {"origin": [-16.62776, 90.52364, -107.52067], "size": [4, 3, 11], "inflate": -0.1, "pivot": [-10.62776, 85.02364, -91.02067], "rotation": [27.87149, -36.42355, 5.95346], "uv": [162, 0]}, - {"origin": [-13, 86, -102], "size": [4, 3, 13], "inflate": -0.025, "pivot": [-7, 80.5, -90.5], "rotation": [0, 0, 17.5], "uv": [109, 216]}, - {"origin": [-7, 78.725, -121], "size": [14, 10, 16], "inflate": -0.05, "pivot": [0, 81.725, -99], "rotation": [27.5, 0, 0], "uv": [300, 243]}, - {"origin": [-7, 78.35, -106], "size": [14, 11, 11], "pivot": [0, 81.35, -99], "rotation": [33.5, 0, 0], "uv": [286, 203]}, - {"origin": [-7, 69.519, -125.21974], "size": [14, 11, 7.85], "inflate": -0.075, "pivot": [0, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [259, 165]}, - {"origin": [-6, 78.519, -128.21974], "size": [11, 0, 7.85], "pivot": [0, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [141, 30]}, - {"origin": [5, 61.519, -128.21974], "size": [0, 17, 6.85], "pivot": [-2, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [234, 45]}, - {"origin": [-5, 61.519, -128.21974], "size": [0, 17, 6.85], "pivot": [2, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [28, 154]}, - {"origin": [-7, 73.394, -115.21974], "size": [14, 10, 6.85], "inflate": -0.1, "pivot": [0, 74.394, -109.21974], "rotation": [110.5, 0, 0], "uv": [65, 237]}, - {"origin": [-7, 84.31148, -108.92962], "size": [14, 4, 6.85], "inflate": -0.15, "pivot": [0, 79.31148, -102.92962], "rotation": [128, 0, 0], "uv": [272, 0]}, - {"origin": [-7, 74.31148, -110.92962], "size": [14, 9, 8.85], "inflate": -0.175, "pivot": [0, 79.31148, -102.92962], "rotation": [88, 0, 0], "uv": [0, 28]}, - {"origin": [-7, 69.019, -122.66974], "size": [14, 10, 7], "inflate": -0.125, "pivot": [0, 72.019, -117.66974], "rotation": [47.5, 0, 0], "uv": [0, 267]} - ] - }, - { - "name": "jaw", - "parent": "head", - "pivot": [0, 73.374, -85.20224], - "cubes": [ - {"origin": [-9.125, 61.47673, -99.81697], "size": [18, 13, 12], "inflate": 0.025, "uv": [184, 200]}, - {"origin": [-9.15, 64.14383, -89.12484], "size": [18, 12, 7], "inflate": 0.075, "pivot": [-3, 73.14383, -68.12484], "rotation": [7.5, 0, 0], "uv": [312, 0]}, - {"origin": [7.8, 70.81044, -97.91351], "size": [1, 6, 9], "uv": [104, 179]}, - {"origin": [7.85, 63.60089, -93.15375], "size": [1, 6, 7], "pivot": [-2.975, 63.60089, -72.15375], "rotation": [-22.5, 0, 0], "uv": [65, 216]}, - {"origin": [-7.125, 72.47673, -98.81697], "size": [14, 14, 16], "inflate": 0.025, "uv": [219, 297]}, - {"origin": [6.375, 68.47673, -105.81697], "size": [0, 18, 14], "uv": [0, 159]}, - {"origin": [-6.625, 68.47673, -105.81697], "size": [0, 18, 14], "uv": [0, 141]}, - {"origin": [7.875, 65.38327, -112.3007], "size": [1, 8, 15], "inflate": -0.05, "pivot": [0, 73.88327, -104.8007], "rotation": [27.5, 0, 0], "uv": [255, 0]}, - {"origin": [-9.125, 65.38327, -112.3007], "size": [1, 8, 15], "inflate": -0.05, "pivot": [0, 73.88327, -104.8007], "rotation": [27.5, 0, 0], "uv": [0, 216]}, - {"origin": [-9.05, 70.81044, -97.91351], "size": [1, 6, 9], "uv": [104, 164]}, - {"origin": [-9.1, 63.60089, -93.15375], "size": [1, 6, 7], "pivot": [2.975, 63.60089, -72.15375], "rotation": [-22.5, 0, 0], "uv": [17, 216]}, - {"origin": [-9.125, 64.31864, -111.04094], "size": [18, 8, 15], "inflate": -0.025, "pivot": [0, 70.56864, -103.54094], "rotation": [17.5, 0, 0], "uv": [149, 300]}, - {"origin": [-6.125, 66.9078, -126.60427], "size": [12, 5, 15], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [126, 257]}, - {"origin": [-6.125, 71.5078, -125.60427], "size": [12, 5, 0], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [62, 155]}, - {"origin": [5.725, 71.5078, -125.60427], "size": [0, 5, 17], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [28, 138]}, - {"origin": [-5.975, 71.5078, -125.60427], "size": [0, 5, 17], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [0, 109]}, - {"origin": [-6.125, 60.70962, -124.43479], "size": [12, 5, 15], "inflate": -0.05, "pivot": [0, 63.78462, -115.43479], "rotation": [-3.5, 0, 0], "uv": [234, 61]}, - {"origin": [-7.125, 61.71743, -111.29498], "size": [14, 5, 16], "inflate": -0.025, "pivot": [0, 66.69243, -101.79498], "rotation": [9.25, 0, 0], "uv": [65, 216]} - ] - }, - { - "name": "leg_left", - "parent": "Tyrannosaurus", - "pivot": [20.42923, 70.7324, 8.85434], - "rotation": [-15.09173, -1.85092, -0.08398], - "cubes": [ - {"origin": [12.54366, 41.02086, -4.25109], "size": [12.875, 42.825, 23.725], "uv": [79, 257]} - ] - }, - { - "name": "leg_left2", - "parent": "leg_left", - "pivot": [21.99279, 43.52539, 1.69711], - "cubes": [ - {"origin": [12.844, 24.19389, 3.09297], "size": [12.4, 20.375, 15.95], "pivot": [21.944, 35.38139, 0.96797], "rotation": [34, 0, 0], "uv": [279, 297]} - ] - }, - { - "name": "leg_left3", - "parent": "leg_left2", - "pivot": [19.76532, 33.92692, 13.90262], - "rotation": [55, 0, 0], - "cubes": [ - {"origin": [14.22989, 14.97535, 9.92239], "size": [10, 19, 9], "inflate": -0.1, "uv": [0, 0]} - ] - }, - { - "name": "leg_left4", - "parent": "leg_left3", - "pivot": [19.76532, 14.92692, 13.90262], - "rotation": [-60, 0, 0], - "cubes": [ - {"origin": [14.22989, 2.41759, 7.14887], "size": [10, 17, 9], "inflate": 0.375, "uv": [0, 85]} - ] - }, - { - "name": "Claw5", - "parent": "leg_left4", - "pivot": [18.03922, 11.69239, 7.72125], - "rotation": [3.25353, -39.92899, -4.10228], - "cubes": [ - {"origin": [19.68942, 7.60244, 18.32118], "size": [2, 5, 6], "inflate": -0.2, "pivot": [20.68942, 10.90244, 16.32118], "rotation": [4, 5, 0], "uv": [19, 239]}, - {"origin": [15.96316, 8.07744, 15.28926], "size": [2, 3, 4], "inflate": 0.5, "pivot": [20.4918, 5.40696, 3.40745], "rotation": [2.31336, 4.43385, 27.58957], "uv": [29, 0]} - ] - }, - { - "name": "leg_left5", - "parent": "leg_left4", - "pivot": [19.76532, 2.72669, 9.58045], - "rotation": [32.5, 0, 0], - "cubes": [ - {"origin": [14.22989, -4.78265, 7.2517], "size": [10, 8, 8], "inflate": 0.35, "uv": [42, 267]} - ] - }, - { - "name": "Claw3", - "parent": "leg_left5", - "pivot": [14.03922, -1.93376, 9.83799], - "rotation": [-11.28559, 36.03256, -29.0792], - "cubes": [ - {"origin": [15.68942, -5.02371, -6.76194], "size": [2, 4, 9], "inflate": -0.2, "pivot": [16.68942, -2.72371, 1.23806], "rotation": [-4, -5, 0], "uv": [78, 267]}, - {"origin": [11.96316, -5.54871, -1.73002], "size": [2, 3, 12], "inflate": 0.5, "pivot": [16.4918, -8.21919, 14.15179], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [45, 298]}, - {"origin": [13.86316, -1.04871, -0.45502], "size": [2, 3, 12], "inflate": 0.4, "pivot": [18.3918, -3.71919, 15.42679], "rotation": [14.70847, -5.40113, 27.33492], "uv": [263, 297]} - ] - }, - { - "name": "Claw2", - "parent": "leg_left5", - "pivot": [18.00128, -1.52657, 8.77203], - "rotation": [6.46283, 10.46681, -26.49382], - "cubes": [ - {"origin": [19.65148, -4.61652, -7.8279], "size": [2, 4, 9], "inflate": -0.2, "pivot": [20.65148, -2.31652, 0.1721], "rotation": [-8.25367, -3.37646, 28.00254], "uv": [259, 183]}, - {"origin": [15.92522, -5.14152, -2.79598], "size": [2, 3, 12], "inflate": 0.5, "pivot": [20.45386, -7.812, 13.08583], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [0, 284]}, - {"origin": [17.82522, -0.64152, -1.52098], "size": [2, 3, 12], "inflate": 0.4, "pivot": [22.35386, -3.312, 14.36083], "rotation": [14.70847, -5.40113, 27.33492], "uv": [45, 283]} - ] - }, - { - "name": "Claw4", - "parent": "leg_left5", - "pivot": [25.00339, -1.78444, 9.60342], - "rotation": [-6.62428, -31.83686, 25.40349], - "cubes": [ - {"origin": [21.35319, -4.87439, -6.99651], "size": [2, 4, 9], "inflate": -0.2, "pivot": [22.35319, -2.57439, 1.00349], "rotation": [-4, 5, 0], "uv": [172, 21]}, - {"origin": [25.07945, -5.39939, -1.96459], "size": [2, 3, 12], "inflate": 0.5, "pivot": [22.55081, -8.06987, 13.91722], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [222, 145]}, - {"origin": [23.17945, -0.89939, -0.68959], "size": [2, 3, 12], "inflate": 0.4, "pivot": [20.65081, -3.56987, 15.19222], "rotation": [14.70847, 5.40113, -27.33492], "uv": [222, 130]} - ] - }, - { - "name": "leg_right", - "parent": "Tyrannosaurus", - "pivot": [-20.42923, 70.7324, 8.85434], - "rotation": [-15.09173, 1.85092, 0.08398], - "cubes": [ - {"origin": [-25.41866, 41.02086, -4.25109], "size": [12.875, 42.825, 23.725], "uv": [79, 257], "mirror": true} - ] - }, - { - "name": "leg_right2", - "parent": "leg_right", - "pivot": [-21.99279, 43.52539, 1.69711], - "cubes": [ - {"origin": [-25.244, 24.19389, 3.09297], "size": [12.4, 20.375, 15.95], "pivot": [-21.944, 35.38139, 0.96797], "rotation": [34, 0, 0], "uv": [279, 297], "mirror": true} - ] - }, - { - "name": "leg_right3", - "parent": "leg_right2", - "pivot": [-19.76532, 33.92692, 13.90262], - "rotation": [55, 0, 0], - "cubes": [ - {"origin": [-24.22989, 14.97535, 9.92239], "size": [10, 19, 9], "inflate": -0.1, "uv": [0, 0], "mirror": true} - ] - }, - { - "name": "leg_right4", - "parent": "leg_right3", - "pivot": [-19.76532, 14.92692, 13.90262], - "rotation": [-60, 0, 0], - "cubes": [ - {"origin": [-24.22989, 2.41759, 7.14887], "size": [10, 17, 9], "inflate": 0.375, "uv": [0, 85], "mirror": true} - ] - }, - { - "name": "Claw6", - "parent": "leg_right4", - "pivot": [-18.03922, 11.69239, 7.72125], - "rotation": [3.25353, 39.92899, 4.10228], - "cubes": [ - {"origin": [-21.68942, 7.60244, 18.32118], "size": [2, 5, 6], "inflate": -0.2, "pivot": [-20.68942, 10.90244, 16.32118], "rotation": [4, -5, 0], "uv": [19, 239], "mirror": true}, - {"origin": [-17.96316, 8.07744, 15.28926], "size": [2, 3, 4], "inflate": 0.5, "pivot": [-20.4918, 5.40696, 3.40745], "rotation": [2.31336, -4.43385, -27.58957], "uv": [29, 0], "mirror": true} - ] - }, - { - "name": "leg_right5", - "parent": "leg_right4", - "pivot": [-19.76532, 2.72669, 9.58045], - "rotation": [32.5, 0, 0], - "cubes": [ - {"origin": [-24.22989, -4.78265, 7.2517], "size": [10, 8, 8], "inflate": 0.35, "uv": [42, 267], "mirror": true} - ] - }, - { - "name": "Claw7", - "parent": "leg_right5", - "pivot": [-14.03922, -1.93376, 9.83799], - "rotation": [-11.28559, -36.03256, 29.0792], - "cubes": [ - {"origin": [-17.68942, -5.02371, -6.76194], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-16.68942, -2.72371, 1.23806], "rotation": [-4, 5, 0], "uv": [78, 267], "mirror": true}, - {"origin": [-13.96316, -5.54871, -1.73002], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-16.4918, -8.21919, 14.15179], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [45, 298], "mirror": true}, - {"origin": [-15.86316, -1.04871, -0.45502], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-18.3918, -3.71919, 15.42679], "rotation": [14.70847, 5.40113, -27.33492], "uv": [263, 297], "mirror": true} - ] - }, - { - "name": "Claw8", - "parent": "leg_right5", - "pivot": [-18.00128, -1.52657, 8.77203], - "rotation": [6.46283, -10.46681, 26.49382], - "cubes": [ - {"origin": [-21.65148, -4.61652, -7.8279], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-20.65148, -2.31652, 0.1721], "rotation": [-8.25367, 3.37646, -28.00254], "uv": [259, 183], "mirror": true}, - {"origin": [-17.92522, -5.14152, -2.79598], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-20.45386, -7.812, 13.08583], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [0, 284], "mirror": true}, - {"origin": [-19.82522, -0.64152, -1.52098], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-22.35386, -3.312, 14.36083], "rotation": [14.70847, 5.40113, -27.33492], "uv": [45, 283], "mirror": true} - ] - }, - { - "name": "Claw9", - "parent": "leg_right5", - "pivot": [-25.00339, -1.78444, 9.60342], - "rotation": [-6.62428, 31.83686, -25.40349], - "cubes": [ - {"origin": [-23.35319, -4.87439, -6.99651], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-22.35319, -2.57439, 1.00349], "rotation": [-4, -5, 0], "uv": [172, 21], "mirror": true}, - {"origin": [-27.07945, -5.39939, -1.96459], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-22.55081, -8.06987, 13.91722], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [222, 145], "mirror": true}, - {"origin": [-25.17945, -0.89939, -0.68959], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-20.65081, -3.56987, 15.19222], "rotation": [14.70847, -5.40113, 27.33492], "uv": [222, 130], "mirror": true} - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/Forge/src/main/resources/assets/bluelib/lang/en_us.json b/Forge/src/main/resources/assets/bluelib/lang/en_us.json deleted file mode 100644 index 8371c823..00000000 --- a/Forge/src/main/resources/assets/bluelib/lang/en_us.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "entity.bluelib.example_one": "Example", - "entity.bluelib.example_two": "Example" -} \ No newline at end of file diff --git a/Forge/src/main/resources/assets/bluelib/textures/entity/dragon/bright.png b/Forge/src/main/resources/assets/bluelib/textures/entity/dragon/bright.png deleted file mode 100644 index e7ebe1318d4146bb10dca6e53c6a815e9ec4f0c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!&W-dj)XETq4p!hyw%*PB>6gHc&$n9=U$y$Y z=ULGFkm<(URR6k*f9~ifPORfQ8{fFN_3La2ewpdrfjf9l==L1Ewstv_XZ2P)c>&If zo7udFLmZS{`L3Ee6k9MnkvtTx<8Wy&hjW9I+WA{b=XXy`<=Mx-{D3oOZFPXx*MkqX zopgEQ%)BO|P0GxO`=7DhTSkX`)|Ov;_wF(JQ^qRb6;Z{!LrZLd&fRoXz1eGZZiJTX zm%F)N?!wuueJ>b}9}~N|e}$?_Y?+eN-boqvB=;!je&qhsWu|1$&{>iw>T&p)O5eGP z?&bGy2-@$?61i~7>)RH^=4TPFrtI4gsia;z^O)Hum9@`z9DjUbLid4H8UCA;o~gcI z;9{45H}4Xg_xk>?q7EhJ|FdO$xh>$s{He+0%H_s(BaX|Ao~)CalRmvyb&z|yU*ey9 qACrmXntbLwZDRvwC@P5A$Jpe($}z8};3Y8L89ZJ6T-G@yGywpxb1(q_ diff --git a/Forge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png b/Forge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png deleted file mode 100644 index 56c9452f64ef0b1e71cecef3b4d07f56ae847633..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!mKPJ^=Hz5!W#wdNPn^2p^s67*vJwUgQb~?#2X}7uGm#gP zQ06^oDwgx$fq}uR<%$^@8TFMVidv2~UU@d+Y|c^~DgvxPb0$Wc7}!LuS~IT`$dN7y z@(X78j}sipEHVW;@~EeaV@SoEw^wiHEjAEfdvHHFiDPf3^4f2I61s;NV<1;Z1`L*Y6Om-ccvH#n)Czom43_rz45ef-N0ICIuk2Y7uw_+Z;f zmp9JLYa-gD%#67I8QZ;ObjW9I`L%cN9-}{HtO8yURm?lI#1`n>O;^>My;kQ&Xvu!L zoBQQ1oXy(zg5mfvv77r>sH()4DLL((lyOgTkAm(;?mt~-O7;w$C5fUQho7nRovY|x ze*cD`{q8K03#YukZBcA~7V&Dzz73H|>a{bEnSD}O`+Udo$0sIqA6S*)ze(wt>I()g zcKLVnF0py9@Bb?5P;&l1TgI2$0zS;2noO=-ZfrN=xXkFuI;lD7(|c71xu^Rj{>k?- onMkh5XU@|$HeiOLf|z}bP2Q^<^Lh$i0^^;*)78&qol`;+0O_S2&j0`b diff --git a/Forge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png b/Forge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png deleted file mode 100644 index f2956d0504901ccd33fb2067b7631ba08471c5ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3454 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 or57IkfgP>p|9}4H3?K* zd$|Vy0Lxt%z&JT@wO!)n0A&PtxcTWHMQ;CCUK+VbR@PgIE_Q-#4VZ+o>m>4&1Ni!+e7d%l_n? zxZ~ZcB#F9yLg{*Zse~b2F@UYst7MK&{iUQ_aG5EvBgvGNXSSOn&)a!Pwl4YxCIRZr zrAF;ib-vH8++2$fyhbC(n*6E`H_m9e5j)dx#4vTTIM(N7SJ&DT!#AwbRgg-JQwN5Q zx5emxTfD z<_{FgIf}z3c0d4#tD#w9mk5BOP9zjaEKzEgPdNzdq+Fv8RiifJ6`& zvx`(knW5m^Q7YzIDsK%yoEEKP*to+aayaWS%U7eh^5KPKEi0l+qpb>Sj3-;5;D+Kv zHlYL-i|VI}v!0##+8Tmz3N3|4)Zp-ePN_qE;D;FvD1ULzXKSxNHqSj&!)yt!U%(h8{>l>X*3G z4Q~FW@*G8)!++>u?i3VOvVR^=a}as+}U{ny5{`LCt;Y zkO{jf(STt?eR~A|C|L*A`=Jo@0c(8qWjZ!ts%wf4*qe=-BnD9I5Y1D}^z#BBF%pE) zl>}R84GSTDkh!q8L5V|p^W~sxAbO7}5@Gd2@dack6VEW$o1FSADwp;WBA#Fqs{UVX zGZnHihI?Q>wI2@j+hNz8O|0QYC41S$o%0jx; z@W29W8|&NuB)_Qaq9M|4Cg#m1olT!j+qyepp4OlgNrC8VrMEU={pUVObBMHjgc1wK zsq{7j52I5RW`nJ7;`ubl1cmNWI+;L9FSj+VU+T^N)LJM6Wp)lVs1y}8XHa_g~ z&Nvc@>7Bm1^WT@q#QUH2gpsl8jp!=!4$+J{6e2PuRC{AZAFtJoti}vQQz9%93)Jv@ zyFFLtJ?~V7jRsa)!wh|m--{awAi{odkjHLIAH4c(g@i>XrbqcZ2>P$-ncZB%-wva( zD?5>%sFYVXnp|OD@5wc&2RgL@X^*t^l|mto*0ZWOJ8mRKs-j|<=sELnkVIrOmN-@@ zLrD-VE0y(+ioeT_yL5E1rnaO3PxCqFpB1&`%C2%X+L$T~1m&1 - * This class serves as the entry point for the {@link BlueLib} mod, handling initialization by registering event handlers + * This class serves as the entry point for the {@code BlueLib} mod, handling initialization by registering event handlers * and setting up necessary configurations. For more details, refer to the BlueLib Wiki. *

          *

          * Key Methods: *

            - *
          • {@link #BlueLib(IEventBus, ModContainer)} - Constructs the {@link BlueLib} instance and registers the mod event bus.
          • - *
          • {@link #onLoadComplete(FMLLoadCompleteEvent)} - Handles the event when the mod loading is complete and prints a thank-you message if in developer mode.
          • - *
          • {@link #isDeveloperMode()} - Determines if the mod is running in developer mode.
          • + *
          • {@link #BlueLib(IEventBus, ModContainer)} - Constructs the {@code BlueLib} instance and registers the mod event bus.
          • + *
          • {@link #onLoadComplete(FMLLoadCompleteEvent)} - Handles the event when the mod loading is complete.
          • *
          *

          * @@ -40,29 +35,11 @@ * @Co-author All Contributors of BlueLib! * @since 1.0.0 */ -@Mod(BlueLib.MODID) +@Mod(BlueLibConstants.MOD_ID) public class BlueLib { /** - * A {@code public static final} {@link ScheduledExecutorService} used to schedule tasks, such as printing messages after a delay. - *

          - * This executor runs tasks on a single thread to ensure delayed tasks run in a separate thread from the main thread. - *

          - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1); - - /** - * A {@code public static final} {@link String} representing the Mod ID for the {@link BlueLib} mod. - *

          This serves as a unique identifier for the mod.

          - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - public static final String MODID = "bluelib"; - - /** - * Constructs a new {@link BlueLib} instance and registers the mod event bus. + * Constructs a new {@code BlueLib} instance and registers the mod event bus. *

          * Registers necessary mod event listeners, and if in developer mode, additional client-side listeners for rendering and attributes. *

          @@ -76,20 +53,10 @@ public class BlueLib { public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { pModEventBus.register(this); MixinBootstrap.init(); - if (isDeveloperMode()) { - ModEntities.REGISTRY.register(pModEventBus); - if (FMLEnvironment.dist.isClient()) { - pModEventBus.addListener(ClientEvents::registerAttributes); - pModEventBus.addListener(ClientEvents::registerRenderers); - } - } } /** * A {@code public void} that handles the {@link FMLLoadCompleteEvent}, which occurs when the mod finishes loading. - *

          - * If the mod is in developer mode, it schedules a task that prints a thank-you message after a short delay. - *

          * * @param pEvent {@link FMLLoadCompleteEvent} - The event fired after the mod loading process completes. * @author MeAlam @@ -98,37 +65,6 @@ public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { */ @SubscribeEvent public void onLoadComplete(FMLLoadCompleteEvent pEvent) { - if (isDeveloperMode()) { - SCHEDULER.schedule(() -> { - BaseLogger.logBlueLib("**************************************************"); - BaseLogger.logBlueLib(" "); - BaseLogger.logBlueLib(" Thank you for using BlueLib! "); - BaseLogger.logBlueLib(" We appreciate your support. "); - BaseLogger.logBlueLib(" "); - BaseLogger.logBlueLib("**************************************************"); - SCHEDULER.shutdown(); - }, 3, TimeUnit.SECONDS); - } - } - - /** - * A {@code static} {@link Boolean} that checks if the mod is running in developer mode. - *

          - * Developer mode is active when the mod is not running in a production environment. - *

          - * - * @return {@code true} if running in developer mode, {@code false} otherwise. - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ - static boolean isDeveloperMode() { - boolean isDevMode = !FMLEnvironment.production; - if (isDevMode) { - BaseLogger.log(BaseLogLevel.INFO ,"Running in Developer mode.", true); - } else { - BaseLogger.log(BaseLogLevel.INFO ,"Running in Production mode.", true); - } - return isDevMode; + BlueLibCommon.init(); } } diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java deleted file mode 100644 index 0c3b6240..00000000 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.dragon; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.syncher.SynchedEntityData; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.entity.*; -import net.minecraft.world.entity.ai.attributes.AttributeSupplier; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.ServerLevelAccessor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import software.bernie.geckolib.animatable.GeoEntity; -import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; -import software.bernie.geckolib.animation.AnimatableManager; -import software.bernie.geckolib.util.GeckoLibUtil; -import software.bluelib.interfaces.variant.IVariantAccessor; -import software.bluelib.interfaces.variant.IVariantEntity; -import software.bluelib.utils.logging.BaseLogLevel; -import software.bluelib.utils.logging.BaseLogger; -import software.bluelib.utils.variant.ParameterUtils; - -/** - * A {@code DragonEntity} class representing a dragon entity in the game, which extends {@link TamableAnimal} - * and implements {@link IVariantEntity} and {@link GeoEntity}. - *

          - * This class manages the dragon's variant system, its data synchronization, and integrates with the GeckoLib - * animation system. - *

          - * - *

          - * Key Methods: - *

            - *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
          • - *
          • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
          • - *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • - *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • - *
          - *

          - * - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public class DragonEntity extends TamableAnimal implements IVariantEntity, GeoEntity { - /** - * The name of the entity. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - protected final String entityName = "dragon"; - - /** - * Constructs a new {@link DragonEntity} instance with the specified entity type and level. - * - * @param pEntityType {@link EntityType} - The type of the entity. - * @param pLevel {@link Level} - The level in which the entity is created. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public DragonEntity(EntityType pEntityType, Level pLevel) { - super(pEntityType, pLevel); - } - - public void setVariantName(String pVariantName) { - ((IVariantAccessor) this).setEntityVariantName(pVariantName); - } - - public String getVariantName() { - return ((IVariantAccessor) this).getEntityVariantName(); - } - - /** - * Finalizes the spawning of the dragon entity. - *

          - * This method sets up the variant for the entity and connects parameters if needed. - *

          - * - * @param pLevel {@link ServerLevelAccessor} - The level in which the entity is spawned. - * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. - * @param pReason {@link MobSpawnType} - The reason for spawning the entity. - * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. - * @return {@link SpawnGroupData} - Updated spawn data. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { - if (getVariantName() == null || getVariantName().isEmpty()) { - setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); - ParameterUtils.ParameterBuilder.forVariant(entityName,this.getVariantName()) - .withParameter("customParameter") - .withParameter("int") - .withParameter("bool") - .withParameter("array") - .connect(); - } - BaseLogger.log(BaseLogLevel.SUCCESS,"Dragon Spawned with Variant: " + getVariantName()); - return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); - } - - - - - - /** - * All Code below this Fragment is not Library Related!!! - */ - - private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); - - public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes() - .add(Attributes.MOVEMENT_SPEED, 0.3) - .add(Attributes.MAX_HEALTH, 10) - .add(Attributes.ARMOR, 0) - .add(Attributes.ATTACK_DAMAGE, 3) - .add(Attributes.FOLLOW_RANGE, 16) - .add(Attributes.FLYING_SPEED, 0.3); - } - - @Override - public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { - } - - @Override - public AnimatableInstanceCache getAnimatableInstanceCache() { - return cache; - } - - @Nullable - @Override - public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { - return null; - } - - @Override - public boolean isFood(@NotNull ItemStack pItemStack) { - return false; - } -} diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java deleted file mode 100644 index 49db6249..00000000 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.dragon; - -import net.minecraft.resources.ResourceLocation; -import software.bernie.geckolib.model.GeoModel; -import software.bluelib.BlueLib; - -public class DragonModel extends GeoModel { - - - // Get the Model Location - @Override - public ResourceLocation getModelResource(DragonEntity pObject) { - return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "geo/dragon.geo.json"); - } - - // Get the Texture Location - @Override - public ResourceLocation getTextureResource(DragonEntity pObject) { - return pObject.getTextureLocation(BlueLib.MODID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); - } - - // Get the Animation Location - @Override - public ResourceLocation getAnimationResource(DragonEntity pAnimatable) { - return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "animations/dragon.animation.json"); - } -} diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java deleted file mode 100644 index c770ac48..00000000 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.dragon; - -import net.minecraft.client.renderer.entity.EntityRendererProvider; -import software.bernie.geckolib.renderer.GeoEntityRenderer; - -public class DragonRender extends GeoEntityRenderer { - - // Render the entity - public DragonRender(EntityRendererProvider.Context pRenderManager) { - super(pRenderManager, new DragonModel()); - } -} diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java deleted file mode 100644 index 37d48f57..00000000 --- a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.rex; - -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.syncher.EntityDataAccessor; -import net.minecraft.network.syncher.EntityDataSerializers; -import net.minecraft.network.syncher.SynchedEntityData; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.entity.*; -import net.minecraft.world.entity.ai.attributes.AttributeSupplier; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.ServerLevelAccessor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import software.bernie.geckolib.animatable.GeoEntity; -import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; -import software.bernie.geckolib.animation.AnimatableManager; -import software.bernie.geckolib.util.GeckoLibUtil; -import software.bluelib.interfaces.variant.IVariantAccessor; -import software.bluelib.interfaces.variant.IVariantEntity; -import software.bluelib.utils.variant.ParameterUtils; - -/** - * A {@code RexEntity} class representing a Rex entity in the game, which extends {@link TamableAnimal} - * and implements {@link IVariantEntity} and {@link GeoEntity}. - *

          - * This class manages the Rex's variant system, its data synchronization, and integrates with the GeckoLib - * animation system. - *

          - * - *

          - * Key Methods: - *

            - *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
          • - *
          • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
          • - *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • - *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • - *
          • {@link #setVariantName(String)} - Sets the variant name of the Rex.
          • - *
          • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
          • - *
          - *

          - * - * @author MeAlam - * @Co-author Dan - * @since 1.0.0 - */ -public class RexEntity extends TamableAnimal implements IVariantEntity, GeoEntity { - /** - * The name of the entity. - * @Co-author MeAlam, Dan - * @since 1.0.0 - */ - protected final String entityName = "rex"; - - /** - * Constructs a new {@link RexEntity} instance with the specified entity type and level. - * - * @param pEntityType {@link EntityType} - The type of the entity. - * @param pLevel {@link Level} - The level in which the entity is created. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public RexEntity(EntityType pEntityType, Level pLevel) { - super(pEntityType, pLevel); - } - - public void setVariantName(String pVariantName) { - ((IVariantAccessor) this).setEntityVariantName(pVariantName); - } - - public String getVariantName() { - return ((IVariantAccessor) this).getEntityVariantName(); - } - - /** - * Finalizes the spawning of the Rex entity. - *

          - * This method sets up the variant for the entity and connects parameters if needed. - *

          - * - * @param pLevel {@link ServerLevelAccessor} - The level in which the entity is spawned. - * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. - * @param pReason {@link MobSpawnType} - The reason for spawning the entity. - * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. - * @return {@link SpawnGroupData} - Updated spawn data. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @Override - public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { - if (getVariantName() == null || getVariantName().isEmpty()) { - this.setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); - ParameterUtils.ParameterBuilder.forVariant(entityName,this.getVariantName()) - .withParameter("customParameter") - .withParameter("int") - .withParameter("bool") - .withParameter("array") - .connect(); - } - return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); - } - - /** - * All Code below this Fragment is not Library Related!!! - */ - - private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); - - public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes() - .add(Attributes.MOVEMENT_SPEED, 0.3) - .add(Attributes.MAX_HEALTH, 10) - .add(Attributes.ARMOR, 0) - .add(Attributes.ATTACK_DAMAGE, 3) - .add(Attributes.FOLLOW_RANGE, 16) - .add(Attributes.FLYING_SPEED, 0.3); - } - - @Override - public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { - } - - @Override - public AnimatableInstanceCache getAnimatableInstanceCache() { - return cache; - } - - @Nullable - @Override - public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { - return null; - } - - @Override - public boolean isFood(@NotNull ItemStack pItemStack) { - return false; - } -} diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java deleted file mode 100644 index 1e0f85e3..00000000 --- a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.rex; - -import net.minecraft.resources.ResourceLocation; -import software.bernie.geckolib.model.GeoModel; -import software.bluelib.BlueLib; - -public class RexModel extends GeoModel { - - - // Get the Model Location - @Override - public ResourceLocation getModelResource(RexEntity pObject) { - return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "geo/rex.geo.json"); - } - - // Get the Texture Location - @Override - public ResourceLocation getTextureResource(RexEntity pObject) { - return pObject.getTextureLocation(BlueLib.MODID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); - } - - // Get the Animation Location - @Override - public ResourceLocation getAnimationResource(RexEntity pAnimatable) { - return ResourceLocation.fromNamespaceAndPath(BlueLib.MODID, "animations/rex.animation.json"); - } -} diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java deleted file mode 100644 index 776c5920..00000000 --- a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.entity.rex; - -import net.minecraft.client.renderer.entity.EntityRendererProvider; -import software.bernie.geckolib.renderer.GeoEntityRenderer; - -public class RexRender extends GeoEntityRenderer { - - // Render the entity - public RexRender(EntityRendererProvider.Context pRenderManager) { - super(pRenderManager, new RexModel()); - } -} diff --git a/NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java b/NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java deleted file mode 100644 index 8d3a63de..00000000 --- a/NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.event; - -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.neoforge.client.event.EntityRenderersEvent; -import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent; -import software.bluelib.example.entity.dragon.DragonEntity; -import software.bluelib.example.entity.dragon.DragonRender; -import software.bluelib.example.entity.rex.RexEntity; -import software.bluelib.example.entity.rex.RexRender; -import software.bluelib.example.init.ModEntities; - -public class ClientEvents { - @SubscribeEvent - public static void registerRenderers(final EntityRenderersEvent.RegisterRenderers pEvent) { - // Register the renderer for all the Entities - pEvent.registerEntityRenderer(ModEntities.DRAGON.get(), DragonRender::new); - pEvent.registerEntityRenderer(ModEntities.REX.get(), RexRender::new); - } - - // Register the Attributes - @SubscribeEvent - public static void registerAttributes(EntityAttributeCreationEvent pEvent) { - pEvent.put(ModEntities.DRAGON.get(), DragonEntity.createAttributes().build()); - pEvent.put(ModEntities.REX.get(), RexEntity.createAttributes().build()); - } -} diff --git a/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java b/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java deleted file mode 100644 index c5f3405e..00000000 --- a/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.event; - -import net.minecraft.server.MinecraftServer; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.neoforge.event.AddReloadListenerEvent; -import net.neoforged.neoforge.event.server.ServerStartingEvent; -import software.bluelib.BlueLib; -import software.bluelib.event.ReloadEventHandler; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -/** - * A {@code ReloadHandler} class that handles server start and reload events related to entity variants. - *

          - * This class extends {@link ReloadEventHandler} and implements event handling for server starting and reloading, - * ensuring that entity variant data is properly loaded and refreshed. - *

          - * - *

          - * Key Methods: - *

            - *
          • {@link #onServerStart(ServerStartingEvent)} - Handles server starting events to initialize entity variants.
          • - *
          • {@link #onReload(AddReloadListenerEvent)} - Handles reload events to refresh entity variants.
          • - *
          • {@link #LoadEntityVariants(MinecraftServer)} - Loads entity variants from JSON files into the server.
          • - *
          - *

          - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ -@EventBusSubscriber -public class ReloadHandler extends ReloadEventHandler { - - /** - * The {@link MinecraftServer} instance for the server handling the events. - *

          - * This is initialized when the server starts and used to load entity variants. - *

          - * - * @since 1.0.0 - * @Co-author MeAlam, Dan - */ - private static MinecraftServer server; - - /** - * Handles the server starting event to initialize the {@link MinecraftServer} instance - * and load entity variants. - * - * @param pEvent {@link ServerStartingEvent} - The event triggered when the server starts. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @SubscribeEvent - public static void onServerStart(ServerStartingEvent pEvent) { - server = pEvent.getServer(); - ReloadHandler.LoadEntityVariants(server); - } - - /** - * The {@link ScheduledExecutorService} used to schedule tasks for reloading entity variants. - * - * @since 1.0.0 - * @Co-author MeAlam, Dan - */ - private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - - /** - * Handles the reload event by scheduling a task to reload entity variants. - *

          - * This method schedules the {@code LoadEntityVariants} method to run after a short delay. - *

          - * - * @param pEvent {@link AddReloadListenerEvent} - The event triggered when a reload occurs. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - @SubscribeEvent - public static void onReload(AddReloadListenerEvent pEvent) { - if (server != null) { - scheduler.schedule(() -> { - server.execute(() -> { - ReloadHandler.LoadEntityVariants(server); - }); - }, 1, TimeUnit.SECONDS); - } - } - - /** - * The base path for entity variant JSON files. - *

          - * This path is used to locate the files that contain variant data for entities. - *

          - * - * @since 1.0.0 - * @Co-author MeAlam, Dan - */ - private static final String basePath = "variant/entity/"; - - /** - * A {@link List} of entity names for which variants will be loaded. - *

          - * This list defines which entities will have their variants loaded from JSON files. - *

          - * - * @since 1.0.0 - * @Co-author MeAlam, Dan - */ - private static final List entityNames = Arrays.asList("dragon", "rex"); - - /** - * Loads entity variants from JSON files into the {@link MinecraftServer}. - *

          - * This method iterates through the list of entity names, constructs file paths, and registers - * entity variants using the {@link ReloadEventHandler}. - *

          - * - * @param pServer {@link MinecraftServer} - The server on which the entity variants will be loaded. - * - * @since 1.0.0 - * @author MeAlam - * @Co-author Dan - */ - public static void LoadEntityVariants(MinecraftServer pServer) { - for (String entityName : entityNames) { - String folderPath = basePath + entityName; - ReloadEventHandler.registerEntityVariants(folderPath, pServer, BlueLib.MODID, entityName); - } - } -} diff --git a/NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java b/NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java deleted file mode 100644 index a1e80d1d..00000000 --- a/NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.example.init; - -import net.minecraft.core.registries.Registries; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.MobCategory; -import net.neoforged.neoforge.registries.DeferredHolder; -import net.neoforged.neoforge.registries.DeferredRegister; -import software.bluelib.BlueLib; -import software.bluelib.example.entity.dragon.DragonEntity; -import software.bluelib.example.entity.rex.RexEntity; - -public class ModEntities { - public static final DeferredRegister> REGISTRY = DeferredRegister.create(Registries.ENTITY_TYPE, BlueLib.MODID); - - // List of Entities - public static final DeferredHolder, EntityType> DRAGON = register( - "example_one", - EntityType.Builder.of(DragonEntity::new, MobCategory.AMBIENT) - .setShouldReceiveVelocityUpdates(true) - .setTrackingRange(64) - .setUpdateInterval(3) - .fireImmune() - .sized(0.6f, 1.8f)); - - public static final DeferredHolder, EntityType> REX = register( - "example_two", - EntityType.Builder.of(RexEntity::new, MobCategory.AMBIENT) - .setShouldReceiveVelocityUpdates(true) - .setTrackingRange(64) - .setUpdateInterval(3) - .fireImmune() - .sized(0.6f, 1.8f)); - - private static DeferredHolder, EntityType> register(String pRegistryName, EntityType.Builder pEntityTypeBuilder) { - return REGISTRY.register(pRegistryName, () -> pEntityTypeBuilder.build(pRegistryName)); - } -} diff --git a/NeoForge/src/main/resources/META-INF/neoforge.mods.toml b/NeoForge/src/main/resources/META-INF/neoforge.mods.toml index ab68e198..f9345a0d 100644 --- a/NeoForge/src/main/resources/META-INF/neoforge.mods.toml +++ b/NeoForge/src/main/resources/META-INF/neoforge.mods.toml @@ -1,34 +1,33 @@ modLoader="javafml" -loaderVersion="${loader_version_range}" -license="${mod_license}" +loaderVersion="${neoforge_loader_version_range}" +license="${license}" issueTrackerURL="https://github.com/MeAlam1/BlueLib/issues" + [[mods]] -modId="bluelib" -version="1.0.0" +modId="${mod_id}" +version="${version}" displayName="${mod_name}" - # A URL to query for updates for this mod. See the JSON update specification https://docs.neoforged.net/docs/misc/updatechecker/ #updateJSONURL="https://change.me.example.invalid/updates.json" #optional displayURL="https://mealam1.github.io/BlueLib/" logoFile="bluelib.png" credits="Anyone who contributed to the Source Code of BlueLib!" -authors="${mod_authors}" - +authors="${mod_author}" +description='''${description}''' -description='''${mod_description}''' [[dependencies.bluelib]] - modId="neoforge" - type="required" - versionRange="${neo_version_range}" - ordering="NONE" - side="BOTH" +modId="neoforge" +type="required" +versionRange="${neoforge_version_range}" +ordering="NONE" +side="BOTH" [[dependencies.bluelib]] - modId="minecraft" - type="required" - versionRange="${minecraft_version_range}" - ordering="NONE" - side="BOTH" +modId="minecraft" +type="required" +versionRange="${minecraft_version_range}" +ordering="NONE" +side="BOTH" [[mixins]] config = "bluelib.mixins.json" \ No newline at end of file diff --git a/NeoForge/src/main/resources/assets/bluelib/animations/dragon.animation.json b/NeoForge/src/main/resources/assets/bluelib/animations/dragon.animation.json deleted file mode 100644 index 0b02f765..00000000 --- a/NeoForge/src/main/resources/assets/bluelib/animations/dragon.animation.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "format_version": "1.8.0", - "animations": { - "test": { - "loop": true, - "bones": { - "Body": { - "rotation": { - "vector": [-20.44582, 11.73507, -4.3361], - "easing": "linear" - }, - "position": { - "vector": [0, -1, 0], - "easing": "linear" - } - }, - "leftleg": { - "rotation": { - "vector": [0, 22.5, 0], - "easing": "linear" - } - }, - "rightleg": { - "rotation": { - "vector": [0, -22.5, 0], - "easing": "linear" - } - }, - "rightwing1": { - "rotation": { - "vector": [0, 0, -20], - "easing": "linear" - } - }, - "leftwing": { - "rotation": { - "vector": [0, 0, -10], - "easing": "linear" - } - }, - "leftwing1": { - "rotation": { - "vector": [0, 0, 30], - "easing": "linear" - } - }, - "neck": { - "rotation": { - "vector": [-40, 0, 0], - "easing": "linear" - } - }, - "Head": { - "rotation": { - "vector": [72.5, 0, 0], - "easing": "linear" - } - } - } - } - }, - "geckolib_format_version": 2 -} \ No newline at end of file diff --git a/NeoForge/src/main/resources/assets/bluelib/animations/rex.animation.json b/NeoForge/src/main/resources/assets/bluelib/animations/rex.animation.json deleted file mode 100644 index 5d8891b4..00000000 --- a/NeoForge/src/main/resources/assets/bluelib/animations/rex.animation.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "format_version": "1.8.0", - "animations": { - "animation2": { - "loop": true, - "bones": { - "body": { - "rotation": { - "vector": [0, -15, 0] - } - }, - "tail2": { - "rotation": { - "vector": [0, 20, 0] - } - }, - "tail3": { - "rotation": { - "vector": [0, 20, 0] - } - }, - "tail4": { - "rotation": { - "vector": [0, 20, 0] - } - }, - "tail5": { - "rotation": { - "vector": [0, 20, 0] - } - }, - "tail6": { - "rotation": { - "vector": [0, 20, 0] - } - }, - "neck": { - "rotation": { - "vector": [0, -2.5, 0] - } - }, - "head": { - "rotation": { - "vector": [0, -20, 0] - } - } - } - } - }, - "geckolib_format_version": 2 -} \ No newline at end of file diff --git a/NeoForge/src/main/resources/assets/bluelib/geo/dragon.geo.json b/NeoForge/src/main/resources/assets/bluelib/geo/dragon.geo.json deleted file mode 100644 index 8f038886..00000000 --- a/NeoForge/src/main/resources/assets/bluelib/geo/dragon.geo.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "format_version": "1.12.0", - "minecraft:geometry": [ - { - "description": { - "identifier": "geometry.unknown", - "texture_width": 64, - "texture_height": 64, - "visible_bounds_width": 4, - "visible_bounds_height": 2.5, - "visible_bounds_offset": [0, 0.75, 0] - }, - "bones": [ - { - "name": "Body", - "pivot": [-0.16667, 5, -1], - "cubes": [ - {"origin": [-2, 4, 1], "size": [4, 2, 4], "uv": [17, 10]}, - {"origin": [-3, 4, -4], "size": [6, 2, 5], "uv": [0, 14]} - ] - }, - { - "name": "leftleg", - "parent": "Body", - "pivot": [1.5, 5, 5], - "cubes": [ - {"origin": [1.5, 3, 4.5], "size": [0, 4, 3], "pivot": [1.5, 5, 6], "rotation": [90, 0, 90], "uv": [0, 0]} - ] - }, - { - "name": "rightleg", - "parent": "Body", - "pivot": [-1.5, 5, 5], - "cubes": [ - {"origin": [-1.5, 3, 4.5], "size": [0, 4, 3], "pivot": [-1.5, 5, 6], "rotation": [90, 0, -90], "uv": [0, 0], "mirror": true} - ] - }, - { - "name": "rightwing", - "parent": "Body", - "pivot": [-2.5, 5, -3.5], - "cubes": [ - {"origin": [-10, 5, -5], "size": [7, 0, 7], "uv": [-7, 28], "mirror": true} - ] - }, - { - "name": "rightwing1", - "parent": "rightwing", - "pivot": [-9.5, 5, -1.5], - "cubes": [ - {"origin": [-17, 5, -5], "size": [7, 0, 7], "uv": [43, 0], "mirror": true} - ] - }, - { - "name": "leftwing", - "parent": "Body", - "pivot": [2.5, 5, -3.5], - "cubes": [ - {"origin": [3, 5, -5], "size": [7, 0, 7], "uv": [-7, 28]} - ] - }, - { - "name": "leftwing1", - "parent": "leftwing", - "pivot": [9.5, 5, -1.5], - "cubes": [ - {"origin": [10, 5, -5], "size": [7, 0, 7], "uv": [43, 0]} - ] - }, - { - "name": "neck", - "parent": "Body", - "pivot": [0, 5, -4], - "cubes": [ - {"origin": [-1, 4, -8], "size": [2, 2, 4], "uv": [10, 21]} - ] - }, - { - "name": "Head", - "parent": "neck", - "pivot": [0, 4.8, -7.5], - "cubes": [ - {"origin": [-1.5, 4, -12], "size": [3, 3, 4], "uv": [18, 17]}, - {"origin": [0, 6, -15], "size": [0, 3, 7], "uv": [0, 14]}, - {"origin": [-1, 4, -16], "size": [2, 2, 4], "uv": [21, 0]}, - {"origin": [-1, 3, -16], "size": [2, 1, 1], "uv": [29, 0]}, - {"origin": [0, 7, -8], "size": [0, 1, 3], "uv": [0, 23]} - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/NeoForge/src/main/resources/assets/bluelib/geo/rex.geo.json b/NeoForge/src/main/resources/assets/bluelib/geo/rex.geo.json deleted file mode 100644 index 3d18bac7..00000000 --- a/NeoForge/src/main/resources/assets/bluelib/geo/rex.geo.json +++ /dev/null @@ -1,390 +0,0 @@ -{ - "format_version": "1.12.0", - "minecraft:geometry": [ - { - "description": { - "identifier": "geometry.unknown", - "texture_width": 512, - "texture_height": 512, - "visible_bounds_width": 29, - "visible_bounds_height": 7.5, - "visible_bounds_offset": [0, 3.25, 0] - }, - "bones": [ - { - "name": "Tyrannosaurus", - "pivot": [0, 0, 0] - }, - { - "name": "body", - "parent": "Tyrannosaurus", - "pivot": [0, 72, 0], - "cubes": [ - {"origin": [-19, 47, -8], "size": [38, 45, 34], "uv": [124, 51]}, - {"origin": [-15.475, 51.23327, -14.01496], "size": [31, 45, 35], "pivot": [0.025, 74.40827, 4.38504], "rotation": [-12.75, 0, 0], "uv": [130, 50]}, - {"origin": [-16, 40, -22.525], "size": [32, 16, 40], "inflate": -0.05, "pivot": [0, 72, 0.275], "rotation": [17.5, 0, 0], "uv": [0, 160]}, - {"origin": [-16, 54, -54], "size": [32, 37, 46], "uv": [1, 1]}, - {"origin": [-16, 71.46448, -54.53145], "size": [32, 30, 48], "inflate": -0.25, "pivot": [0, 89.46448, 3.46855], "rotation": [8.75, 0, 0], "uv": [-1, -1]}, - {"origin": [-16, 28.37894, -42.36923], "size": [32, 21, 49], "inflate": -0.025, "pivot": [0, 73.37894, 12.63077], "rotation": [-24, 0, 0], "uv": [0, 85]} - ] - }, - { - "name": "arm2", - "parent": "body", - "pivot": [13.56731, 58.46159, -45.9607], - "rotation": [29.07337, 19.05681, -20.20848], - "cubes": [ - {"origin": [12.56731, 47.46159, -47.9607], "size": [3, 11, 5], "uv": [111, 0]} - ] - }, - { - "name": "bone2", - "parent": "arm2", - "pivot": [15.06274, 49.29312, -45.32771], - "rotation": [-27.154, -2.96386, 4.54476], - "cubes": [ - {"origin": [13.13695, 39.306, -44.80271], "size": [2, 6, 2], "inflate": -0.075, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [0, 0]}, - {"origin": [14.86195, 37.306, -44.75271], "size": [0, 3, 2], "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [36, 26]}, - {"origin": [12.13695, 44.306, -47.52771], "size": [3, 5, 5], "inflate": -0.125, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [165, 257]} - ] - }, - { - "name": "bone3", - "parent": "bone2", - "pivot": [13.25685, 45.11756, -46.37771], - "rotation": [-14.50257, -2.95519, -2.10666], - "cubes": [ - {"origin": [13.13695, 41.306, -47.37771], "size": [2, 4, 2], "inflate": -0.075, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [0, 28]}, - {"origin": [14.86195, 39.306, -47.37771], "size": [0, 3, 2], "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [36, 29]} - ] - }, - { - "name": "arm3", - "parent": "body", - "pivot": [-13.56731, 58.46159, -45.9607], - "rotation": [29.07337, -19.05681, 20.20848], - "cubes": [ - {"origin": [-15.56731, 47.46159, -47.9607], "size": [3, 11, 5], "uv": [111, 0], "mirror": true} - ] - }, - { - "name": "bone4", - "parent": "arm3", - "pivot": [-15.06274, 49.29312, -45.32771], - "rotation": [-27.154, 2.96386, -4.54476], - "cubes": [ - {"origin": [-15.13695, 39.306, -44.80271], "size": [2, 6, 2], "inflate": -0.075, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [0, 0], "mirror": true}, - {"origin": [-14.86195, 37.306, -44.75271], "size": [0, 3, 2], "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [36, 26], "mirror": true}, - {"origin": [-15.13695, 44.306, -47.52771], "size": [3, 5, 5], "inflate": -0.125, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [165, 257], "mirror": true} - ] - }, - { - "name": "bone5", - "parent": "bone4", - "pivot": [-13.25685, 45.11756, -46.37771], - "rotation": [-14.50257, 2.95519, 2.10666], - "cubes": [ - {"origin": [-15.13695, 41.306, -47.37771], "size": [2, 4, 2], "inflate": -0.075, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [0, 28], "mirror": true}, - {"origin": [-14.86195, 39.306, -47.37771], "size": [0, 3, 2], "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [36, 29], "mirror": true} - ] - }, - { - "name": "tail1", - "parent": "body", - "pivot": [0, 82.97049, 21.3522], - "cubes": [ - {"origin": [-15, 55.74549, 21.0272], "size": [30, 30, 39], "uv": [123, 128]}, - {"origin": [-15, 71.63781, 17.37365], "size": [30, 28, 35], "inflate": -0.2, "pivot": [0, 60.21281, -16.55135], "rotation": [-10.75, 0, 0], "uv": [127, 132]}, - {"origin": [-15, 39.02049, 26.7772], "size": [30, 13, 37], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [16, 0, 0], "uv": [159, 1]} - ] - }, - { - "name": "tail2", - "parent": "tail1", - "pivot": [0, 82.97049, 56.3522], - "cubes": [ - {"origin": [-10, 62.97049, 56.3522], "size": [20, 21, 38], "uv": [106, 199]}, - {"origin": [-9, 41.02049, 63.3522], "size": [18, 14, 35], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [13, 0, 0], "uv": [173, 3]} - ] - }, - { - "name": "tail3", - "parent": "tail2", - "pivot": [0, 82.97049, 93.3522], - "cubes": [ - {"origin": [-7, 66.97049, 93.3522], "size": [14, 14, 37], "uv": [0, 216]}, - {"origin": [-7, 54.52049, 94.3522], "size": [14, 7, 38], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [5.5, 0, 0], "uv": [174, 0]} - ] - }, - { - "name": "tail4", - "parent": "tail3", - "pivot": [0, 82.97049, 129.3522], - "cubes": [ - {"origin": [-5, 69.97049, 129.3522], "size": [10, 9, 37], "uv": [255, 14]}, - {"origin": [-5, 64.82049, 132.6022], "size": [10, 4, 37], "inflate": -0.025, "pivot": [0, 30.97049, 109.3522], "rotation": [4.75, 0, 0], "uv": [255, 14]} - ] - }, - { - "name": "tail5", - "parent": "tail4", - "pivot": [0, 82.97049, 158.3522], - "cubes": [ - {"origin": [-3, 70.97049, 158.3522], "size": [6, 6, 37], "uv": [149, 257]}, - {"origin": [-3, 69.22961, 165.59014], "size": [6, 3, 30], "inflate": -0.1, "pivot": [0, 70.15461, 147.99014], "rotation": [0.5, 0, 0], "uv": [266, 21]} - ] - }, - { - "name": "tail6", - "parent": "tail5", - "pivot": [0, 82.97049, 182.3522], - "cubes": [ - {"origin": [-2, 71.97049, 182.3522], "size": [4, 4, 37], "uv": [0, 285]}, - {"origin": [-2, 66.99549, 197.7022], "size": [4, 4, 25], "inflate": -0.175, "pivot": [0, 30.97049, 162.3522], "rotation": [4.75, 0, 0], "uv": [12, 297]} - ] - }, - { - "name": "neck", - "parent": "body", - "pivot": [0, 74.22605, -48.50511], - "cubes": [ - {"origin": [-15, 55, -67], "size": [30, 31, 17], "uv": [251, 113]}, - {"origin": [-14.25, 80.39311, -64.98257], "size": [30, 11, 17], "inflate": -1, "pivot": [0.75, 82.39311, -53.98257], "rotation": [24.25, 0, 0], "uv": [251, 113]}, - {"origin": [-10, 66.05, -70.125], "size": [20, 34, 25], "inflate": -0.225, "pivot": [0, 87.575, -69.125], "rotation": [-39.25, 0, 0], "uv": [221, 200]}, - {"origin": [-10, 59.575, -78.125], "size": [20, 13, 25], "inflate": -1.325, "pivot": [0, 87.575, -69.125], "rotation": [-14.25, 0, 0], "uv": [235, 259]}, - {"origin": [-9, 71.2, -85.125], "size": [18, 19, 24], "inflate": -0.325, "pivot": [0, 85.2, -69.125], "rotation": [7.5, 0, 0], "uv": [268, 61]}, - {"origin": [-8, 83.89159, -88.09601], "size": [16, 12, 13], "inflate": -0.275, "pivot": [0, 89.89159, -79.09601], "rotation": [42.5, 0, 0], "uv": [198, 259]}, - {"origin": [-8, 86.39159, -80.39601], "size": [16, 11, 19], "inflate": -0.25, "pivot": [0, 89.89159, -68.09601], "rotation": [2.5, 0, 0], "uv": [111, 0]} - ] - }, - { - "name": "head", - "parent": "neck", - "pivot": [0, 83.05369, -83.57238], - "cubes": [ - {"origin": [-8.725, 71, -101], "size": [17, 19, 19], "uv": [286, 165]}, - {"origin": [-8.775, 84, -101], "size": [17, 2, 7], "inflate": 0.225, "uv": [104, 155]}, - {"origin": [-7, 93.5819, -99.5906], "size": [14, 5, 10], "inflate": -0.05, "pivot": [0, 90.5819, -77.5906], "rotation": [21.5, 0, 0], "uv": [0, 111]}, - {"origin": [-7, 81.46532, -93.49693], "size": [14, 5, 9], "inflate": -0.075, "pivot": [0, 78.46532, -74.49693], "rotation": [-25, 0, 0], "uv": [111, 30]}, - {"origin": [-7, 88.64032, -92.02193], "size": [14, 5, 4], "inflate": -0.125, "uv": [0, 191]}, - {"origin": [9, 86, -102], "size": [4, 3, 13], "inflate": -0.025, "pivot": [7, 80.5, -90.5], "rotation": [0, 0, -17.5], "uv": [149, 277]}, - {"origin": [4.59053, 84.6097, -93.1055], "size": [4, 3, 9], "inflate": -0.05, "pivot": [2.59053, 79.1097, -81.6055], "rotation": [0, -27.5, -17.5], "uv": [255, 23]}, - {"origin": [-8.59053, 84.6097, -93.1055], "size": [4, 3, 9], "inflate": -0.05, "pivot": [-2.59053, 79.1097, -81.6055], "rotation": [0, 27.5, 17.5], "uv": [184, 225]}, - {"origin": [12.62776, 90.52364, -107.52067], "size": [4, 3, 11], "inflate": -0.1, "pivot": [10.62776, 85.02364, -91.02067], "rotation": [27.87149, 36.42355, -5.95346], "uv": [0, 239]}, - {"origin": [-16.62776, 90.52364, -107.52067], "size": [4, 3, 11], "inflate": -0.1, "pivot": [-10.62776, 85.02364, -91.02067], "rotation": [27.87149, -36.42355, 5.95346], "uv": [162, 0]}, - {"origin": [-13, 86, -102], "size": [4, 3, 13], "inflate": -0.025, "pivot": [-7, 80.5, -90.5], "rotation": [0, 0, 17.5], "uv": [109, 216]}, - {"origin": [-7, 78.725, -121], "size": [14, 10, 16], "inflate": -0.05, "pivot": [0, 81.725, -99], "rotation": [27.5, 0, 0], "uv": [300, 243]}, - {"origin": [-7, 78.35, -106], "size": [14, 11, 11], "pivot": [0, 81.35, -99], "rotation": [33.5, 0, 0], "uv": [286, 203]}, - {"origin": [-7, 69.519, -125.21974], "size": [14, 11, 7.85], "inflate": -0.075, "pivot": [0, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [259, 165]}, - {"origin": [-6, 78.519, -128.21974], "size": [11, 0, 7.85], "pivot": [0, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [141, 30]}, - {"origin": [5, 61.519, -128.21974], "size": [0, 17, 6.85], "pivot": [-2, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [234, 45]}, - {"origin": [-5, 61.519, -128.21974], "size": [0, 17, 6.85], "pivot": [2, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [28, 154]}, - {"origin": [-7, 73.394, -115.21974], "size": [14, 10, 6.85], "inflate": -0.1, "pivot": [0, 74.394, -109.21974], "rotation": [110.5, 0, 0], "uv": [65, 237]}, - {"origin": [-7, 84.31148, -108.92962], "size": [14, 4, 6.85], "inflate": -0.15, "pivot": [0, 79.31148, -102.92962], "rotation": [128, 0, 0], "uv": [272, 0]}, - {"origin": [-7, 74.31148, -110.92962], "size": [14, 9, 8.85], "inflate": -0.175, "pivot": [0, 79.31148, -102.92962], "rotation": [88, 0, 0], "uv": [0, 28]}, - {"origin": [-7, 69.019, -122.66974], "size": [14, 10, 7], "inflate": -0.125, "pivot": [0, 72.019, -117.66974], "rotation": [47.5, 0, 0], "uv": [0, 267]} - ] - }, - { - "name": "jaw", - "parent": "head", - "pivot": [0, 73.374, -85.20224], - "cubes": [ - {"origin": [-9.125, 61.47673, -99.81697], "size": [18, 13, 12], "inflate": 0.025, "uv": [184, 200]}, - {"origin": [-9.15, 64.14383, -89.12484], "size": [18, 12, 7], "inflate": 0.075, "pivot": [-3, 73.14383, -68.12484], "rotation": [7.5, 0, 0], "uv": [312, 0]}, - {"origin": [7.8, 70.81044, -97.91351], "size": [1, 6, 9], "uv": [104, 179]}, - {"origin": [7.85, 63.60089, -93.15375], "size": [1, 6, 7], "pivot": [-2.975, 63.60089, -72.15375], "rotation": [-22.5, 0, 0], "uv": [65, 216]}, - {"origin": [-7.125, 72.47673, -98.81697], "size": [14, 14, 16], "inflate": 0.025, "uv": [219, 297]}, - {"origin": [6.375, 68.47673, -105.81697], "size": [0, 18, 14], "uv": [0, 159]}, - {"origin": [-6.625, 68.47673, -105.81697], "size": [0, 18, 14], "uv": [0, 141]}, - {"origin": [7.875, 65.38327, -112.3007], "size": [1, 8, 15], "inflate": -0.05, "pivot": [0, 73.88327, -104.8007], "rotation": [27.5, 0, 0], "uv": [255, 0]}, - {"origin": [-9.125, 65.38327, -112.3007], "size": [1, 8, 15], "inflate": -0.05, "pivot": [0, 73.88327, -104.8007], "rotation": [27.5, 0, 0], "uv": [0, 216]}, - {"origin": [-9.05, 70.81044, -97.91351], "size": [1, 6, 9], "uv": [104, 164]}, - {"origin": [-9.1, 63.60089, -93.15375], "size": [1, 6, 7], "pivot": [2.975, 63.60089, -72.15375], "rotation": [-22.5, 0, 0], "uv": [17, 216]}, - {"origin": [-9.125, 64.31864, -111.04094], "size": [18, 8, 15], "inflate": -0.025, "pivot": [0, 70.56864, -103.54094], "rotation": [17.5, 0, 0], "uv": [149, 300]}, - {"origin": [-6.125, 66.9078, -126.60427], "size": [12, 5, 15], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [126, 257]}, - {"origin": [-6.125, 71.5078, -125.60427], "size": [12, 5, 0], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [62, 155]}, - {"origin": [5.725, 71.5078, -125.60427], "size": [0, 5, 17], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [28, 138]}, - {"origin": [-5.975, 71.5078, -125.60427], "size": [0, 5, 17], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [0, 109]}, - {"origin": [-6.125, 60.70962, -124.43479], "size": [12, 5, 15], "inflate": -0.05, "pivot": [0, 63.78462, -115.43479], "rotation": [-3.5, 0, 0], "uv": [234, 61]}, - {"origin": [-7.125, 61.71743, -111.29498], "size": [14, 5, 16], "inflate": -0.025, "pivot": [0, 66.69243, -101.79498], "rotation": [9.25, 0, 0], "uv": [65, 216]} - ] - }, - { - "name": "leg_left", - "parent": "Tyrannosaurus", - "pivot": [20.42923, 70.7324, 8.85434], - "rotation": [-15.09173, -1.85092, -0.08398], - "cubes": [ - {"origin": [12.54366, 41.02086, -4.25109], "size": [12.875, 42.825, 23.725], "uv": [79, 257]} - ] - }, - { - "name": "leg_left2", - "parent": "leg_left", - "pivot": [21.99279, 43.52539, 1.69711], - "cubes": [ - {"origin": [12.844, 24.19389, 3.09297], "size": [12.4, 20.375, 15.95], "pivot": [21.944, 35.38139, 0.96797], "rotation": [34, 0, 0], "uv": [279, 297]} - ] - }, - { - "name": "leg_left3", - "parent": "leg_left2", - "pivot": [19.76532, 33.92692, 13.90262], - "rotation": [55, 0, 0], - "cubes": [ - {"origin": [14.22989, 14.97535, 9.92239], "size": [10, 19, 9], "inflate": -0.1, "uv": [0, 0]} - ] - }, - { - "name": "leg_left4", - "parent": "leg_left3", - "pivot": [19.76532, 14.92692, 13.90262], - "rotation": [-60, 0, 0], - "cubes": [ - {"origin": [14.22989, 2.41759, 7.14887], "size": [10, 17, 9], "inflate": 0.375, "uv": [0, 85]} - ] - }, - { - "name": "Claw5", - "parent": "leg_left4", - "pivot": [18.03922, 11.69239, 7.72125], - "rotation": [3.25353, -39.92899, -4.10228], - "cubes": [ - {"origin": [19.68942, 7.60244, 18.32118], "size": [2, 5, 6], "inflate": -0.2, "pivot": [20.68942, 10.90244, 16.32118], "rotation": [4, 5, 0], "uv": [19, 239]}, - {"origin": [15.96316, 8.07744, 15.28926], "size": [2, 3, 4], "inflate": 0.5, "pivot": [20.4918, 5.40696, 3.40745], "rotation": [2.31336, 4.43385, 27.58957], "uv": [29, 0]} - ] - }, - { - "name": "leg_left5", - "parent": "leg_left4", - "pivot": [19.76532, 2.72669, 9.58045], - "rotation": [32.5, 0, 0], - "cubes": [ - {"origin": [14.22989, -4.78265, 7.2517], "size": [10, 8, 8], "inflate": 0.35, "uv": [42, 267]} - ] - }, - { - "name": "Claw3", - "parent": "leg_left5", - "pivot": [14.03922, -1.93376, 9.83799], - "rotation": [-11.28559, 36.03256, -29.0792], - "cubes": [ - {"origin": [15.68942, -5.02371, -6.76194], "size": [2, 4, 9], "inflate": -0.2, "pivot": [16.68942, -2.72371, 1.23806], "rotation": [-4, -5, 0], "uv": [78, 267]}, - {"origin": [11.96316, -5.54871, -1.73002], "size": [2, 3, 12], "inflate": 0.5, "pivot": [16.4918, -8.21919, 14.15179], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [45, 298]}, - {"origin": [13.86316, -1.04871, -0.45502], "size": [2, 3, 12], "inflate": 0.4, "pivot": [18.3918, -3.71919, 15.42679], "rotation": [14.70847, -5.40113, 27.33492], "uv": [263, 297]} - ] - }, - { - "name": "Claw2", - "parent": "leg_left5", - "pivot": [18.00128, -1.52657, 8.77203], - "rotation": [6.46283, 10.46681, -26.49382], - "cubes": [ - {"origin": [19.65148, -4.61652, -7.8279], "size": [2, 4, 9], "inflate": -0.2, "pivot": [20.65148, -2.31652, 0.1721], "rotation": [-8.25367, -3.37646, 28.00254], "uv": [259, 183]}, - {"origin": [15.92522, -5.14152, -2.79598], "size": [2, 3, 12], "inflate": 0.5, "pivot": [20.45386, -7.812, 13.08583], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [0, 284]}, - {"origin": [17.82522, -0.64152, -1.52098], "size": [2, 3, 12], "inflate": 0.4, "pivot": [22.35386, -3.312, 14.36083], "rotation": [14.70847, -5.40113, 27.33492], "uv": [45, 283]} - ] - }, - { - "name": "Claw4", - "parent": "leg_left5", - "pivot": [25.00339, -1.78444, 9.60342], - "rotation": [-6.62428, -31.83686, 25.40349], - "cubes": [ - {"origin": [21.35319, -4.87439, -6.99651], "size": [2, 4, 9], "inflate": -0.2, "pivot": [22.35319, -2.57439, 1.00349], "rotation": [-4, 5, 0], "uv": [172, 21]}, - {"origin": [25.07945, -5.39939, -1.96459], "size": [2, 3, 12], "inflate": 0.5, "pivot": [22.55081, -8.06987, 13.91722], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [222, 145]}, - {"origin": [23.17945, -0.89939, -0.68959], "size": [2, 3, 12], "inflate": 0.4, "pivot": [20.65081, -3.56987, 15.19222], "rotation": [14.70847, 5.40113, -27.33492], "uv": [222, 130]} - ] - }, - { - "name": "leg_right", - "parent": "Tyrannosaurus", - "pivot": [-20.42923, 70.7324, 8.85434], - "rotation": [-15.09173, 1.85092, 0.08398], - "cubes": [ - {"origin": [-25.41866, 41.02086, -4.25109], "size": [12.875, 42.825, 23.725], "uv": [79, 257], "mirror": true} - ] - }, - { - "name": "leg_right2", - "parent": "leg_right", - "pivot": [-21.99279, 43.52539, 1.69711], - "cubes": [ - {"origin": [-25.244, 24.19389, 3.09297], "size": [12.4, 20.375, 15.95], "pivot": [-21.944, 35.38139, 0.96797], "rotation": [34, 0, 0], "uv": [279, 297], "mirror": true} - ] - }, - { - "name": "leg_right3", - "parent": "leg_right2", - "pivot": [-19.76532, 33.92692, 13.90262], - "rotation": [55, 0, 0], - "cubes": [ - {"origin": [-24.22989, 14.97535, 9.92239], "size": [10, 19, 9], "inflate": -0.1, "uv": [0, 0], "mirror": true} - ] - }, - { - "name": "leg_right4", - "parent": "leg_right3", - "pivot": [-19.76532, 14.92692, 13.90262], - "rotation": [-60, 0, 0], - "cubes": [ - {"origin": [-24.22989, 2.41759, 7.14887], "size": [10, 17, 9], "inflate": 0.375, "uv": [0, 85], "mirror": true} - ] - }, - { - "name": "Claw6", - "parent": "leg_right4", - "pivot": [-18.03922, 11.69239, 7.72125], - "rotation": [3.25353, 39.92899, 4.10228], - "cubes": [ - {"origin": [-21.68942, 7.60244, 18.32118], "size": [2, 5, 6], "inflate": -0.2, "pivot": [-20.68942, 10.90244, 16.32118], "rotation": [4, -5, 0], "uv": [19, 239], "mirror": true}, - {"origin": [-17.96316, 8.07744, 15.28926], "size": [2, 3, 4], "inflate": 0.5, "pivot": [-20.4918, 5.40696, 3.40745], "rotation": [2.31336, -4.43385, -27.58957], "uv": [29, 0], "mirror": true} - ] - }, - { - "name": "leg_right5", - "parent": "leg_right4", - "pivot": [-19.76532, 2.72669, 9.58045], - "rotation": [32.5, 0, 0], - "cubes": [ - {"origin": [-24.22989, -4.78265, 7.2517], "size": [10, 8, 8], "inflate": 0.35, "uv": [42, 267], "mirror": true} - ] - }, - { - "name": "Claw7", - "parent": "leg_right5", - "pivot": [-14.03922, -1.93376, 9.83799], - "rotation": [-11.28559, -36.03256, 29.0792], - "cubes": [ - {"origin": [-17.68942, -5.02371, -6.76194], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-16.68942, -2.72371, 1.23806], "rotation": [-4, 5, 0], "uv": [78, 267], "mirror": true}, - {"origin": [-13.96316, -5.54871, -1.73002], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-16.4918, -8.21919, 14.15179], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [45, 298], "mirror": true}, - {"origin": [-15.86316, -1.04871, -0.45502], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-18.3918, -3.71919, 15.42679], "rotation": [14.70847, 5.40113, -27.33492], "uv": [263, 297], "mirror": true} - ] - }, - { - "name": "Claw8", - "parent": "leg_right5", - "pivot": [-18.00128, -1.52657, 8.77203], - "rotation": [6.46283, -10.46681, 26.49382], - "cubes": [ - {"origin": [-21.65148, -4.61652, -7.8279], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-20.65148, -2.31652, 0.1721], "rotation": [-8.25367, 3.37646, -28.00254], "uv": [259, 183], "mirror": true}, - {"origin": [-17.92522, -5.14152, -2.79598], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-20.45386, -7.812, 13.08583], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [0, 284], "mirror": true}, - {"origin": [-19.82522, -0.64152, -1.52098], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-22.35386, -3.312, 14.36083], "rotation": [14.70847, 5.40113, -27.33492], "uv": [45, 283], "mirror": true} - ] - }, - { - "name": "Claw9", - "parent": "leg_right5", - "pivot": [-25.00339, -1.78444, 9.60342], - "rotation": [-6.62428, 31.83686, -25.40349], - "cubes": [ - {"origin": [-23.35319, -4.87439, -6.99651], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-22.35319, -2.57439, 1.00349], "rotation": [-4, -5, 0], "uv": [172, 21], "mirror": true}, - {"origin": [-27.07945, -5.39939, -1.96459], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-22.55081, -8.06987, 13.91722], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [222, 145], "mirror": true}, - {"origin": [-25.17945, -0.89939, -0.68959], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-20.65081, -3.56987, 15.19222], "rotation": [14.70847, -5.40113, 27.33492], "uv": [222, 130], "mirror": true} - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/NeoForge/src/main/resources/assets/bluelib/lang/en_us.json b/NeoForge/src/main/resources/assets/bluelib/lang/en_us.json deleted file mode 100644 index 8371c823..00000000 --- a/NeoForge/src/main/resources/assets/bluelib/lang/en_us.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "entity.bluelib.example_one": "Example", - "entity.bluelib.example_two": "Example" -} \ No newline at end of file diff --git a/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png b/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png deleted file mode 100644 index 83be2147b8db3aaab415e12dc3b6e9a11a594ea4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!7Pn|)P)=iz4q{MmaJHmZ`5KTT zT@vIM%(v z(aRpoCoWyiTgojaD&F|F!PdZVM@UbNjptVBj4jLF?f%O$LFQ-3hJ{yuCnpH{RqTF0 zeUaRrN`{moTZcM{69EVLnQmQO%s%OtOoW(UeeqPr*})2&$=17>Km8Ke@%eU3;;UAl z_dE-lA2QvTo9bV8@y{Lo#EEr$XX6_ew|<>1!7nqtJ8%c@3EiH9*VZm)@~qx!CojNR zaWk9uaEODlE8kU9hhhtcCz6N4bsR43<#29rQagW3>HO}AsXY7mmmhHEtgR04`g-ue zwv#SzoSD}|v`Lv6asM;6d&}sM&)V{9@7_H|f67<|ydtWYcW8+%(7BtgsyBPB&W+HL z{c<<=%Uw8|weJPP@nd2)_peY@i7iud+B+%Zp5z_{-H+UVy3Ca989GZ6MLiBbQ|UWb z(Y^fs4MF?eSt1usd41cW*!(Qw)s%f3B9+u@XC5>Aq_Xz;j^mF{Oz1waD#L%1(lgZ; z3|#E;@8(@%^IqToRn(#6{C~ELFSiAJm_Id{T)EuXZp3k!(UWyjbJC~xst$5b_e=bf q?_)BNT$9h7r)_M&3`GSo`xu+NS2^bO6ubn+JAk44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!&W-dj)XETq4p!hyw%*PB>6gHc&$n9=U$y$Y z=ULGFkm<(URR6k*f9~ifPORfQ8{fFN_3La2ewpdrfjf9l==L1Ewstv_XZ2P)c>&If zo7udFLmZS{`L3Ee6k9MnkvtTx<8Wy&hjW9I+WA{b=XXy`<=Mx-{D3oOZFPXx*MkqX zopgEQ%)BO|P0GxO`=7DhTSkX`)|Ov;_wF(JQ^qRb6;Z{!LrZLd&fRoXz1eGZZiJTX zm%F)N?!wuueJ>b}9}~N|e}$?_Y?+eN-boqvB=;!je&qhsWu|1$&{>iw>T&p)O5eGP z?&bGy2-@$?61i~7>)RH^=4TPFrtI4gsia;z^O)Hum9@`z9DjUbLid4H8UCA;o~gcI z;9{45H}4Xg_xk>?q7EhJ|FdO$xh>$s{He+0%H_s(BaX|Ao~)CalRmvyb&z|yU*ey9 qACrmXntbLwZDRvwC@P5A$Jpe($}z8};3Y8L89ZJ6T-G@yGywpxb1(q_ diff --git a/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png b/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png deleted file mode 100644 index 56c9452f64ef0b1e71cecef3b4d07f56ae847633..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!mKPJ^=Hz5!W#wdNPn^2p^s67*vJwUgQb~?#2X}7uGm#gP zQ06^oDwgx$fq}uR<%$^@8TFMVidv2~UU@d+Y|c^~DgvxPb0$Wc7}!LuS~IT`$dN7y z@(X78j}sipEHVW;@~EeaV@SoEw^wiHEjAEfdvHHFiDPf3^4f2I61s;NV<1;Z1`L*Y6Om-ccvH#n)Czom43_rz45ef-N0ICIuk2Y7uw_+Z;f zmp9JLYa-gD%#67I8QZ;ObjW9I`L%cN9-}{HtO8yURm?lI#1`n>O;^>My;kQ&Xvu!L zoBQQ1oXy(zg5mfvv77r>sH()4DLL((lyOgTkAm(;?mt~-O7;w$C5fUQho7nRovY|x ze*cD`{q8K03#YukZBcA~7V&Dzz73H|>a{bEnSD}O`+Udo$0sIqA6S*)ze(wt>I()g zcKLVnF0py9@Bb?5P;&l1TgI2$0zS;2noO=-ZfrN=xXkFuI;lD7(|c71xu^Rj{>k?- onMkh5XU@|$HeiOLf|z}bP2Q^<^Lh$i0^^;*)78&qol`;+0O_S2&j0`b diff --git a/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png b/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png deleted file mode 100644 index adbd4aba3aedfc3c346c7fcbcd858cbe4dd261e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!Zjwt65OA~RHu2!IKd|xH`;UJotCY^rs5}_f`{vw>EiO$N z3LOzw<`r~)`(`)e=Yh7PEk`d-JKbu&a%s|urSjIR6`Z;x41ng`DxW(eV9(;TfP5fF zx+KUinBhN8a3r(H6zIsKo-U3d6?5KRy`8t%K!EMR{p2K$y_w2uzx|D07t}vHbT_ZS zqnACFPh7g3x0G8Pb3e8>o{E6%i-MMq;~$6()ryJQ+f9BFF)YSSz8_8_4VL` zZ6{scI5V$_Xp=HC;{IoB_m!M8-n(`vqUbO^7^(#vH4lVt10_7L@KG*&OB!JNoDQx9mgM^n9zM-Rfhj2rDv)y z7`WKw-_5(k=DoiEtEfZC`TuMgUv3NdFn?+?xpKL&-H78dqbKX6=A=*WRUPD>?w9x{ q-^XMkxh9`EPutjl8Hx&G_AxejuX4=mDR>EtcLq;aKbLh*2~7ZCIW7SJ diff --git a/NeoForge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png b/NeoForge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png deleted file mode 100644 index f2956d0504901ccd33fb2067b7631ba08471c5ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3454 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 or57IkfgP>p|9}4H3?K* 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%0D$ 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 z zeTA=L+L+&ZdKJt8$5UC(LR@MUJXLq|gDiV}Yj7tYFcVoQX3byOMJt~5w=-^K5^vlt zcRB#^V1}RQ9m}T03vJ0jQ!hz7(|89N+6S$q)dI4VMV)0oL|pvOF&Nv6oJPjPH%0R`E6$s0!DG#G&|IPB|QE{j=oOK8(b7eB? z0$5;Y|LQa4+Gvi#zcFa3Pw}9(ca%9U0d+Cf^MmJt17~yhX?tU<`F6h|AWjl$M%g=m z!}TtDL&V{KOcIOfEJQP&ir}*d#;3q1A1eX;xj(YT$ZqZ11IiUobg2!*4E_PylEy{IWTN>wpet+T8b`m~bdr}Id zqF34X1uiM^<;TZP!!*;u5N5loTW?(tSN=Waw(vC{R z{D9*TUS}aH4`(75p}R{3fxl_z)FY@xSo-7g3HWJ;c$$Wr;yXWv;vmnvP$C-!MR=_O z58Vf!$jzTJd)u%vyb6I8aZ=`%!vxIV8hGUK3ac(}%!fgQZo3$P`ZX|FAfN=Gx$ z`PZsW1&yYeEW9!e)Za(w{Rf}b{x`;7U&4}j!Zo$TG1!--cioMISA~G&OH{6dE(0^2 z0$zsD`%eX?0S9THoipNz*px{6;dR7cN#7M((OCJkT%U0X|BUEtV<@1KX`a% z4`70@6J>SnuhGzs60rz3`d2g*LIn6SqtCTx2KuH|^|N4?y!0!)x#hJwCBqeZ1=*33 z3ctXp;+9$dnxh|6sMk@KAn%5(?Q_cVl_NVA8>W*^h1F^(f;?Ujh;CQxXF zVn@(-es+|eymI;S0v#JhWcECYU_WJ-wDkioGYm{=D?fgcLA!JfyXFv`{ufXl_v1nQ z_X7LrgoRI@SX=w%V}t$u_^AQrv_ zZh^YqoKY=;78)HN)A)TFV_4y1+G#o3)AZh=F|n3thq_)KA+-KynHj%2y;+_>-*K2m z_E#`zY}*DK`p@$G5#@bqor;a2cuf`R(64!xX$-x>BYCtuy{^PP8XG{uL;`xd<&sXP z0=jTF3LOl1I>^q=I#XqnM)om;bcO&kPt=>-S3?@`!L6E;R{L^@*fFm_PoU-+Hd z*@yYl94oZ&AS=j5m4S9~U5oamAV=0NEjW7_`2{Iyw{#Nc2%X4p6L%ZRu3>|}%9iz{GH|rx5|awRGK~<6RCF{OL>9_{*#*U} z3{-h&Iw~%lgU2Tk8XYfA?CIuGKf*F%qg(?J2_4N9pNxo!EWQo5($K%aTX{Xg8_>Uh znzu&9jaL`H=f${|p&fTR3uwQ};3dQpvXuu#A*)#) zhFj?qB6P@db_D(q6}q0xcebzp(ofr%?DmlG?Mc1B-TzkJwf-_ zjv=&5p72!hI_o&_YsmF4fscImycl=8@c7efYk$JX{tSBp9~9VLRfu~jQ=iS0NAcvf z^2h!I%A}v2NXPP}jNHrcrh`#wU_VFyb?&9EuW7`HHdGYGc>RrjC8I%D$1$kDOFYLq zD$m~R<7%%*+CCL-WzT@Ksq2qYCdlL!pj*Nc6M~^xgf%O%MoF){FxU}yH2(TzwAIiD zLmEW%6Qs^0dmF>!+ag-BhNQT*A2ns~5*v7*=s}xl#F8hoCk&36Eos_f+ zOv4jL=3l6^2iNewzvUr;9aCPMxTlw!iflQRsuNFCajVDX!Jl!8oE^J$ zB=mV1d5Pce}h7`E zJdx$Thx82BzYaBoPu#_$>Foa4FzeVs=kgZ;#yZ_%X8e5a(Z9(O<$t{%(LSRN_PEq| z4T_`oHrBBgZRxjK!}7>(Bw9>2Is4BpMa6SBO3Sj|^5CYA&5wNgq;N!I; zBjEwhPTA?88&h`h7Gfz0JG`d(UBm{K&Yshy$h%o#bG^voSz_sMexTA%QuG)t3$SD(9Gem~;%6;1rstFH6or zE>5Ie3u-_hU!LBH0)ciV7qfF$yam%VD}n*IJtW}CB2VmP*#*DKPsN=?NuDZ9dg7}* z-PBc1{0>SLYK=I81B!CT!9e90G=IADUT`prcvLZ$>uD1 zP!7$P%FuL@m&PB?gc)ExinkwGdIvYjq@M7~ON1&7;}`6d9v*JKJE*E)n~qC8sTokPD!hw?Tf+XMeE zSDK4dz} zu;Q)=cQX*Wf%<&xhbu<-aYLglZunWslR@06e+2WmUq6Z8aqPAm%UEb-JvbKsa}^2o zoHo($H9W5E7e9SxPI$vIgl15zgNAF^0`&g9eE|taqv73ghwdSry9Zg)TRD%iAijg> zd?#laEh8YF+{6Fnfv8SBd4{lccbG0h1nxq({P5E2FObM9B<8v+;nnaflVgV@?J0n- zCiYGB8j*P-O1llTl#{fIZl;PftXTk0XvX01f6Pp?>TXZyVvn=))4%*IRNZIcElU?v zrXxx>)vSD#h)Wrn;{S8tZb5nY!L8fT^82852Bq};^Fx`eGe2*8myYGq4Ja!{B=igE z2vXK&zVSZBG$R6GRW`vDkI0UM%|}KaAeh(GWeA5{MyCUjEC2gZr`u>;b9Ha}d+Y%L z)9~n|otkj=Ny?G@ctS|f$irXiqnUPk-pve${ERZ%;uLztNrE_( zKi_Ban58n;%ixHMMKTp9R?_fP)(!WPkCsoD(p&-^Z*w+EA{t{Jl)1=MQy}BagLqa; z@~>HTEM<4*npqd+YI(asZob_hS2Qa>h8am(HA_#|* zgLNIIk~#QkwWRlcvii+Vaur~ku&YX_EjC&V0%b??gtRB?(hX_&SnyAe!#bj(;PZVMWD z!oLcxPeQwSu~AhXbUUJrhBm#%v+265<|(9Xbbbl}T2X;qPe*&>5%NL>o<@m!27N2w za@IxS?|FL2hdlWtFa81Ymr-V14X^nRh=X4($@FE@qJ)P2DVOq`F-^e5mpt5sOJ&dcNvfzpyRRQPMR%U!{;77L$Be@rD?r5Fj1MfN031PruDW! zw4Bhg;i^C^Pod|z(x`M*z|Ob|*V(nR22Wwx$%tq8YmY&w(F@Tl{26aQWf8z$>3X_~ zB*%OY2t#<0H?DlC!(67imS-=Iiby44Cl>i0Bje{x7Jm1!JagTzA(wZ9Z$jIEcPR7Q zS)sTI8GnJY{EG?>Os=~hd3gePd3h+qh5pHU>w$9T2O{N9Tsv#!MbF5OfxTVa9um2E zY-Tsiw0j(!$G?Q)U|BUY^9WI+)ePIn^M5)hj=2}C7qOEB60;e!0?0_!#vrbLJQh?j z7=DYPiqlM^%)vt5nnT02Sf3%W#h4bd>%yAjvxu_jn(`p+4r9(v-407sHYgE@V?**} zLN=RmyVPVOu`zo*)Ng{=A6@tdxGk3}zya`YJVZRo^o5t`NKqggpl5DF;NWrLW|p&P z@bYP=P@|jJ%?L1(X?ZW)l*d7rMJYd% ztYqyB`)3R+|H9R+z4^=Yq2t38y@=(4I+T;AUc9KV$2VSv_ZW3gT2Bk_H2U~;&BpR| zM%tI1SHGWSKu~4*$|J_!8u((`GH_{1c7@(_u;9TDc}&_chc3%gEL#W3EB^g#&Sk3W ze**>b%lKn|ukfuO&?Z=^sF~P%rT1Zt?`+Ne5N9KT{Zj_jIuwoq>}is%UFMx72Ofs| z$1~b>mR~aqP4kLSLII+K?Yn%){IR)P2evH4) zL9>|-aO9J8L?^JcbmPgNO1H}7yi0(j>$2Ur4?;Oy{vmF{a_WsZqdaL}@}zDI6w1VU z=I)4~fC=sJiH$9SV`P*(LqUmdwE7T!2Xo>5lb z=Id-ng|Zd!9h-gzV5ii#hrHX-600=l=o{vM!u-g4pz@#}`Pz9u^8AbNd2BJwhP^Gr zdcA`I&XMccCwPyuke_6bd9CKlX)0xWl(J!!^{OMuv+sjU&Wn~40_u3D*!sYi-9xqnN zU^ zCECp1ZkW(`nzO(06eHHV6EgoNy&k4+!{ir#r}pVI@d_I5beKA@=h49Kny_Bi&^Y#e z3Cn&ui6_wRUuUF;(Aen54u;?<+=0>&P9Z?&5vo!;2 z?|y;w8_(83gt78KgwzYnCy)N|h*R~gy=F0X@T1Z&vBK337~OL4=^;mW^%S9lN<**u z4*EGd>;Sk~YbT!Xl&EO@WUloh^l^K#29wS385|h~!Oy@}KJXcM0XcCk7rg9{eVbR) z!x_G;Dp-G2PJJG%)1*g7Rwwja*7P1P2T5scq+fLG98P~*f;7xiA-(dS%TImUMvUKt zLh|FEjCGK*&@TuC!fH9}G; z1!Q1gU050I8STYz7gkV6-n_ZsKThi$ot^?G;T-qcb!6Zd+6!#xePdqu|F~ej`ym z7Qu#}nMf0`h0smniPvX&jMqFACUmdTy3U8htxT z;})+jDFh}2B5NSqF=rhbq*5FzFv}$6B9Fv%1}a^hS<1xBG!k5C$a7{Pm9XK05mp38 ztmemejjjZZtqo|&S4&e?Mn#HW>Y6-TM!WCg`Du7(U@}zl22z`Ps1zQ6hVu5^r{+=5 z(RsejAmJ0o*Vev5XSFIw`$6IeXBn}3y~&u5!TZDaPhnsG8AklS%|62Kz#fI{DW+;$ zB?nfG@>c$%j8%?67{kiXIGuf&_2}o|;f`T2Glx@(;=x@=yw>Uf71hv4*7CW zm$aFA|hA-KW^rs!3PBIWzebP@@mqg(rVp4Opb8zCLg=$f~@ zVwu4E^-S%3sm^7rRp2zE0QX(a)A`Q9CHOf*hp_*j!Mlo}pyjWenyK5?Nt)@JeFeut zNCCt(lnrjnBk>l4M^vK;W9K?J$N!3}hcgeA@j=Q!|JND4_NUi;xics7XlQew963dI zCeU~6eVxgea_uRo19Z$@b7CiCdi8|)N&tVM=X3BN@39b{M&l`)C}`~RkaD5C<;iC! z>&(i5BTmy?1ymfyxt;;ms?gXS&~+4(9f5c?e~m0dAitS)e4I4t2(|+c9EVrR{>c}H z_dPbF@yHL>*1kYzwCXIxxMlMF)pR&(xLS{d^ z3%L)Frwq6VBP}Es=8C`Iw@CWMI$9cmiP6x<#0;(|(ORz%L?#tpzn`!GEwaYgiB;qt zaZF_Jv;pVXX^$g~iF-5WG?~QZ&kE@21dn10s62j!XO;bzA;#?g%P5VTP^^2QcPpL7 zDH`IH;Puz9gu$9So!7ZfGKzh4DDMc96;9d5-tv|U{O~uU$t!=>k$WV;>ylEat8OCT zsVopCbz&3+E#It|2`iEwGj-JJbKg+}n^CF?#51POLh@lP46n+0{b?*=5VL{&sW@_t zig~L5&7QXwU^abI+XnXfGvMPNMNdG`I|9{!O{2=eVC{QI(^E5ED(G9rS@vRfA@&7z$p0XGEDr$%jZ+uAiJFb*p2g|qqHf@o9@2zh& zYzjYh;$LTvyd_|r>gYG|U&mOt-FP2+Oq5&R;hK>f+r7(AFZ>xZ!I^=o1DEV^KysX^ zWB2-~L&uSO+Oyzb$o6^-ZD5TR6zLilUYUWwXr)~v@x(Ht1XNi3`oBJ`N9z1lAbwxL z??tEJNO%O}R6KdWp2AbGtMDqkMJlIj&SPA|8h*kHY290lS(r;EeicBh&bqet3wW@v zvlTduvU!aT#zHSRO9OoIMUK>=MBH${gO2pMXDjqQnB@K3M-U2V??4D-US%OzwkhAi ziByy&Xc?v0sf;*gyz69i21d(9=YBdSJHpN29cCXcZAixNnPg)hd-fg_$}Y0P?b-US zO2bo*A$GiVQ5LO6EP~+QaMuw0hVlrQ*HP|pm(nobDw%ww3e(FO9kjT#E%*M*G8v zy_5Xh@i!=^ze9ifXyY&ygp9CcSTk3Tc2^yhInB?0l)eWrvUJ^OxWD0h9DdU%gP}Cf9BtZVC{8t3pmbY%|=?aRHuSKzbyDEB&E{Q*kk1nJUVopHF2cMURM?a4Ig z--i|}Ukau$+Vv0#b76@qSWEuIH7I|W64OADj9^%MG*WQ32yi3#B369uK%AXlu0I}v zhW`rFY-t)$@j9;ofASw5DuT#9MXPB43Vw7XtAa~ZH=%6KGG)9>!Bbo?|NU#PmC`Y~O>8w$LE!DRqv95zIQoQ32)Ar%4qd0I~ej*iR{*Yrz%HH%j>9yfgM{0zK*0>n0=#I_}OOU1u$Bk}G3blHEhIJ2}X(I4Yl4 zsSjr@9u9GU zM_@A2>u8IACFmR52Hc*2bb;_NSeO4-yv9q`%Uj&+c^q9HbsADvlbG*UXOu_bdwJap zXm*eFUW>roKnFbgPDn+Vn0KIb-ln5+HdCVqQ7%E}?Juw&^8exJGvC`=*~DmhkAX)N zi~>goIgQ_<4gLfNnrAl98?6eOnqHlKkP*D#(OzGq3=nSz4doK$AxKgImksTbb(WHS z5BM7SXyLkRqg8vtix(VyhkW>MHRz{>001BWNklV*awAS}0!-bJIN^B?!sNZ3Z~ zreQw-vO)O>mic)awWBl@jUbQi-#B8_-_d5i-WY}koc@1q1etsje=6sd9m~XJDKpuV zt@bz0>W)xeKL@S@AM0|9@X33~7YfKUzViJcPg^80qJR73+SsS>^xEyXlCavC6$x z(z6pfg#z#*#UnHZPi8HBH)O)V>y(41vs@;dzR7+8fjb8;d!HI2Rh?Q8DFgnJKiu)q z)39>)rX+MXW30o$tBPxFk5lS~*Mb%d_do6;pEh{k4LEDZOQR^*L0-_QQ5sfV1{az< zVGnV&lMnyR&${-e*^*Vf2LiFQzYrVj@^_v_EKO$$*Wbk`j7F6P)$>jq_gTDhejIuA zG_lK{?X@%G)6Z-w{KH@#c$jNl{v(#N{`-NO3_2*&es*pBUw7MtTMNJH8M{lUH&AxU z&Ip7%8+Hlm%@=r{9YfYFMFSsKZhRAcx`N}a=lMX~daOko>C3lrt!xRp$-|Cec0eLy zr)z@k8PhgAvHV*E^QojcTJr_FaRj%BHn_mEVc1Z_kAzAfL?-U?#~iKA;+kA4paRU4 z_6Er)?$K+sbbcdpvyj1Fd1Qq5S;Fq+X@yo%mYFAxlQ+`x1-WOal)4^Ud^gLz_i7HT z3}+&qIJu3HtTT~S!1qC%f!x5TZXcc90>JaRPtZ|0T81Y_=VKj=1YQ7}4Yg)Dh73BR7iiNab;w4*5e1)W^XuuvGmo zHx8*VXCdi`tvo<`eSTo@nfa%^xJ()#o^8Rsyi<=*mS0;}9`>sqFd7dTm9P-e8L|Cu z*(f8&78jIJPfa$j(Dwjx8aC7XE^%qr$p?c$0ax;`PUe z>AI&7>Sd~d@DSIAuHrcS(P7l*w-W^Kz_P=igV4_(p$*3ooL8@#iC$3@Zux~Co+IrR zzx)?W3TA`ypz~dOh-WCMpfCG#$;xFY;pJBtEit<8;rQKj8dR!^sifac{n3* zxv3H^9>&>6)p6r{%%^VU6w^j?2pJp)I~4~M>3ZVC!HFGK$WZ?_O6@tm2u>PO7f<{e znMp<{oY0UKkFzId&b9*ynjagrcK1n4+jzMRnsl9=*iqOS5Pi^x;EH3}M7HHe61wH} zQ^fyC?C`u*xC0qJ!Q;CZU;Q3D$=g)~`F@V}VZE;k&OGjx4*-m6{bP`S|-j`T}Fyu3maVRpStxOBWKRu)+@bJf6m4?b(F8F5-zwm za{I#rEoDty=??;eNqIRNc3;kT?vuRyDE=)zwgGheD0CI32`%ZBtYZ$Rum~DX>wsi> z4R^s5$BtueLp{?OgifaY7KH0@xoOf!LL;hxr*YCC1g{iU8~eUUpJoE}Xi!Q(#&0-2 z;8xg}K|M^T85Ji$J&hB`p#!`` zrB$at_{{%rc3jtucK1qNMKF5s7GIan+!J~FY04DAEVy_Jf`lU6`^}-#(Lai$@~=lL zgOri(9tg930~M#t9uIpu#))6=yg+9tDdkdyFe+2&kxq{Bb`ivNP5AuT!P8@fJ&$3_ zcm|sXABgww!IZFz;z_4{cYxnF3QG13Ihfz2^G`hzIRN0Gzni7U}-e`XSOQ>QbbhfW~l)XCGx z`T}(2vEct9b11tv{T4FDtm*YX9OR^AS$Qak9CYsL-)t``gbS~+S}`4jQU)GVcX`Ue zho=K9@$dlW}xzLo%{u+lYPg1=rAJ! zIvv-2w|Z^Kvh+@$9va}>$EKd4!5)Wq723(C7Aai7e<$U;>(t<%vW2h8x4tzyu>;fJ z;z=r=U!FtxjHOorI^OhOS4=BZKCj2BNGjEXfhiPnljs$wZz>#B$uvh^}CR zY_Ms19DY-7Kg4svMEZgSQvL`!%xD8Nw{3Y^7 zJr6=Wgs=L4AMtJ?jjbG`eehm*XH;yzBMSwmP_R$X$-ia(t`c~1?@h|%7;WlVWOzGD z=qj=Dp2+ysO~0#t2^o6xtDBG-D;pduxq-9$+*eiM%|CL8eCH;F=I8Qn^}9U{gG+vc zDy<2<(La{%PdvbvciU`y{XLKp&X^!=a1%N43qc(0HV8K(ZQz<|q=eo05F?N$hlb#H zf~|Cwhc6RmDsQ7e`n3E0fOP7c30Xccu|7?3ZLHNnD7XuftGhuhM~(dAUy83rr-qpo zA+)qm32Q&aCU0eU47#6nagIT@iZOpopiu= z9Hld$oC`eK>kEcE82zO4C*$Vb5v`V#4OX4rkQ)V~!v{z?Sx8#M*RzFb6&ws~w*Tc` zjS=1Z@coa0$Y9(|Ct7zU`I4IoM0k_VA{Q%?mI^NX8W09XBXZch2G5Q+Z%Xzp+Km1? z|L{Wn_}zuq9+&6<2PjWxQkNP1Pr-7zmQnCKUD-}?rf%ilkz*bE9cLjZ20t3*5$-kG z&A5a`JMg%sOObn#LpvR>WVcO>(B)xpSrJ8(Doxsft@3_0~Hf(3pj{DHes zUdT?DTm{FhGQWW3EqH#JeD*XJkY^m9|2TQ;{5{Tlo_zn1dM|mX;6Hz2c$ehi``Jr* zw0wX3Oh24<>~FCg_dhY)`+fMQa6MsFGQCteR$*6`t(4|xKkR_R< zbsN7PtP7z36uR`r!Q?em-;Nu;9737a6RF~+6KO=sPiNUWdz6ahTR57yh0I150!R~H zZer#ZIs@9m|4U50ojKh|p1lX_MasuDc5iImPe=LO%MBg6m%fJ`=FXh%NZ@vKUY~m{ z-fQNOo~U{wXk@dRI*nZF-|?%mRUVyn_@Zlpow;kof^zFciPH^q^OrDqSq1Wb2)J3} zhH2BjjGX7>7JS)$@SKg)pSi5D2K(9yepW!=3@{brC*L^d&<@qF|s15A`o z>3Idb`(hr?bui<;UV-)F0Sx<=&E7}(_&vjEKlAlr1aE6N@CnN6amp5@?F=+~ zdoVl7^OSMw+W~fN@STR?_V7hyiSkpKc(Ur%lLS;l>EqZI`p2+pA7%FVWv{SClX~c8 zAb1*XSn#lvy-ewpJtlv4Sg!9G;N^ze-6+&w#o=b9=aMZn8)UR4YjdZ+i;z%=o>H+v zx?G_7I$>@mjtRj`@$FKC_P!xi7~bRTL_hhnzq0`d!NXJk4Itvr@-R|;FW_dmyuI)u zl}$e8z}bQCLRb!cKK!JuH=D}fl|E}*bYG!^b#uO7YxX#=3dtkE^3cy(F5ZT4(Rkfd zPe*2Cj^>KHT*5RE-^|a0=PD{qSJ- z-=n;O$!Dr;M-BZnEIg}$jXa7>hf*N_IXOic7{BMqxDHUnK6_BwtYPlR==;0(aE zeMiQE>3Gjob(Vwg`o9XsTWO8s*ZAJzapdP+P`*HT7@=~rT|rskah=41&2+ulb}9sK zL-PhY^!;?k+Q&`+{w`65JD(zsf=8M3P$OOaEUN_jhh4B!jAwJl(?8q?KSG-K4ffH$ zSm=BRr7J1LD$*$}xyBTmG6B%Vxp1Ss#0Uz}?ZgLlnW(g6p zR_%E-d%QV&$43P#i!->t~3A_NvOvQ%Yf2k!+cfqo;s{Ev{I6UPVFvy7siAs^zp(U@5RooU6h(=2<% zU)5AOxhG;-s)+oAt5>S@aGCl#{~3IiG_2HHi(oyazB_lU$^ji-FE}~AYx&MV|1F17 zW{2sNQ@;)07YqZGbzL#;DWr73C__)|In7tr)nzlr7~YFUqE}pG{E8R-PP; zh?D#pN1RXc{4(ft#^!MqaG&8O1`R(-xRn9J9q^#YeEqTY!Ng`f9YBEyB`<>u8r0{D z3`WfU$B&oqy6GOwx1L;E`?JRf-1U$Tr)@W7bJyRZj(&qY(VqzJnfd*Vh1VgFfi(sg zDMXP9kc%`3!+WrR>Jg`&^3&V|?(48xOI$tXq|O*7BFNI_BQ>5%YqKO{#c4Trs=VP|85)t%8?GoAhihj8r)YwNd}w9Z8+h&;e*8UcA9u_APY7v&o5Om_=_@lwL-hcP3T13Za8?7roNKK}*gpL!a`C zT|X>Q7$Dg}NXPdzvMEXUdDa~-+}$E$Ou^ZS?{Nq&C;4)o^o}y~a0cTIyVJX;2JFRu zH^ZNPiu78(7DMMz*# zh_hgq0$zKDQQWg2nLrQFaNlDq@HTYLu{7u&og3`4Yt0jaJ*%S~UUHn8vQaiIAKCM< z!$=!riEr1>Ah$n<`{0D=7M#x@4}Z+k-SpIwOIw!vNd`CXJ50-dg#;;v=a{)^s4;^|y_(uc(`uX>0C*)CO~qNi6C4 zr@cMB-D$V$zc!vUAceo-C$jb-dS1Hnd%$({%;}l4kSY*SYZ>Eh8hXzB<7Wru6yI5n z3Lwe=KTS_`X^xMQ*1NIm6(!gFagK2AVLF$O;@m_+9mV?+pc|S(lnDH}xtW&+PYwQ8 z`rpc4M(tI&dH7zzBpQ@#+2a zUj>NcOvJZ=&!1i;!jMeLi@1GR*1#sp!&!%e49dzATe}!l@BdBY?Gv!t%4D_Fu8if9 zkH>Vo{^`n*KBO3)785>l$6)?N_<#Ntmb?ECa$?(B2Gtgn;j*hlgpzOV%Vd0+zi}EU zpCeQnqX!oJXrlvG=oL}S(XFMqeY4T~tM=W(u9N#imCaF&kQhUC;qp51s%c?`^^Q*nb{r6f(4$VyR^Sp`@MCWPDH1r*1H zk4U)p-DvkDmEhGNRgms=xG}8~aijWbg3DumJH&mG7q6h4yp*wKM^}S~OQfBpJcwnc zpx{#HzGq%+(@RZY)z*)yfkRQPp2YoqjtKc$YulT3&AG(ia-mB0)tez$&(8|Gfnsp!q^ zg^Y+lCYB$3kA2I36K3h-MmcS~m*~xAWlokijWA1P(Q}Swj{$w!*Lv$pdX=bwBJ*bh z+>b!0Fr0nZQ7inl@tBIHrtQ>gO<2>-%Q{8iNh>>h8@x&8xTLg;A?-NM(&$wp7f?JG zpqFEk_?u>pNHtx`a(Tji7Vp4+i)nf(j8T!8wHD80&NG@j_Y+uVIy%F9aK!Asg*08Z zD)25V_dZo$r6GeV%-#G3y? zSVK`kEOgZ310Kzs&OY@2_DTOa`g`4A*1vBw--kkTJ=f2#!p^#kG$eT(q1j8342&WV z$b|~ccar?hxbhbM%t(t<@;lO6#nLl`-5Is%I9sk0G#kj6rqI&uGgV7~QNHlH_h%TK z{VH@BWNj5Z<)rM-f$vzTWEA}~4A8#vC<8m%*LJ|o>CZoa971yr_LGm>;N^pYZ~b6M z>7J$-Kd5xCb~=xK6J_|HG^!;tlSCr>RmWvcaN=ANe-3rQPnzwiLrr72{b_@=C+eA# zgS6DHQ58a&eqqkpMu>vv6(OO6!f;(Y9S*^coIJ+q#d6LNoH?YU0bhRX?9V(i%wF8< z@K|N`BMb!6X*E91Gy1<|2V$cif(I6*)jVSOryqu2gwwP^YWinm@!T||*50|BG!go# z^6+GpN^x$FLO-tvac1DDtGXJ*y$?6`{SL1o`}+;y~f?>`-|EN7P%rz1@}VXMi%R$W86FCp%7Uq;%K@OpX8lUInv z2w!Ie<_u5B+tn`)_D%m&;R8m!6R;1tRjFhn7M?w(>nSXG&Iu^eIDmqBFJKwv{Sas= z@6MdZ(}XFcf%>@A*C%Epl5fg5ijKB(9m-?Zar_M1BKWbVL&)QFrYD*Hqfp21p5g97FBQQFS~caWltb!GoS@$g>Kd5!vb{1N)bzdOiLXqgWm z1}JOv6WJuE-CsV7U8sC&3R}tZGTfpyP#pft&p1A~U1H4yg8mtqw|iZO;50-#R?prC znx8~QC9)oExX%Z-BeHA?(s+|e3=^}l`Jwi_3?m*-K{_RHOd>N415M|h!WiO9FZt=r z!tk2o9Di&c(h}F_>^-E-?8Dnir*I3S7Ee^!(LM9@G<4{!EeGG~cIn8@T5y@kWh|A8 zCyZ9<{D+w9|1OVZKjqnBnP)v@(U$j6$jHebk`8GJ-pZRROw8ztaN;=AWB9Mm+i0FB zQ;~bp>|JIz=RZw3eto?z#1TrtTUS+Ic7Ev`;Vq}@EbIx`p)EV+tccX9tBPi4aE?dt zU64zU4ZI9K{F}yRd2T#txCtN7L1OZqyV@{wtw;;rt`S)$jl6dP5oaMgk=gz<;UKV+ z6y&GnQFAAQ0B0UMk*8VwN%T3V%Xo8dW!GI(7MZh-+Hahru@%4XATJ+hrsxg6PhjuC zZ+&d#y7oTq)IK-(nBwSum4VeC^ZYo0gPmvTM_zoA0r204bNWudWwVAH`RVK%{u+aV zk8nVM*<1#6DCHOaA$&?sLjR^fSzaa>Ua}OTZWYgsBp7xyfU* zS(Y16w)Fpuio^2R1Wp_u0)5}a3aeR*zJ6QeO8X^4?BU{(vt|r5dZ)n07*naRCN|3U9W#XNqP6QUp&1Xit};$dYs2t^!1&V z=_QPd7#|LoD+Vvn4*i_L?teo6_j4$VpQ4XBLYtsWy@g;34p{E^t0)wfIA8qVI0gFu z(0|a82b47{q@b6*-oL`j?C?|`wc@a!L5-i|=$EnVV|^S@pM(Dl@GrBbbIrjo59B&x zUQd!^nfjG~XQpDSq2eDj{_I>_!t&bof)WDFvGHPeGyT9_bc&4bJw4+RfH;|jXcm20 zFs_e8JO42aEOnhq`KdhKdJvvwDr3Z<6LVSU4I0E|;H89qw8>Gw1z6v)(0^{(U^7}3 z);GHHE7O_5&5Xdk3jWz=h7RAi;_tYX{NVT8^H=7%Xq9P)Z64gX_7X=ow_TP~365ZA zz=&t()0DNnE>AkeR`!uaDrLEKIQK{&GGixgm#Io-O6d&(2|nSGDe5fBqxha7wPi2L#={^kUkR3zC$#!TH-s3- zW7GZBPl=67LJ`5$lUXFP?_2=gG`*CUEG5R2jYbqa`mDOkOV>ZH| zaPC7`e*V^doBq;28(-&1IE`{wfc( zX)R%eY|(9|aa2Gpy3W{jtGI-m?!x0d!gA(Q_-~>-h8U~=JF@WxU2l%vO$Xpbb5{cQ zPVA^JS{W;XSETHrGM!;O|14!g86IGSdMg6vru5VJWu(0#y+Tu16;73)@3E*nW|bdh zb{QqI<0K|=Qs(e51I2887zj7{R(Z@dXzT0@e8@`=DvtnZp8G~0veEAB zqK8s;D}`IofHG9?!lRIoXR$y}{sQZjj({VedKfD}J{62#P?S8cT{O;h zO(5&U<*!+G@v0-oulF`%ChF{^mamHJ0v-;Ru4L4AKXO_NzbG6d^vI1s-w7DJfI{X} zcsZR#g}jCGc=tUj4{t|3ahwXiX<)ztexBKY`xcHAt^{`a?yq=_$*SOSUav@TnW`OcfZp?>Lp>JmjJOdEfdedLdF@ncPMV4c~~ z_^H&7o!E#`7c6cJp?>Ledu8vv-UeG3mi;HfCY4{o{fa|C7w z=P9c&QaGTe(#ov~t$7m3KW84wni!XxJ3fYF>a#xKamc`fKeFoQxy>WL{P)Ybn+kT_lxTd+v=Wr_> zFK<*}YmY^@?^m3Dl_fi#D+1;DE^&5HH#?bWMX|TCjsk0SQRQ;`FGiR)koDt0zLe=w zhqJ0vr#GN1^?3NBl>N7;1InWZ*)Vx!Pocm59`g1P8YB5rk$8QHIR3S2(>2IyZ1aDK zGaqzC-;{}o^+YQ1=I5b+Yk!#z?so91{H{RR{h%+PJRDR!iIRF{N!{Ixyxz!&_B?IR zk1cKYRGufcZlZHLMH#L-Q1P1{w-CoAr)MTg%bRn(uHO;&R^jD0p^HL%m5%?jC|tiG zb3GlJ>D-Duy*R_8gB8P_g=qQ+-*^K2S11?khbbrD9dSwbgM{i=uX>uuh99YNS?dgS z?PqRX+6aq|bnWz=iO7fMR=`=0%1@{z1@q)A$Ro*{ zeQ$k;)&0{sUw8;XVYD#9WCv^E1jJ^SMV zyHTocva3uMz=|p8?d3N$oA75<2)l~HzFOts!76Xaw!e0Qz{Wl`(IB)d0ZmHZ_cyc# z3(KfHAY7fhjns89*MOZ#h+oj##Yrb3Q!=0%Ga%DGQ)qrYouEuSqC9>B5;UZ(K;GwI zv~t5CMlCdMPbtZxpN8$1khVheYT!Dxm5mCMe; zK0PoXy-^8R{??5Tc29^*L0o5(F8P@s>w6BwQNa}0nHBjj{!Q!=z6xD8b83Wiv&?1$ z9u=9hkOFxac`nZ-rdbhMmSUIewxIE2neF-rqvtQeC!^_A!Q;(tgv*QXcx=`Q+c|p6 zt#@8+2R!O~GwtSe229_5a%;+?(tGsez^h9CYF!=glH5HkH~E=ck05{JvEj{mFJ^S6 zWm)sW&uM)46NAao>VtlwZJwjgLWnOrh+4>*iS|YcF_hB-x{}ko_SB5rG z%g^C&D#!}f98CS293MDJdDBO_T$?Qi%2+^&PzyllS0b2N9o6}nL>r_Hb72W8u?9R} z9?Yj}N!;&G)aWoMMYG|nIP4JO4Sr6|$aIGnXZdyhjl>4yGMe|I$^%8vgGXL(K>&A| z-U@V#>!~LggIsw=|YPg-z2L z@e5(}=q!DhJdo+#AEV*@4C&TPzC&MTJxrPV#YT#6?JJh~3ed~m3g{zBoz`;0eY<-m zMNB331@i0F@!NgNy=ay4v<%$WSOCh|nU**orJUx<$m`yJun=k8@fb6dPcu_G!D#x? zlk5I-wj;lSufqFd1h@S2%n1K47^dHGPdI?!kFu|2bhL1dUVe3p)8MV=nAy`7orQR% zl}bdQ-R~Ok3K`SR)?0IZpToPZa(c=_Y+*%MJO$TF?A$zzatPT0x2zjX86|F@?3guL z%-unRS5U*8H5?&d{B>|A%0pzQUT-oI2~>K`DRI~5onp(kZu7a-7XtH+0iA`jFxRUc z*$Ct58ahW$S(rD=t471x9huL)ylDKsBiFqQyxPQTRXi%|(cV=Q&Xkt#!dQ=enssH0 zpUkxZUHmBg)2Z(~g&SOc3rgA9z!c1%gO2Ll=DrDHocbKEdo-RPvO1olL#rEBoxMn& zs*2cHmCA^-S8vAk)@IjdWy(`g_1zBfguLuHSi^U-ZZO0*Uqac7#^BopqyU<4A&*E{ zVAxYudp-*-d0P?OB)*-&fX8oZgL=iNTShD8@vW0r=TwsQtRiyO;H+k@V_%g?2XgNF zyj<;fCZaPFH^;}yn!%a#@?@Yg=83G$zz;qBID%JB-S}^zME)*)IDLaBYFC01_G$z~ za^m2LT3?ZHu;!~5_LG+>cTd|6Z=zSkmWtmnyOgk_YcDV}D-)1qEc+0-`;vLw|I zVvNWjR-?m=wT;rEIKYeIFu-u0bP~E7NNPOiuicr)Z(_F5cj1-k2zX0t{z}yr!O{M7 z#4icUOyy!>r@+hy?(vLwG9%`DgN(SLog=!CvXk8^s5E=U={qP+?;VlW2esA^n2Vnw zKfgydXn?jrJB-TTbS5AVhL>_SyQM&+t#VLF6j(eDpghF;>URg<+)9jxFEr_IU!lkd zx{dQT%Qni2`yawBpdR!uC>-MnWe%?HU&JYL5yIT_5YMMUA+M{# zgZGjT@Lyt-_xRJR#@agG4Riv&MQ+}{^~BZPOjc(6T(Nr;euZ$mvl{QW`ZVRSf0Oe2 z^CwYM_fyxDcMVcjEsbwJj-ordD)x^bo`*_KQ!Xk12hw?`gF5luuB9^F1-PPMo2~(= zr?I5t=DB^n3dMbHR-PE%6_B7x!Xug00B4nlogz?SyGYF0iXVj^A|@DwW;R3qq7+OA zdq(4U#?Oq&Fz#M?M5#>ZgdCdn;;(?aM0vC%ubSaL2Q3|K z?|-%J?rpe_<2OWZq2qs%4t2XHaO7=N9xu^x(-HUJ{?dg{k=CCKb!1rT3UgM0pk$(8 z8j-gUIN{^RkuiAg704?n;(Y)5)%DKc2tq12ZI0|vGb=kT18O8uYWvcFGW(yqs+qT!%f!Zstf-T=FO(Q4&E7+_b8fz zTMyZ2%W0)!8~vv~`%sM1_1w03_5~!Ds&2cL!doGoDZQ)hwqjqR({cI9W3uMoQ#soK z@A`6f@El5LsyvF`y9nmRhla8!rP0em;b~fL&OqvusnZt*d)z0U8|2|B(iWVd)M$Ly z9i%sS=U=(;5$vP=Vq)H$r3|!Z(1Cv^qNBa1V|=0fl8?b_-Lu@{^#r?kBMS1c_jA+( zGqrIEa|~Q=@dTR6^N}B}t~^}s^VF2fP(D}M5H@v}l~f+tl>Y8&?R7cVn}kpYe)nAX z95aON!gnYS!K1v(;DdT0u$EJo@$sSXFF}SGZ)Z6A?+=~)MGg%JeY+TZmjAn=;VCTJ zcpmx|XCa=Nty`>p$(+5Awg&<&r#s%LD^z2uMiburqmhjEU=Dv5WYSjMGEwn6lm)Au zi>O8^MG+H^QXr)`g2!J>!ZY(=mNbPo&TuM&hGi$}@!QQt;x0S+0Vhu``PIO=O>^ng zi$1TuzW)A%io>vj2=?ihr(A5$?aPW@k1{S9ZGnvW^pZzUk+~s#EuF+>v!glE#@$E# zyN^=KS#Hj2Ur;7g!ljSUQ8Po?Nt)JQ>e9-YK$f`hbA}|;NbybbIsFo#gAb2i4g!JT zlP6EhxRi5^BPkV3gax}M=^@(z$%hZj$Oz`Rq=85IiLAZcnu2n_kJ+2En0%6ev|CaG z0{<0f^uV%!gG}uGEbZqf2x$53ahKVBLC{b8e)EaVmy&!T)wiihW&uQF zgU5$xewX|y>iGQz_Zgm|ZFocQcERJpma*5gU(Nfqw#ttRT0Z73tK2HB_YJ>dyIj@{j_Cg06&TjT;(A+ zxUs(6-?7f@7d*|SqWrLeeBSrpz~{dQhX{b86tTtPAgt_zWic1mvHa-iT4@;W{zu)+ z?oGU2X<~c992AJ1{YfU~oXa4C^R(0j}Tj%?PDhT3g> zX!$n&C=VKDUJ^u@HUlp=R2ld_N6kc*;hW~kr-oUG_@~jRUbf~p&o?{HYlmxIuf}&3 ziZ|cga7J_+%F)@Apxf)>=akrh!3d98kR84J&K=<`ywC&Bjp^z8EqhQ1-aqBn5PR?h z*0T2x@_xwAqD%gO7?i~vWTZkFAD~R9u-O$RQ(R{t%7FVF&MZuBPS*6VeT&$|<58TI zBccYh>o4r1-c=yw;r`z~mM7n$bC`pQm%|(qr0n*5f#+k`kv&+`lX!{t!eDaMx6$2DfBTe6SV}C9S4Qlj@n|o<2y-b9TVgyqlhSi$;J(1zG7y-7k>6&K zjMkV~;!OrMeJZbZ9A0gF@t5(V5v~F*-`JV@Qr(H;yx+hmrXN{PX*g4HDa(%7lS0d0 zy0b%9dH9z4Ym`-g>~%_WJ8nDnqcjwc&}z>{B871QfVXapz#!i-#`Z-NcON1tMLdYsr{eYyu4_=!1FTjWx#$p zX&K&T{`piaowY-~CMF}gZe_+aN~HADt|^qMy~ok*Ezrtvy~pBIefl1Wc*00i3j?Nc z*{U>Jur~g^K*RIh4lnat2I;7zTMRBk+=BmW$lLd~(W&_+xi{##^k~^pJZtV-Igoij zj~6e?n#*7+kj=h;xGe5={2x3%RD&~*xn)BA`f^aQec}Y2EakPzL89&Ow52%6&;|Oa zm;P4wA z(LvKFJw<37_6YNy5hLndMzD=;-V6M-k-D6ZHy> zbe;IR&GYWA!@D_b$G6qJg>_1U&38&Rd#}W++nqVg&BRAE$BRLCw*LNLV&4KA8p338MJfFm) z5}%9E{7y0hK1sQc!ajpL*HO)&ZOQA=lgrVMF|gW48#~NE#Vqt?Q?bme%Hu7{!?v?* zCS3UMr|H!sF7JI1;Ecyv#;SF42W{z*CnziW!XGu*;h%Yge&`<}&nMxDfqkwtp&bq# zET)wTSm%*v9a#E7eP-eGnVFFrX1~lJVpnU+zTuuP!0v1_kfJ6*H^eVOJr^mO%2c{= zJ8N)ylTRBOX^Ml_0*E8XOlPljlM@*B8{>w%sd()PnEXxRAn03#THbLPz>)lWRUXUI z_n2>vyur5{_y-wjzQKrmnw}lEC!L%gzfOKO>$p7(;69AAr~XvbG9I?#uV8q1;ONm| zsce;*m-IbJwLy8bgy(Jn7aVv@ruN`>e$JlHoE#d*JFNRwCoshu>5-Sb=kZC1I4fEedL~wlGlSi3%g%dZMq} zdqc>taYUG&ffUkUT1sw|c!kM$6EC=VQ41;aPI$k9CA^CQv2l;BGQOMtjm&Fl4h=h~ z3oa)#ziVLj+J6nw2R5fS4ed`*&Fy8F&fE-PN@rEKU-t9#ld}P54=0WfGoEMZjHcks zWAB|q$Nm3v_a?x09qD1-#Y!wB00JO30^q|!0^q(6XGjib(MZ-VWn^hIk|jGX+mU0- zu8J#3r7D#;Nx4$4RJMv!iOY!`R~AQ!q{x!BFEi4}GsD@q3`vkf0uTE_ECc}%Al7_e zpYz|>_q=n?J@>u`5;K3j`_4Iiy8HC<_y705ba#{MaHR3Dr;Qt7BJ0VU``IjWVj?iK zjW7`puR226s|+v7;ng;kndOp)Dz=44B*Wa8b;lJ4FP9v|a~h<(N@Q-K(gk-U7}sDR z*I(sI5>doF6O{Pkr9|H%0uSY@flov{;|e~zhUwhoR8iuc?<3EY7av{tFuzB6QNuhm zS~ocznAc1}MiAhBVRyiY17rYAOvQzLA+06m8x0eQze}!8M3ylFzR?V1l;*gL@#$*$ zgx()gyDD|Ox4TeTUEr#;(1$=^0#bNG8D$uW_VV7V$&_5YU$z-__et)lq>FlGB<1&qBHID~VRhKS|?7Lz1;lZW>cirkjMRWP-$64If&e0#OG9MAAzL5?Pn?2E)#YKnS;#38ShbN>=`qP zTomVm$V8dq-MCkolzA>O;qv@>koigPf&#MqgXJNZ@(*PG};y!>+k3#@2qd_8T5?HzY)yirO83nQd+E6PC|46{$2zRxNp(4CMq{_`~p2@pSWz&?tEnL-1FasAJy8Vfg#@@;4sU*hE z9yMeirA*;c8|yw26FfXs#wrtTQH6?P*>ZKRLa*W&wgA2%_4t} zcrE$x^Z)=L07*naRQ)S2JelZ}(V2_gR)b*qel|09vML)U|(?c7sBbBaXVrbqt;WbYyrEzd$Q)`_giR$5kffPcTd{%g8B_9?(h>u=cb@0IUqC9SMGA@By4%1sr*)^iOCg(f^=OlzPY*KaK9XCvZFD{Iu z#;bla@^XRfOK%p$s~Tt6bK2^iNN&`bgKMD#H32gL)mP$=$M)WE;6qpV&O3insH`-Y zw}BI_gu{WzM3!j;Q;}9CCSnBunMf^|o}Y1LAgZuD4@4E0c_4+%Pnkw$=4YA&hre$UGh;%u(F|oZ%~$h8>{`^JvRfHPLzo{xS42)3)wtOUOIb zG48>Y8|Wpv>a`7bw(m;wDrgV!z$NU`_3EjeaU-$y4i%quCLOC|(>6GW^g_bp;&xzdNQr8J zaz$MJM|dCS%d}p!!7Y56JYkw$z?I6PZ(4b8hLL$q;@Bdi?aYtGw6hy5j=TaL9pCNr z)ji9Rau?IzJYNLCZX>^=blhJs**X*IjheEJ6QpMypGh#&v1lfqcdj>BuIemu@BUwR zTvfFDn5^Y+2Lwem=|d-)QCyA7r>gF56UthJxY zGz+0$G7A?Cs=Ix?a3K*;)p{tpO&;XKu;t^W!)G14P6Y z;|dWT1rB1=)R?Vt+jg#lU>-@rB7!sGq)v%Km5J)qE_L}unB|^eU~lKQfp)o-!ETo4 zAONSqHQVBS7)jJQ(#^*8A`EE}ee#VrXzw8euFLnTM88X#YMdr_+|^~DUYH>Ru^lha zw$**is^u8_na+FvAdKVJQCEGHcBK!80%=0Z7>H|OMFxL@&p9H*`#j7jvIqLswSMk} zeiSmotJf^uEsrsPet@h%_O77X zWti%vOJ1SMF>am9Z z4CMJJrMPdG46DuFk*68uKDKwROQY0MHDK1oYYTg5J8FzQ)Dr|wI0t^oJZ`<4N2wy< zmL%_f3no$yvOXU3PIOCSr^HL&1sIf}V+vN{SojPC7e+8D96VYukWDa<N{2Q4s{_-UL$93feqZEBfqDbL|ZQ0<#h z%CG%HxKZjWotHe8_T+ETUrbQDKw=!jn0E{YGt9<8YLNW7e6IwO&f{U?kii_1N(WFmFzLxKTS)7Cw^C5lE-vhAHj!WqUqly2-xXNWS8 zuAo}YnZ_~NrYbpA^GK%-Rs(sqoF#p)dD}fGY$S6Kq36OVu0aHEfhh*_FeeS{;#QKJ zxpf@zn4m<#;vElBrU>^MaoyK#!N(xLC4nfj80q5Xhpw95Il(TjFunjC1B90*rS}L)Q$ZgDADLXAFjEZ;3{07C*b$N$4M*bhf@x6I9{H9)A zGlBJtL*Z>C&RGTe=E56HKK^f{>X*p5V_zla(H1vfvX z-<39$gJwzsF;DYOne&jI<6|u!Ow7h~Kx4F&G5Hfgf-{d9+O0puU`D+&6VMe_53B^{ z%`fd)WkI6szU1Dm#nUbKHuxy}NEIoY|DR-*unwYD-KfwM65!a}G4{A>&Iv|?gyE|8 zx@}X=p?}nntsP@2*Sa`)-WOpS@AErLx;EG{L0)I4B)d2V#g+EM7)ak;F#CY*t5ZM~ zROx9e8b&B3zTY_rql7UF9``Dv{W|IAfYc@Org#3k1cC=6i>~j#BtWUdG6hO_&A~Ks zmIaSfz6tKD5qw{Q`u=yBA?}`xkin~~rd{Oc3guWi9j>^lt*Z7QpPdlgyQ$t=XfXG| zr)5a)PcWA5;_8?l1~QQu(#~O@==46Ahwc9A-cCtoHPT6#{7gXfknzn#im85IN&U62 z(vQE&k4fjOK|<~*iaInZbp3}QL zSMMVdw>k50(Dk3o0hpf4d*3VmB#*1lQUEwx+d%bG!{8znbl2F_k>u~Gd@>59jJQe+ zgL#;ruB&e2KFW-ISUJLep&F|WRBfpfA4ZH#tG&bx6=g^Ly)<+&sRk_>PA;H8IZJ`-?cC8mZ=8_pIdc(KSdqv}vxgs*4+8 zv89Qsw22K7`r%wPa%<8!7_vm3iJle|GS*}yx(kQr)e`8orxWVZ3qUc-Oud+&gWs$F z`u9FppwBF7!cA9XR=zYZ8c8+8(jSA+-&4M?q#gB90wR$cm(Y#+y|(yzC@rcXERiOd zOguMTCHT(#UBst-q)Ej!o3o#AJ5J}3FiRdL+2mz!GNS9ko38~iO==@hP9mVapblIc zkyH%ekOXx($Qs0V9`7!HhkTDyM)8!%LfUrP8D&D+g8qws0p9!bbr~hSGHJw{x4Do$ z91g?4J*dty>(9YOtXnDTTQV}>^~qulhud8EO&3JA8HU{n0QBjp8aZ)hx|G7J0nnpL z=CKW?A7d@A+d$;rn3xqY+yA@Z_+9XKCHQk{BlVf2kM4p-l58HdtrnuQ zt$bI=<3{>O>vO#4{x-BAY5Nkw(tdG_)mxcxD1CU8tx$Sm%`MWIm|sH1GNW{#q89Js zcG}gC$FF>uGncqmjj-f1eE1O}IeKq0@K{-O|EiGOY|#67mY@#<4b`d$y2KrpmmW_N z6bX70q%E48UXB9sH{mKWm>@*aZ#D8;^Zun3Jqks{6qbsd#??3^f=h2!g0%KqA9ueXQ3cZ^tf*VM>N#F;j5 z_hDgFsi#N<{Q^fABI&z*M2eRqUL6~!VGvG!y;tL~QrbuzuERZKB3G*#4J#YJVc*LU zAnx1JX7AJ#DS5~+0yLtlu9mSRUO|~Di=#3974ggj=ra#LTz)*tkRrstGJZVfl}oS6 zLMZ|*ev(FdhHo+eZZ?o<=!&bl%T?k@?FFW&3R5k13zE|?2s^`y<-=ljdw&8V<@Y7t zb&ymtbuY#Yi|tD8fRXy$92EVX2xxQa3Qgs6VV7u8RiQY5{Okc3g3^^U%9kejy;*!w zm4&)kb+6{_S`g{1zl57L2pT~V&+i64r(3=`|D)sq6R86wpe6~+aBUlw`Gq}$hH>-q z@Tiw3@yx5S+4#N++CtQ;o8OMRs&9+uRp8+#nF(%@c~Cj))6~w@99%qj(y{{;AVj8>{U>>{@QhAyRVuZTFL>Sjw9-v`U$@PpEi>CIb+k-(gie@yKC*Z;D(T4`w+R_FUl!Q5pl5Q>k zYkRqkk5?m9o?m>kh-zJ{_7K-~d~7Y!G2eEKTE`~aho6gj`w5>VNUlN;&`CkKe{*rY z8UA~+Uk-PclP4z?N~O~XKNYj>U2CLj(Ort$q&M@nEyjglP#!TnE@<0pJJECnG_VI= zChGzW@e*xvJ?JL1Xk?IU=E%??1Kr_W_pyNXbl)pBO-!~&C6MGa6Zu_F^S4Tl3EQT^ z5<|&bJ-;^^ne_*4WL#cVH@F?d;vXRn1AiDeeN?zM3+qsHI`Rr6%h$?Rl7KT=DYx#LHf>Sn^&ObFWt4fvWa1W>@yFIM zHfRT#hHb9&&=t@=^iK2B1`^<|zM%s0@U;&c+#7CHg+@5pu#IC<(N@NAU})+O>u8fH zxy}Sk9uulj^O1RI?`Ylaf zlj24^t{TWMQO@ML%b0h9?P5Y#p?iv_OhltP=@>mx7&FN4eXKkir87`qx8Yv=6I{zd z-;{PCvm?QCGKAP7y?AQ=ue2iJbv1bxkSN~CPZf>ZmguF_WTcM#jO#$tK5(NzrlzEG z5aLlqE>Hi{#db9_f}~0tvrkmhsh(0YXoGYfJIJA{u;;S}BoDB7$gV-ev!HZ{R9$$) zd2JE|{+D??BX9d(e(@8p*}_?Alx~iycfLw0Q*c$m>4r!`4>;iEO8h z?^wLJW`!?5T-XS1&V;zT^}ls(f;-7y7}x$GGk300bqq-4GV#mbOy|J!{i_qD{Okh+Y zdnS~O#Wf;;O;SR%zSsE0ySPT2cy77Qh2SmuDL&@xvZYco0Te;(3Y@e0;3siBq;s3t%>e@b>PZ-%e@o{ z&9>B=sf$andAS-~CaW#y=y3=!vxs4!#Njvmp67wILWV+lynOQE=6H|Xlf4CxUYRVO zUH>2iF)N;$|IY=HMMHo7i~ICkCZma_L4>JBUGOx`Sefmrma1C}8X2jJcNOzD-z=F~ zyy$q9QJRO>VX%8&F=^2e!A<*Q9(4{3b@|v1QCHt<#Fu&OKJ3#VNKEz0s?PieV|_4B zw(UFM__$!5+laeI_zL6h!mFyxZyfGGYto0Ze~xR%aMv+wQt9D}N4b$k@L_jixSUPs zj58LHR~jq%fH5O0CvbH^>JldZ-fK{I+Y%XzKf{zr+>MuvN-r$#tB@0bfp>n$UjPM( zxN%kTSn_$82aI7LZluYsa^}nYT&XSCQO>wEX6qSM2gy^aj4#7+Eyys?D187TJg;WjmN*fwLMJ1zkof*zyHa3qkB^2bJIBf>zVOR<`tOl&Z{KrY-Y_0+iOrTQR zUJ2wejOD(0emCW$?Z<)pV3d|EX2Pv`P#O1?GQQiQj3jZ`5E-0da`L6Oa1Tx*NcN(< zec?^;ivAuIWQ2M?Rc$qG`M4m|G&?7z$Fi<7J(#I&YY|U06wZRv2aC=%p-R_XIH#^5E7!@bgl2xhwvfbj@)jDGB<3MgNeSoX639R7meu7Y-eikI73}6+n$ebg8DC_d9#><}%94u5)+9_0_$W)y9s<)TWETbW1D1z#oaU_W%b+`XAGwmJ{Kes9w z7c{tvai6@D;vu`n znh?66584Kf)1H^Xg==S~P%NP#|CDr^$}tBfG~d}=)PuNN*G<_tTqXVrzbbs|&GDs< zJgtmjGPU~)UuSe{DU z?cZ`IIv<6Qe}%rJ4KHs57xvKC)M+RLzH{}~CLY-G-Eaa2n%)6Lhq#eql2m-pPuoY4 z0cncN<`xKNY6IfOZSlgJAz<40l~J#s8@$$DWu=5P z8{qy{AEo{e+(G>zL~l$&j38ca#Xb!3IvZCBH!+ZggqzkvbQ9%nh|m!1x{K%E7>#)} zWR-$fLg2fqFzfPhi?xfCJ(PXqDMk_)=yV;ah|sAemOMpwr7X| z^VX<-CFn{d%4xS@K6|m!)pvxYF;m9zegD=;GxS?etnjuHuVf}Rp!ceRdLM(>hQoYi{h-W ziX#$jXaA~&s-Q7@8TB}df{r?=1T}V@x{p{M!!RlJM8<&6cO1>Al(k&lu5b@Mq_%WxOs+AU3-Y0B*~4oT88YK zGrd(^7G7G(J~09zZu+(=q;aJskx?(GVQLG%ZP^p^prb8&S8zeoO!fup@*Q>TRVk&- zZS;YOBG;UG7;>V-rP~=qY2|n+O$4Jbj)XMfF!&-4X)l@o{akPL#dHXQAF7;)q1Twk z-ZUm6u)|f`z_{Saflnc6ujDG4J2KZp;GacGcmRgGxEQbl*;B>Dq=R|nZDB+ihzCm5 zE$EDlv`gF!FcS|f%ip#-T;^gMjpHoPrESvUK#2K`WFAot4eKjE!qXP&vl%=uCq@H( zF9PvPVJ%nlj5yvW#Dj*o+k^LRU*b5@CXzN(geEF|xX3WAL{AF|GaeFocukpkDGSqQ zF6m|VkN1g*h|T;wPvkPQF}eQvSBgSpu{+(WHuAd~frTK7sRjtif&Yl>Tjr6k@1 zG6>HE@v8A$l~yvO+fSx1zEyrPGKj=6dg3`{+5S)Q$b!l|E-x?R9)Lhe)FQw3Ec$OH zNT-<{d!~e5Sc*)#>$>_jm`XqLEZn#+jUG zE;O}u@%G05cZ+|a$pBuwZT=t9>_yal!{BrU=Z3`}_TFzEXVTeZ9~_o`Chrpyc?|8$ zqqLny_7c)2t1%GDYoBR27zyh?M?8bGd!>vy&|EiEyZ~*{=$_Vs5XY_D0|+O_I_!&& z7}JdFAi|AHHWondn8ZBdof!Tyv!F4!v*Mth6M8VI#?gDi4wI=gox4$2%skAE36}?R z%U-ySWRyidS<-at4!o{S(dBYn(Eg$%lrIQ-m$QdAA*b2ruHGCfQJ>MZ{LZPVY4 z5~3%Q<=IlxPfhu__tV1@IE@ft5o0BWO;dcsjbnM82!a;r*|2I_`{WXNHmR=`!>}yx zhYhM;1;_e05dA;Qz^%LZDJG?}0ZwRL-{GWfz@uq4G9Mw2#6(bMUHUlX$OwC41|>}n z1PKO_B!}!>g!|e2UaitCOx``E(_g|PkSyPx2&Ob??<4;Hshf=<2Ke#ceFAYeRG_khq%vjgY>o<(|s-}0IMxOJ=0c$FLPjE zx6nS?K)Qg#k0b-OkGgc{A;|C9U=84KZd9m1d z12?_b8Ai{me5{dY@ug|5US($e9LtRJ=ajTa-n#}8Tv|s*HqF4_#I|rWr5^d8Zo3wG z&6*BNpp21a5DGk!+OX4E{cpT;j8J* zUnZjT)zwY6YrN{WY@58zs_(1M(!Dwxi1A#@AiSN;{M_@XI^dHYJIA>qS^pc$%Mt(p zAOJ~3K~%r$E#Z~PbV>i_I;kih`&XFC+$}|*6OSD-nGT@(#EHqU^CX64<>r5uC75JW zd=2!vo*t%O7t^n9(;jtbN@KWjWFGz;YHevWo}X1rse#nqgnNGb_X5a(J_t}FkoL2J zj@(Qj6It;bc<~ISDv`oT%rpkUyMZv{@H0(>d%p-RjXUvb_mJscX8h{XtNKa_9HgGoYPOiDMa_CTzVi3hF3 zu-PL0ubQev)7~5yigu3(*h_mgNfmYbQN8>os?oB%ZDkqu&K2iP2WIK*CG&8oz4R7? zo|}!}XQ*M?^0uDPubxfmn5X*F7%@Q!%wP3Y69aKwgz$DnjaYT#;$q8o$pB-2I zHOeQ)+0SZ}{AU{1(@>ZF5V<_YuRkctTb`xs!6c?#MX2n({b9c(8qfU&Y{W_;;+0a# zMJ66H5SULzWFV1{K45G!7RvCr59ZEOq&^W*PuifAR4bzxi1{YbBAjcw4-Q4S+kDWUdcGDxE@QfO^Pa_I#6U2G0&Z? zdwb)<+zD5k%5hXX!I)IxX~(&h`fr3eGhWElO9=D@!%jFoqWS^b^ua`7+qcHv-hfC-gF64cxx02+XAqL+qdH4^hqoq(?fv{s{tMt^umL%vaAY z(O8>+Wy(?d2yL{Cfu{jn=A;DC1Tq~reoR}QwBUp*&SerxA>k%$o=P`c_|Y}Juf0~B z>#?1>)p=Jnm4PZHb&r}->(fsUxi6Gy>ugg5cLMv?+3NsP@04;dl6`Vf zk!l7o?*3L?KY1P+(Pb0TuKC@lc#9afb3e=E0b+mU+XcSM3~b}TmB5>6S8>9)&_}mz z*OfP^t#~%EfG=3?WXiHHl zsw0-hso_bH^$opRR@Z=}nHhCYRHOW&ZpN;vbrGOaluV@#)Y0mA;EZ8Z7{wb+BVuk? z%fDsORSgArW`mDz8zN{#wmb7U=|%SMZWyJj(W`{YJ*p1UfBRl%&^!sTBqL|#IRt|+ zEEbYE9wb;xQM+nasmnXhBkp7GCpSZk^2fXCRfBE5u+XzEWFGI)7p`bt%CK{X-8;Z( z!8WO&bqbGvwj-#Vwq=)}PL0}#F?f|(>cZP(S1`Ys*gy0fdtjm{v+d_$Pve4RxkMf_ zfpK@(9rjHpn@Z13s^wwnKaBSaWgvr|fYhZFR51ESLw#hmM;{@Z!iIL@K1LHd`In3dm`Fe{1D^wj`d4levjKOUc%*RfQv?llR?duEk$&-H2=pd~F(_T+#K24j zpky8z&0X)&Xf%&RP6>BH>?VrB8JxBv7kP(`93um&t3Ee@)M90ddfh=W?jh@^7)%o} z8?%z1-PG&-gIx?zX74$8c)j&nDZ?wla=1;3=bz^XC&l{@`>F)g#274_YCQ?7jIqmV z_1UP8HYk5NsB3Qm*B~61^3{M_s1#k=KBLz?HlInm2=NJUO6H+~@6I*MX+Q{%s2%1~ z={G%!))~6%JklD7j(DhQs-LE&KGh(1Zq*Y^=HYqWG7nv}?*yNBF!+`+h61LIvv|SP zA;)|n**{1+RQj+w8qi&Z-Ug@Chm8T@*{0;-ndEJrb6v8x?$zCSyQGUaet$N+t0F(I zPDD|LlD3Wgx#c!t{t`Sdmz$n6y6F0Sh>dcY?r+keRH@6L>gsK4|;DAhvw4Aq&udSJt6 z(|t9{Qg>CQ=DLyD0M%KRziw^IY~-KkA>;5g$MA-Wcj;_^c&J>{HsK;t2{9}8(Je_r zb)|}@D=0O%pmgU%k-~{XVlp6i3olDH3HQ=ct)&g33d207s_}i3egP?xT6BPv~ zL(hPpTc~>siMSRq2LC%bg7@eN-xFm5rL!g_bUK`ddB{YXz%$0*W%4l&$aKH@sWR`P5jVJ?_ESB5}}%gm^T8qLLYnMZ?t#C%m{wGkf)!+nTi z&oSV*-OOP6C`IskI}F3&p*dtRzt1xsS7bHmJqt{~m4LaCoSs>#qb83ICx))M&?eylR&{DEzvKJa1o83g zMZR~W$aOJD>t>0oDYv-Y1*m2ZK~((ji7rl*3~K}9zU%lZ$8KHRgS6SujOr4WVdJhE zuglW<=%RizfW~qq|2nnt%}~B^%HWBxi~lWf2fCA>#Jyk`3AqddVG~{9KD{F-;>6Xs z$%U6rDKM)2BUe); zDv{mR`tuW<3%$Izv1A@zoqS%P{NIL-{Lm7349Qn8u%70#e}Z(C#+Mad$3WE+*lyR@FU=67!{=Ix18_sZSSdLBs1w z>s`)#O?UVt>FAH!_^G$QgT6Z0ff*iU1})REzYfBP1RVyf+W=z(50V!a*RQ_TP8c>) z2h}odySf%%YX0x~3Jvt)f;f?@@7xS=f;L}6UAq9$(^0fEQIBN3hPl|ZtVF|a(uQr@ zxKB&;AqLprF;Q(RhU3$|t>Rx>ny&A3N;wa1dWOgM9Dw_7J~{_NdF2giCxQ?r^ch9* zScH}LWt51T%o~o`1YEsG5-B-B86Xo$41wADCyna2Yzw83u3%k66Pl$*wnO`h zC<)#M*N5%E8*w{l+E4J|+$f#u1sD5f&1NZ*vHZ;7ByTqJzbWzpi55J@kMYnK5X!+B z(nVawiMVgNMjXbz=$Sz_$RcriOQx4(9t_Gx@ErqunB z^LyXN#C0{}PF0mEtK$%k=b?cYNNZRQ+bDtzr4Jin9*ba7F2V~q#*D|hRn<#JAY#HO z+l8pk(Gc${^g57P2s2&bT;x*xKT2KP_%U3P^LJhEb@8>nZ4!)j71dU*+_xU#>Resj z-}cQeTY8v246!E~+A+T2nvq5P1lMlZ*XcOa3iFU@>uL24(xh&)U0^1gA-e8E$yRsP zDlW&j#ktt7BpYV&df+Obp^K93gQ1Y@AH&i_2FG9^xhs2w*IhTRtqZ+*!j$N2Tl?Ai z_h-PfR74jCx*6hkv$4EuQ_KNBZ}~J6l2ua-A~h@-*uMVj(|qq?4W33ATf3*(Sv5{< zWfFz3lTs!TP+nc@;a*pb5X=L$!l}`K`b?-R_&w8?k4J7sNDVWAz zlo}D$SU%_Ag5J*|t@J@|vV{O=w*exHL{X2NeB(mjJ2O|JsCpVj+UixwMT1-0EZnVF zgr?Qwo;)Z~_Sa>7j1oi};V-^6v;Qtubk8u`=_rgQm`CK=b)|Zm?L?xMYuKNTo@j|w zzKZiJ!X0=!Qf4ydio76%3`Kj32U6{x9G+jq7ev7dx^~9X51kD7JX@17 z$B`$FhU&ih{qM!+`OugJ_fsa~dM9Z#ph_1EAv zZ~IWfe+P|_Yy?=6Ct$QBn*#Dn{`ONL1yQsCZns_;#0F{FE@lf{i=leV9d#wlRZwka zS^SN&=&zdJOrN#uSf)PnKn<6J5|Hn5Xd;LS$?}K|_gmH!ot&?XUXFUo*=MXo4krD`}VW+S6f-~#D|%EuZ2VH*u-oz6*7N2vwIKa(mi)nn}rO*eivSvEF?&! zy50MV!LD1h>dA3I965V#_{4AA{BP=Xko#Mnp@cF7`rBcnBU73H%L)jSsibl1eOVdf zrF+BtMck?clHwb?gzL=xuWaT6)A>w9!7503h%-|J)E=_%T5rw|Zs(<@`byP(~ zclX|>NQbEBm%+yzPBC68q%6I@Uy&tXE3+#N@;Ru>51U7I4aM8cf|WwL&Ytspo9AZ%^qcY<7On@FDk#--{%+&GOMO(|sfy9~osJKtovPr>%`N0} zsU$<0f#`KOv2&vExQd9{k3`Po@*9C%W7plC8;e<|>puj)AK)o;rga^Np#9;cH>Xr$ zMQHc`qi%-iS?#Xx=mHXTB?H^4u3aJz-^)Olb0phG+t7NYp>RviH;vt?fMttypTENNKrGP@J!3bR#m9xg4pC7c2Dh%-Z@D za{=Pc+}K*CmZ%HWbq(4UoMFd;sUp_Q|HrxGGLcmbk^t+iTCJ_qBW~MO@2)Kq#U5F@ z39EwA+sdDVdIe0R4OHj3vR%gND*c>6w54l%CxWU{l4%6oUV~4rOQ<^s}^X&fkL|-YZS$u+uhKe2+=bb^6DtxilwsVo&47#`P!ViKDbptxi)HJ0y21liv( zF8*64I@K{|S`F_B)H^@uNUQ-*JyhDLf-~%VrdxeK?(>0zMM^!Xsz&^A^E91mCpV2$ z1*CyJer^%(Z|`I=J8wIP%h|g+VO3PY%#>udOu%G^s3${LN>K*Dws%)w&&beANqFlh z#%73bfV0fBE};xieIYSXP2rwX&P45CvYMvK@w-Y(#!K$VM2xa*hmbv7elxz6Uu7_L zMt)bE`>pE2LRBjdZ7Is~mDh^4&hu-!*B-M1CMqM<%WN0}Vg8cr9}YeE;xwk&^d0kd z3!e)O1EndQ;qH#?PQ-QIgl*~acebZC3Z;kLllhx&_j`}yehgk5fq}Gvn_241?*U_7 zL1XzzGz+=we%G`&dpyUg#9zYhk+X^D*A<#LXPBs+eV+ItxFEgfK0W%c46ibd^qet| zGMS8u&>FZ7GF@52i~844UEbY;%87Wh0So8#7XFp{dXFI~tb^W&AA)pa@5O7qKe|u` z80Z42Si#KWB`On>PG3he{LK(Lbm!f?gc%(fSHazS^L>`8?`Qj2X(O0Ok`87;ZQ!Cn z)lND9xTsKs(#Y;lDIz2Z2ly~>eM&G7<0i?71~&iP6}g&^>uQ?7_SH?-wH^{>&!^69 z9o2OE80dDQUQ|KQk{d2zb?B&9Rxl0y`GY_o{dL=6W(SJ3{UgwvFNTRtzpRkZEqArpnB zJnSdi)A}_@4^3$!{22Y-h8Gdf$$}DVZVQWdbywGQy$w@x?0qjmNDN9FjZCAgur{Q_ z^zr#WVSIomS3-gdWQl>|wY)daU>t^}d*7AcE5BPaB#Cr&6Nt!wuLU#N2J@H&;urZp zy`lHqkKfgM0E@ZOgJAodpx$4!Ea6%GLyV>t}HS>2%XQ zK^}L3xNCGPY5`R$hly_|J}^QRtH;XVmdjf*N`0QjxHAO&3HM;Z$IBR`$JA;S- zXWf3I&LA6h4J8yMkF791nMxOzVDog+;+hX7Fw;1*esyo58jZ5#SJT*p@Y>|MtMma) zo+fb-)CitH=r3S9W7u^w1A`}CR<1H&Cjm!`2TWxi-4Nfwij(vq#U*qQ(2HCDKQP94fAkWVLkbqeZl#PCRbY7c_VVxLt5F#O zPBE*NdHm)<^qJh3@QsUuV=YqjZIvr&tX0fBZx*m)RVxXqp2mgKsGL+$4cm1$YynM+ z+}gfx-nuG}lh$)50yL;<;N1%D^gAYAR<7#Lk7Mk#BOlyS5P26q?uFTdFTHIWiv)TQ z(UeI|b|1u2La4eT7fH84NCl-1w{JhsdnK9|AnL;E23)V(46#Vj{@*RypP)~lg6Zsl z6Wk8osb&-086hO3B4p}+Fc70IrxDhcuE-}NphVD{E5}sM654TXa z{*Fb9MGmOdU_z=-s^Dgb_wrpgL+t7j>_p|GFpkZoRJn_G-vhpW2V!=VvT5LUm3W;x z)yW~z(uRo?c_dJMb({>&my9abJ?SOZ6;vO|h-CUZ?kY}9Y-2tTZimq^u4KqEpEgi! z_`tR)-L&ZNB59ly%mg&rYj<&CB5ny`EdO4#cN8^j{x9P=35~e&9pZ4!nMO60YOML- z{anRfJ0z$t)KkNHvXgM_Q`5oQu%kq(;_dYb5;7=jfx$6nC%-I7ZM+cz*&pcRfA68* zF7_k|qHmF1B=|D8b(nF{2VE4u$e>nCmuUR4u2`;@sUZw2!StDnS+Id&g=HL`ldGpGhh#lS6O&1A^OWV4L_0(DrbW@eyGz zy!$Hc9E&X@-mt5xwp(Zq4``a8j!mF6C-bmf+n9&yLF1}6w4S=*Y74S$A0aFxq&nS)C5?kGFO|u%tDbtdHMOs&l+km?J z-l(H4V-rKmrFT@mA){ekA?l=iu88(QgYA@q(t-AeI`6kUUfh3sKeN}(5Nsp`>yR@6 z``10JG@f68S;#z+k&u3o2us}betOU8eGN!>om?aaRB0RCitAj9&E_KIck$!lV^cVx zR3Y;SwVj9@RrkO%e|jj@&2;2*d@cvm*(=uh+iwl#V|#1MdSok-!=CXcMtbylLS#CU7=m%5?0~5; zZpMG~{YC11ipfF`Tu+Ms5z6Tj4OLkSkjxY1%@NCdc#fa}yp6y<-G+l-pCCcW$xS-| z+Zd1~w;u?f!Nc-fdLQ}x-My`hE9rpXm^lZ&y$qdz1Wdt!bG_alf-E9qfNqOlJK0;q zxV>enKJhkP2Ts3rciw?U7>HUtyo2bzhN_TeFM;s=UOx4Qr=Ttz$5* zfq{ez;nbU{J5@`!P}Uqoe&#~y$Xab5{>-}y4vsp|?(qVWKyE;qTeK+LyVE{R^}m18fRjsI$F=FQ-4D1 zy~dB{ap1CaMuf97>JYCCDc~>Ga5}?W(;(?<^5(AEM~Ed-b@-mWvkOWrlK+ zat{NUhw909&kT#%{e9|`=-o1zY7N7y>bQITK5^U*y$azKm4~~Blkv5OcsP~PfNka8 zY7Q>dSYZdr)8+TE(z$Lc`aE9Uy||?PB)q+xpxl~Gz$(@5XJNYhok(hvd!-tU>MQX9 zm-e*ILwt5s`ze^EHkKo_!K?v!dyMclXo4z2`%B40+m+>3JvL0j(UVJCm6B!~crevW zz&>^h_V2pQ5NYFR!~SN4T^oY5XPD@ohbH!*RfALQu9;-<81ol*p-z0Y46~E@#sE~p zGGa?=W=@HLj6s+1_vO zp}}ah`~WHwFrIFwXtkvy(D9Z)CR7`#e4k%r3=a}{J9W>&741I`(Yl=(@uago2;7ZrXYN6-%~;}ermI<@2hFdt4n^>bUs_Qw6aHjsg(c#AOJ~3K~$Wwez$<* z;XN3>UU@Q(#5_hQylrLr_v!Q0z#`BrfcqWl+S{LU+h^5&t3DUso!h&97k3q6ncj&3 zI~kl1zgdQl{oMz9_p&ZSY2RXr{~j{;B9q5A@=1$cCI94GG#Xb4TRMcv*d^e7vY0cu zvyga`uKnG59eiCye2>xn2s6t%qr3KyfB0ap_cykqlZSA0f%WSPbyV9b@I0Rr3_c|x z)n)EsH4Z3!sM>L#tu~02=EgY!LCSae_24QQi|VFv!FJbe_mR7&a?qA>vPR0;Jvq37 z*_m(K;>X4Gg`he_yN8=`%GfoeCOZiD(gid$HxV)2VVy~PjBZs8<3@zSJ@nHi2B7Y{ zBJ(iF<2e3L^P~7_-G@Uhf6rqd4A;)GlJ9Kfd#Z4gO{E`Wc5n88JNErn@K;9zJ=m&J zW7`+CFNr$tx-i@D-DWIL(j$z{NzD=%a&`Yb+eh3rULE-EB9pGO(1!P%Fo6sUz&qFD zC9$A_q+N+KAF%k z`Xz|kmqFYBckQ(yOIXcJb1?&{PQWm4ckfLgLDmR94D6UsY+=FMt<5n#QSPr0=ih-S zRyS#kR5Fc_I9v&2M-nuI^xUh zlpK@>nmnu`uGerb$iw3PrM*R6?%j%thdk|=GgEyS(WYHxI&McYfF)Thw+9JufT?FDv!^hfWroC0@yAHIa~ZlkndLah-tCkLo6FJBaU2CcSsAuz=q% zP)&9pefJEE*|XK_COX6N=w^-l5@)I@xtv--sS_tVCMvcgBkLG^}QhxrzQ68b<}4NGkSIE zu1yg1(oz!0JHL3-{9l6ThK7QKyt;#L@n-!0?ro)t%Ndc506CM8@vUZ3;T9w=AnXFF zJoJL9162(!+EZ-5e{&H-LO%@LlEB4$P4cCktQyHR1~Ra;Ql6{dlX*C3#{s1d-9wKu zU|o082CqyOMsK~ZrjM<*lxgJkumLBnfs%*(Q2JuMhJnWT9T4Vc=|>kWdR*?P;5rW1 z$Jl;#p!b?}Iz``39sgXHO8By#3O3|5IpUJ3xodbASw+TpIc5=eNCADfCh&YkKcy{CkH%Z?&s z{QnxumqHxOTggLa6`%)}27D!iu3NmQX1icsFv&WIbwlo?YR5#M)WwaksILUN3EX7S zZBMkRL>0{YI*cl*uo#G=fct$Zbx53D@!o}KIy~sSc=cQ5^DR%V>up8_6sYHTcNO`UN;=t3wwGD^uY9}zIPC`Fx?5z>9ICiv;n>dN>k z+=|F>nf97PJB$Jrm1I39ma2$?f%FlUu&&@L^fnb@H6Pui{if~Pw*80_gpzv>;l}Iw zi!M^6?P#Cx+K9pbHEw(u5o8|X>bS1#wzbUGHqv|ThJ)WIDO{SIQ2?cjp+LGzG7iT3 z6y+M4svjX#T9^IyK7K9Zte>dn<_h>RA6%bXZL6rmAWl>m2n6v4sje2HBmV3E=*aCxMIbDvm=pfsoV7{$)PeE%;8Xu!Vn5H9kq182MH zd*{=6E_{l1s*9V4=|=n&B&2z(3&gB$Gm^(0tPOu7TuAf?XJh{r})Z@lD-IbEYNp5FeU!*G?X)d#qV@p$(55gQ7Pm zlqQT4^fvWXEO;c^07w+w1FP#1wkGzh4mY-RMSoY&3ypD>n%GS(o1~Vy{9c|c+IJPW zGV02B`)?FCT^(Rt?Z1nO$lc(TuKU_QkAQREVl2JRI6u=s2kOc`R#?{Y;-HP@rERU0 zICq}%GggCByE8?53lL1{M!%p-e>WayrWWy-g$6lE7g!WC2-%Y z_ndOoKoHqSAc!Jf27^tNy>LK(gAV^+Cy`npG7hLwJXEr*25#Ll-C3_I+>b+;N8Qgy zb&?W+HW;OhD%6!x)tm8U9#v+cL^7Y&Jwl)4U^!(TdM4?E9}L6+(>B`*7hSiocwkFG zl+0Irbo0c$hr7*e^Rjq9;6_YlGDv60UZEk4plZeauI$gcon&Qru9&YQe13B&NVcrz z10qfn_)fg^XT4<}{usAOD&R5=l7vx{spWQGI6bnuf;cb=^H5zSblLN&h&lLQ`vN+MH40DwE=CwAI`kuk6I>kkMWUm)z?H z!S)}#3$^Rio>vxaFO2s)`GnvEBJc0)g^)FL@Dc{>Pv6tK=WjjGTcjH>d38SiXv6|uUgN%Hhf_Zl>Hzjf_KRZ3_| z6XAMmY4~*0MLlMMF~xMg-0nh~F8(-W4W{9GtvZmQ{4n^gz39JxoiWBYZZtTVavWc^9^m>dPVV>#N*(8{ zV*{-#VvYBI9!%sq-?_eq^tK1%coet}QeI|^-m;HWRm2>87IgtG3w9K@H{kyg7Flh$ ze`RO}(--u-`eW$U0Q~Dcz22Yf9|%ehZvXH!o&SsX_2xgernheC+}<+U<+(w6-%lr> z*D#+zN#Wp-P7=8uz<8VuRGZyj?a+J`uKslhSb#)-HelSd3p~qwJ_AGMp#fi4;4ZL` zdcRBDe6gX7NSlj@f0lY`V^9)t=BhePBfOBGT$n`lB6#3`Q+StiH3l-u9@axJBy9fn z94~j$WuV$w2}E$pF7s$&Aa1jv8?fh&jC%BH`IWRLLlsFKSOkhR4Gi<0xarS(M<87{ zZJZL+hXDzzA6hUERlc*W+Yeg@&Di_K8wIh;KHI-F-Z}8%+l<>bP*Qa*mkj#=#H~&e zj`SMK#k*l(+yCT7CX{y-(#Ej(zE=(RQSkdLW%*}s73#k(>1Gl~)s^k&ghu1I4j%UB ztV$h~0&3Ttk5rZzF!fDTtV5gT*<6JlUOP-#X{&^sBI|SzeSrxOUM#*bu;KeR_m&{; zTLj0DMEMW{XwtF;e2p3X|HI56j^vb>t0MS55aiSRp1qSsncKS$ZHxO~$vn)f3V!1} z|J+Y2>4tynP%+S|5%Xuo-h0Z~RvGRVD~|DL1KTaR*+Qkal#X%nm}-R6FsZKKBBIq0 zK~+Dlq@4+J5$UCrXt_TI@)NrEgOP%i*pCx&0-+s++FTLq4n4v&i!^JPlFL zu3;bnaNS281L4!Ph-sd_6RG@p??9kwhcXbN)PlNhZ6M|~8{qaZs+xp0JBd=M=YR5nepq(OC<#|-O1R|j30hn|nWu%*}g5om%ctQyd<#%4|@mgetWjQN+S<5}LS&dSae z%A?K7y@XtKt-C~PdsI5Upt{PAzrmmv?Oea@EPV|>zsa{d17*K7LHXY#MIiNbMB^)T z#)1+V^31JdxM1et{mcden;#(hOP^xDD!9KBCAXPBMLYhBye?6$9|E~_;q`d~vy~s1 zC|niG9ZpwLr`7y6Q);rQg^Q&9PoQttBx)}}pp`&|!DFcITxDJY*(YH{-Y^Zm4beI# zkp&@?JhWAGMTqcp(#D~fK2r$hL3WAY4-@&T->WhY-|K#SCj)F9zoX1RWFlTSZ7LXx z>aHfkz8+9j_fBz0Klt1@T`foTS;KnUW_@m=7hAfUwyHu*(g)?PN+7zgQk>q4dy2k` z@2=*1f`=(}VIU%(st_gDDu{QPB-?*&8pp6y&HnP)AE=bBb-2c>1jeg^@tthRKxP9x z9LfW?1h;pov-|k&@m4ir_e3@aYs{EwwE;xbs++D>4^Isjju}nk>M4O@Ns* zJLZ2HW!@5Sj>;!JDHF|vd@_`d;BLKFm|V|~iEh!}1%WQ|psAS+SJ!+<5U-=!m{Sg{ z6qkyJN@8G^XvQ_M)?H47I>Dy_84@2 z6@5|%N*@0alSs#C?<523SN9K>KAgeaPa`=qDZ!HwEmHNMs`UCzK5~S-T^v|PfFqOY zRn?EPce&Cri1et$zM5ayFI)^5(n2-PIL~^5xP815#~sXEv~wgT!c0@!hxgNfjuiqw ziYFS8R+RZad=IX+2iloJr15$mZPjJF@JQnz^;t??)5QZog>Sq9FV4UKM}v~s?=&5B#AML(3N@E<`VwzgHDvpV}h!G20FKm zwlv5|sthIWZR($9E^2fCCfc$7My)dWpWe(^gcyC{c)?7vBF);ZwA9t*tw%!7+Se)> z(KvI!>+4Qdxlb$B4{}WuvJ$uM(eWgsb`oyK`?CYR3fIk5EUtiY=F;i`*ZH6-fw{(w z#N1x7V1`r3I%&lLwrgeY(AryjZ!xerH>&5BCDS~w{7#mwj{&!nW;>t#EX4`J9`Ew& zaq|7osiz2&R99aDDZXjNhrol(y0%Q!Rn^sEe$pYEVF1qZk=K|>?B6#KJoF*fU(|Uz zwI$Xrqy6V)W&pWQzIFV{A0BB9ud9^1Om}(mS+K(NX%6ss5a5q>=xp6;CU4b zY){JC1qk;5$Kq1zOxBVreqxFW;x$c%9v;}b?ix}1;#>;@!YfhZJ`cu zo%Ax11qX->&L?Ck({drizzXDQh^x#R)Ztl}>-=JK#VZgL#Up2a*Z3voQpv|n*q+_k zdyiS@Z_{b3NPY-pui`tYQ+1p()%{o-DQl-?|1wq^*a|UR~g($IdxAwF_vI@E4Nt9FeRnlM+=f{V0ie2vr<` zYX0I$SLPArS;4?s#y80-A#@;169e%*!zjg($3DTM92T{fN5%hFg?(M9At9Q6pzKk=E;7^zhRg()YAYq)y{{4`Xiv1aSKjzx*&_{GNX_V{11A-(#|80yok%cieI*Sv#@o3kp(P#$ZCA zK*%APyV2t14NMOA(tx)56teS1Mj&#K@f9OYa8K}6uw2Q*-jIyzTO4Ytt70!<35e^v zI(TGF!9;kcR>8B&?aT+DVZss0@4kf}Be^F>!ZE#FVz z|MVhL3`ezz$TU`E7a>#sow}$ZVm(QK#<$xD_SM;_Uc6M_{1!9u)E*Hy!c{$eSJ1=f z36NSM72y3(ZD!#Mm42Rb{4p=SwvWc?P$2cNr*Y$x(T{orul5xsjt%PzhT*Ky^V!`q z%QNB4FPsSKHZWA`aq2B0S5L15u!Y$qZQRqNYBs=nX{hf5-%1O!YT8CaZk?3WPut3D?mBw<*>Rwf` zZA+ey3oPA!#5%QkWA)RJne81D%m~+;@1d>5lkG0<2zt?-W{d{j6ruJ1b#8H;hm$FY zgX-+R&8qLJzL$2^X#Q0`_a0640z>z|MA)Lol91{+UkO_3%#*+!wm(7yy(``J zXjD+Wf1WYvlTRFZrtu z!h|UNbHhXp?_Z&Rr>!3`-9a+?A75a#={}zda3{+-Ack(JRgg$O3MbACq3bD!%tPb3 z-y49xps{t~4Um~yx7-#G@2Xc3H65-~ebMl|jVaO=B*Fm8VuLA-tfUkF5}p4nqv+po z{a2IlfBGc1kwm)u+C^26$B%pK=K(<)(B1On&>@({J1{r!L6&kC2Q=Aesl zJ|^80>7%=PX^$!EHB1u8^J=`OU80YZL`=pqGxM*4L@Wqd^gA%k1VnLsu|N;{+z{!gprKq$b@~!-u1)EoBQeX`&JEv zx@G$g7>FHdPx=K3wFY*Hx6+92cdC#ak9!E$YhpiFXADX#&M>CI8(@xGzyJQ^v{$`z zyqizG24<*4Q+?(3B_(J)*Y+Z^Dd7x&dkyKSko(M9XyaW=dcA-6ae@iImW_`*n%YgrgaH??uU1{sZ2Ig ziloMpf#mh_4gHi3r4eyEz%|;&wIOqvFekVkbX=_7$S+3*Dv%bTm^t@)UFpu78q-dq zK%v$mbO1Q>Jgw=-i69XaEtNvD?&vx5w~Hpp`X%0J*YGQ?U?Y9w7@X%XdcFVRE6vO! zGI0UVS!WC7XjO;36O430Q37`YWp5n24%rJzz$ zDO<<7Z;Q}|JAS>|y$&_wj|wLt!V);`AfrOgJRAdeGfqDa?)=;i?n~yOYAaXq#b$_) z+*5vy3S5Gj+_I7K=ky{gj7|$xuP#-g9tPJ1MDl0B2_+C{h-<$dkp5Lb=Hamo+Bgz8 zernoO8gmDIMUDGE9d-u5Z>l=h=3+hp5^{~>w#nJkh%(Tf8_GP&4?FHhm2Q&cB7)Vx z0_rsl0(qysXb7NP-0oelF=-nvBBB_62fr#%n9FqfC74HICQ&#(Jl|55G>G+>+c? z>9YmqwdpR1Vu>t~uS7uARUM~a~1!^dE%I{*|T z?Yv9#B)41N(_Ja9=|_dP!Q;Bg%qaPIqT7?;|Ig9Sf8$Q<4B*|fWbg#I^pmT4y$Sjv z2RB1>vZYb{5(IPsaguXH9;xMC)uyVeF7`qIYCx60vw4WI^c)O?tzsOPpPL%0{g0^1 zJ}3$V^RQiIs@jJt%=I>kZa3v{EAh)-oCmDYZA3b%nKBSp4++Id4Pxdjadb9dpG`Ad=XoEeBfoeMd6k)` zURGU?Ons$S#(IAIB}vF~^z(EmSNpAm9r^<@5E@kSe zDyR-LkUIm?`zi+-C|2HEuE;7$Cckr-wm1awf_iz%U@ZE})7Ra{7Vhr0TV2E@<4B$a z5Gq%scLj|{5()>Mof=@FmC&kNgm@xeaxEr;I{94_5De;|B=Xumi0y^Q0rZ4$E4@|o zn2G^f^34ULzod9gIV8@PvOMy*quhHIhJEAlxu^Nv4{_6x!75re!J)&alVlOnz2Sm! z=9Fd}2IBVZeIy{CQDG^C{XrP=_fd}(VmzQAAyeB3F*#5EPe8H14xaw* zsp46cBf-4~Cg>~1VcXaz+5kA&@Jx@cyEZt9dYH1gJ2v3D4ZSyWu-W!eq}OOq=}7|Z zl>gtsLORp!{r;(0skYVVsxo$>H*Ux}pl$FwY9_u$Kc5BvUCZIb^8*J8l5oRPLtpfI z8l}xgDz6CXgrVzL0a;XK%_TnL91OCM6{1yJ0Bc0W)TcFhUYSnD;g%%17+A^gcVXmz zO~wbmnU%*i1l=iLGE|W~9E4B0Edb<*$#BenX=8 zZQ>8x`dP0ew|Y>*kT@SXQeVOWLvJODd;I($3`k-Xz^$uobv%%{s^aU{-W`U2_b>yK zQFM&&c`k{I{?yM78?36EWTYDZbBGo5?@;HiKKhYfaXX3KlrR{GSBafcMRlQ`JK??) zGdj||wwIiUudzMOlaIV@l6M%)tw1Ct5WTR{;PWcg8xz*922a)$i9LbOy|*N|tNDgR zSg>3<(Def*P&;170S`rU@2j?z|HJbAF~<52z(5v(@O5C_{H>y%w^QH$ z{TO&c1^)aCz1}B2K^s7rJ%Ft%xERz~d{_7g<@^A zkc)iG$v(CC{+^VnaqWXA68>jj?)Co8ALC;2byk4C&3Ee>pr4}q&0UP((mvzt-pv{L zd{SQxxB$LQqrVCTie72pvjg9}fr2=nS@dR0QC zibO_}FZ|Q3)NUWPWxmWxRhc-L7#M9bF1o0$l6lx?+G%3rMpZv+Aglw3npKJ}Ol!1! zAK#`JNdj@a+5OO`v89hw^tU#UamRu7j;HxGF%OE?hubLZGsJy>Ny!}gWFZXI_Hcbj zS2)iEp(^3FrCm$^yB(5Y-I&SH?1*LBC6O=c{3p>*>ua18JUO54w8DX|FkhtN& zU4FMsiMP+tUK-HV+PKC10It0Tq21He@HP3nMnWR)`57yjN#zi_Ot*8df_wXDG|aYC zv7eNTESqgLu=%8nxK*r&$EqR>SV*Gq|%a^XOYfG`^xP)Gtji(ewzma{KnXA4M z>WXAKCeQs9=Ac3{FFO7i!vhS2$C2S28J#hsF~IUa1nw(Al|bwCo`7Du6T}vRjWPfl z+J6*0);^^Q#r80g9$Uk}c2_bV1@47mx#pt;*Njy`NnDrQBz=4x=JC(>U`L~`@?(9K z&OLq5qpShDs!lyVjouh}F|8tv$Tb0mf6$=n@4Ax(`r8Ak>g zdONW7NEwHM^!^t3(+7?4pP8U|zL`aM2X%LC@Cxl-w_;X_LeH>aDy-}~ zy)6^v6L~%jv37B#>a=k{Vw+1KmS-`e#(>XR<4ZPcjdSAU;8t(%AHVRB-a8 z@w}W>kD9#qIQY2DndTJyebCdLA^tku{_k=BQWCE|$btI20T1u%y`kW+>9N`p&?VFSQWUwNri0XIzS#J@zu5kz! zuF+Se2vF&w^m>GU40valE+(2!raK`%n?bfJICJu}!LJ_a^**(^_dCm0rK4!`F(`UY zP#UjRBf%#(^?JYc7Ap;Dh}i%Mi`%O#EE?x=7-{&1yY@o~qz^I<-FLgpe*1~Ik%_1t za<3@2`_TPQ-}hi38q)KbnQnust|~-Z)zu1$tLjRpgFfA`TrO&y4cIbKAr-ZK3BnU>iCnkp5;f=4XCdimmC2zr4@q#f@z+obKDx2p$79cI9c1J1lm+RR%IO55tj>I!p%`+Z*K5Wt;jeziGE_`>|!BD9@3jGy>(_iIm{LbKvL& z^UFKfl=3l7=X#*ngG&#wVS`GySqY2v43HYUeTInzlAjVmfE(;Rbay<}UpJKM3}>`W zpuIwax0E^AK=_`9^fX8)M=lZNc_?+Pp`O-B$wyb!Cg$PJz)$Xi$&*2H56d=vc#(#fQHQ@8m2$@I@w%XqT4RWTE z-s`&j7!?SwE$vkKqQb}|F%O7(brKQpo33||zdPbCU)Xz^qIzcZDrCA8Hcm{J~#{iDzozU^1%MvZZ|TK0|$z@8mKiU%RsGUEGX0y>=_7aRr-Ld zx$4%hAEnRxtMF~hgZ$2m2xEe3HJO@3{>ZUHLK06xMUiJ~`P@cZX7W!zQZSQEjP53| z&JvHDfw++H6in|leeP;>iM(LtR1>)4YZD}9#7h~CjKcl6s=!!J2Jbsy!s%cs1E`Q~ zCDiGT?_#2}3JU7V>pd_~B_CZ?t8hCUL!#_i-Wq5xzz7BF7x@<h9BqEWCO85yJOaUNvh_I;+Dx6Z%}A4gTFI~G z6Ggu|{+lKql{{|fqq~5l^)}Q;JRb0*qKrB-xi{hE6a1L)rh}t$#I&(|_GfLSqcR4V zb@KKoafYYqAijvi4RDq5!{&+uc+wEHTkwuG4CERH@*0Hrg}0~jz?gphH{R?Wg@EK$ zHG+kCvRWr?AwRlxD*a6E*3c*`7bUxbyZ<^-0auewb$?EiPcaCze>5Rz*D^>@-3DEz zv2ha!P<~`_$q+RddLDZQcC%-ocomQJHtEB0nDBnew&Bix&`3AhUsS7U==VJI*jB>9 zRvyyRn4g>$9d*z1Q$i9kzuYN6J*~6TmDKlB5QU$kGk+1Bc!GOZ@18l2jRj`pX!gtx z?G1;)k0#hp8IPkf5iwMSO~61r$0CO>laGibvoT+pNMce1+JF9XhGzOTw1J*sN*&>0 zmFMZbjBV$}B5$`L_e^g+lPrthX#>YCRZiZK(10HND&1SoaX=OD5$fLrs;th_?k`QU z4J~EO!9@^vQkcwm?rSF|O`rtg`ilY3rFX5BssV|cYdr#=YN9j-rKaQ`woY;0E#6e! zR<|v&>2$~a1~jwx784Rxt4*LvEZ>Zjc+;dR!pLqqSe{F~X=2vXQ{1?axgw7gs)Xy{ zfs49B+EDY;-`*f1tUSK0{PAw1MyprFxZ^Ythha(pTLimPOHB)q;abW1*_GK6o5TT&e$+>(Jeoi?i6;`eH`5B@pM+2@A-^iPO}txfh%2sd>5Knm z;br8462(Rag`Q%bPf{m!7*B(`E3Z$Jr+G`DorU{zGBALkCa8d)b==uSoB286BiUFW zKDzcp&!Q%0~0MO90n2Ucp2aA7xn4i?YD*xaJMoH$qyH)yRwU$W0%81EeI z?Ii1F0N30lDMX~QOtiJTgG`e)nhI-$Y=N2vXiCx#XZ$uTT2f7nH`V}-^wW)cBjeb$ zW_qf(;g)~O%x!=I@yM$3mtQ$OWh}3xl&1ATqM+ODFW%P=8vCZ)-0^M(w?x{{{Qu0o z3A|p{RoHv3WZAJT$(F6jl59URjSnY~h z&6nzZcfs7;`R*=mnaF6Y)HKm`zepsgrm0)|B`}br9KJ5$Rmv_Ai(oh%Q)*>)i1J80 zQgHER9>YJyEUCf*8vVm_vh3SQ>jOOhv-w%}&#y=6J~!VLt$IW?T4fQeNLWLJS9Ty> zph}vqB-I2KjLXfM!ABeU1efmKAwRAQ+(dh+PIETVq{BDac=*v8aA4iAZ*q`u$~;0g z{_6u2_7?ULu3HdSj`u-e2l2k!EnU7nNwboABlx~D4z2%H;7UD$8wJN=`fYm7_?cCl zp{}-Ulu^=xc@%aykj`njvx7Fn4%3?t_tRR=K?I0;{8hkUjk7Rkuls3lIoAIPAoB?4 zZ&+d(h4S|vf!HK?-gS_mhf5>z zOrLvV;fvr@3F3kKOYT5oU%kJ4J*o%QE{m@UmM41R7D>fLCPE`>BKu`81LA3jl>=ik zgfjKuJE{yD0&8L$;mz|Qh$GUpRlJ*@3n|+P#|LGpES_6f%@QT%T5&09OT=}bqMEEp z*B|rhcAr9q3z!i#0a<0L&6McO&)=FsKgq)$m|)W;F?eE!?};Mq$%vMhT|OxgiPK0h zC(hH+?s&cf#;}Wgc5vwqz_q9SF!Et2+%_)X9k%Wy)TWzuvEGzrAXlL_JB{!ng!Kv= zl(biD%vEgpm+Jq!mm+M@7D^P)udRObmr}f)=QMIr}d9e14pMAj*+XY-4 z6oQ0ATe_RvjgSer4)V>=+9r_pz8kdo%P1fCLXILsix3S1Q=VGPrwNDNHq10Sb&wa>2zV4Sfo)(ve@;T)d$XbhH>JT*O6Kr>&`y5P@DiF&npndEf6aS zm1l`eh8T?}6EP!^Ur(cnh<79HAfjs-qDy<#YL%IhM8t)|2%cH4ix79dds^VG-BgN* zqXivHI^AyqrCteVoaH#W#b*zJIvy!Y5m5(>?j(1wfr{(`6kL~4ueZ~u?rRYxBS;WF zOSJ-{)Y8W*h11k$7lBrj*Gev$EX?3;gR5Vk0+B12fNLU!xpp8l&Ny73 zse|tLm(0lt{}$@icEFV@ys>$yQwM#qJYIf_;BT82o*S$p%|89k&#n*_!Dt|7AcKN- z;9Kal1_q)U>t)JxGiX#VmgHBQtbqMtodg-OI5-}l8rPFSq4GLOv>WSS)0d}&${eoX zN)LE*?CR|BBs0tz%PJ~a_j@%Y*?FR=nM#|Eh~(c0pbj#Qv-I}``n_!Iv6jX0F~U&$ zOU;g^Et?p~8R*T#ePJ-uwBrD8S;SziCAAaDT&;qCJww3D+%q%D05f+;a2(vGnJo-gwJ-kf>( z!gYf2W+I`2Qd5Xv0rC-YnXMU1ICxC#ax_Mo#oNJ9{e;KP%OKZ znPVcYnZFR4M26ukDKfefG}h;KbTSW}IO@z%;=6>wTZEravGk-mr@&pagH)8@@`$sp zXBn>&GP5Ixe4@egd2r**(l=yZ=Q{D8>Dh7V=xZc+8PgmYo2m@YhhGk&FNeWwp#EC8 z9ik6)q&O+&7HU)G8y;Llzin}zj+riBPv*9K3#3+R4atRA68t9WN0Ea;3$jV5Tx{f) ztjgC~e(j)6g9uD95zFK(?f~P?h45P5{{va+*XX`FSjCDHL(8z2PI6$%h!0ztae~97 zH%vVl6Gv2&)gY9`de)t!W6S3YWEj6O~Z}RP)Ve1 zmJT)1W*8g`{1q5)CL+VU6RB4TssLSkHMQF zO*L7s6#Q)~Jji(WG7D-NAPwt#+hjF``t-?5f^k6zY^Z<(JXnOrM)o9)6p%*=wuWV{ot0_G({n>5m|;ky+gyTCvc=%f$* zf@hu&dU#Zthbq7?**|njbOc#^S9o&cpnIZ(SVfDiDzyXy?j)e=X9vK=L1w#UVzmeN zbNtPYFbmn&vcp~D8h4KGckx!?%UR2IXo+gH(=@DS{s>xaCg!`2tE*~VVzB*mcRIv; z7b@>|gSPdR5NI6#IooijX_#?X{yI_(npaGxq2gVWG@j)E?}B@im`+n9(!MZf)U2s9 zCGF3(kV!%F%#{$fCW2=;cL(p>o$ZJcL>kv;%H3FX_1rpZ94)B+!U9Xro_ghsgG32r zSBgchuMFFGHHb{4+pgwXl-8e0`}+JzB-I7*VAr0Jt1@@YYJF9zuk6DkAX(y;p^~-( zdG~gZko(*@R8XaRpCGZHKN4Q%p?a?rwk>OHEc@!2eXK`_^aYrg%tP${NPxZ}CaN#hffIm=u18HHVn@alURt!guB|Dz_RjfgX3gA0VJqye=eB z?Ehd|Y`d#+bzROG$4MAtWFCIg(lQ=m#?R|Pi^@!@NHZ+R7tfWO&MNDDTM01MAGEOM zxWPviWpCWS(N7-sQX5!-ekx&a+w0Uhqb%7Tu3cR8aR(yvssZR06ET4SK!Uy$3AA3; zjR)|Fu)BMLL_NIu(1`jd4NZFQ1rIvFqP}B(KKMI6c6srGw;=&u7LZAEK8tHoT6UD~ z+huwli|f4!0u!NON5e!s`}s8nZ7Qv~VCZqW1*p2xq}a6r%cZ1UGLIO@7nNf+rd z^VqQ+WTfmfn2AgoNxv4d`g18%-ho(vZKHKs)L2zk9(OWWb!{I(GhXxZOnANbx*1YW zsziP_e91Jd&v=4uq?+#sD0Z^UGLnTE-aie43mBO_?7By}FN9aFcPQ*gVB7+if-4j_6A`&maE!uh!x|3F)bTwH8=tXK41U<^X~plOy~`oKNSYcd)WG8X z^Mm=?+g4CW!Rn9c*1x680~mJ&FLn~YX&tEuHs;&0v%ycEYaR7!+iZ*Y7jV<|f74a; zBXvo~mh@-_{hORcq`Q_dtF9I9`Oap@LpTGeXI_gt*iRCbah#zY-7Ow`RJG8Wo*7s` zFX+oaV2?9<3qG;7aUbSVv*7r)Vft?XTAbbri4DL+rXUi&a~bh#@boZdc{EZtIQnX~ z|H-Y@X>t*sK5sk+AW$R`6i(*Rwg)5++4;Z8=TaI<=Hk^f3o#s@!X{vvspt6g)Ir;OyiIpk zgO6W20^NX+r2vXqy`M*Z@=Tsjk+p|4m1M*<6um#|P2ggI?Sr$(L#W%LR>1sY8JtLJ zVDc>t{{WB90}&7wg7sbT&Ka{_E2h!MfF6cj|KP6zrn#Zk1R;Qe*kS5AuI)~4IyU?| z?Jna`gG-*AzDnY6Az5*@7z%#Jp1gU4wE?>1iD2=(#)BM?>fRcSvzu;5oAJ-!c^FdI1ffG9c@g5psLc->V^2D{Ab#FEO=iN6H(RXY$@Qi=q*R2 zd;!Q@m*k^m9>#USjK5Z}P>Q;3m8a=~j*>}Q7;4?p+Ai*Zu;UH(-;?y&Cm|eKw?(k* zT<5v8i2EwE$?Ass?jhVK_h3Uye~Zr-3*->n={HUQ-Ax%3@XW0!TDUt-$^)icOH>%oNGahLWQOJO4U~#oaHxy7FeekZ{wvl3^NW0c5tW8`00v3jV0>x(uz5fWF+=w zTc!9E!Z}vAaXHf%zp@m~Yd6V2yo5dxMfWAwDeWbo`RlL*tT!BC)7~*9wg&L6W3dA~ zb0kQZ9bYmCOCAV0tW03ZNKL_t*dDpWuswD}l?D452jl&v2~9X&RM4~y+Z zX`4|tXCU2lcQy+yKB0-RMG@lN=5wv^jSd*$t+bKewWB4c-V_ut z3j}mFTz430w8y2nO&}fc$l%u~z?gs%dtOqQaWHnv8jLB?T4ZsA!mo=S%U9n z6#Kcha4}}bINKnB4uC2tbu$uUtC#nVu+2 zu2T>xBk^$taEi24aVb&xeo{gNIO`z0euUzwGO~_QeWlgQ-a77XfEjEs9~iZMtajR8 zV}OMV@;;N&C+aKJLhdt@u?7i^a+RP}$|>6XJbCZk!{Fd|1PkvOBChSwewyZ{QDZR4 z&tKUz+?|D}UynL=ld!*IJl8s$G3r=zenJ23nt~0pPbk|K&Wk>m9U@fpp zQ{FsI>wg#0Qv-o|K#|6VG1FMkdYE3njVC(5AAzX!`7Wh#mm$pMn`2g|Z=EreiikkcLS|&(CXi^hj(RKRbKmxB{*19tOpx zP#le}teRlciyQaRhR-?lr-PFUh#owr1*O8Jv;i=VZh^$DI;^XYu^2!mDf1YMA1rCW zSrC0(_i@AmrgujSeHWO56{68fEs~W+NC*rh8LPY*Z-Bz>CQXQ7dDdp1S-5z9>+H_J z&uxPl_8{y@tfO>R)0ngg-UF@uLvXkQoPp?Bw-*Ch#Gtt4+JJOQ*n)Jx{JxY*Au^AH z>5CAw_dliltR=j{@B9615&O4<#=xuqq$}(QHx% zqBK2)IyLP8uS9D3v2a200i;??=EdMrwddwt(NR>ieJY?D!~GU@=3yZ9%^rvaXP!pm zMm1q2K0ltId7BOrGn}gDSQdZF3|5exmzxh=Q+WuYp@TjCN^oe%^z@xnGLR#@ok(Ci zdNlK!w4cfxiU-@t8HhXNm6RK&#`Q=Izb%q!i2^bbQLg9%o|xr9yp_T)>|%yEhrH^@ z5JFY|-Em`{hH3Z1Jkr?i>+o`;q3a_{!B4HVWF86$y4-m^K}5j%>@2f@J(wHom7y*) z*z}GYRaq~7ogb>R@8a6VIGIlQubUi7Y_m?U;Y+NF*6xj33A4)Ml!7a!;fGv3Q(<`9AouQ9x8f`=Bcz5wA&LGJzRw*EVSjyj5n z;n-BNsDpb68bQ5hx_H(UNKCt3#+VZ!f0~8O>ZKGMKA*AiR)Lb+rhZl~E8P4KMpt6(0JNn;QOvT%W^ zP;t_{212!9N&cJv5@^d~lLSJX6gdQ11tHlCQA=kYF}8KmEE%}2sS|l`x?diEKbxjr zlD)n_e3^;oWZzDCwbb!oq2GmPSHOkxBZrGunQtSxaK)Ntl)CDcQ3e-L1NjSTi+{W`**CLvKJu0?)F#u zmT~D_R|AmO6Py98Msmiv;`*tRvpeZFXCZNnM6}e@T#pjLTZObhFB307!xqqo#R7Vq zdBixe8mebq|7-+>j(*kHl?22K`byK>Ku;?lFY*s@+d;sX4v27(v#TY~kQ8juIOSnx zQBi66y$1G*r?X8?2Bt~up#fjoQw!Yv=TRhecZD|5o`ZC@S($VNwDV6EqATCx4=uGG zoEv^U0;4VwiHBDh7a>jm?Wf^oAY%d7I$pICi_&U3IuYg(R9j`vx%qCf>s$4e3)g=2 za_yr-LVp>85|6HRU1LzEbqg1e1K@e-&X^u%z$NM{H(S~M6d^n2zZ4wQFTlLo7M_BCcv01ySt(LN7-obCp4P+r zdm944aoVOEg!Bjyq|-hM+?JL&r(lHED0qs1zlDZ(ra89iE={8#Awe%C+51l$rFW(HEKACmO!%g->Ty?20dT?6R`55YWc zy*6kC?_j_hC8qViYEgMGD-tQK7g!zqz46MQ(rnjb zBJC*4@;rpwqfEyN5(L$2&OT-!!s~~t01XQ~e_aNmWY)2W?<{DoNZJ7I2KGFYLfq2{ zW)u8%Q}aUGLx;4WSVuas^C;(0;(CSn{4OCZ{=z(*DNwJ>Lyp|HkZU!{U>y%_ClRIr zP1_DK-?4&qaroHr(tcF<*{eu7gB%n#9?XO6OOSD$f{~@*^j+)0g*4>jjPbxk(*Wb} z?ApPr;OQywbRBq)>UqnVNnwpE&L(0mcDXZVch83nfmegm?_CVp;?97w>+j^7_d2-G zr4j5C_kih%w=W>V1={KyWez*ayF{|UravwqJ&=HjIO9MY##E*=rP)=Ij94v3%S@(o z(J6I!;08W1bxc9$i7)KvAGuUPA<-O!v@2ao#8R-mH@3Bps+6ng6+13^_)R1G?9sJY zWqdn0FaDQ6!X^HTF#5h4Pmqzw6{6);OxpvSW{tF^N9sB-tfvgrO^rU6U?Eq5BpqC( z4AK9?A^Woc58C1Mw+L^dNHP&63F&TWSYQD2b{eQh-X<`u!jtcH)Te0{X|!^)W|{_c zC|kvKn1|a_h-AV#$b9Zm4pa5w zx>-N#9?hwa{jF`~rqBqwv2o4L{X%b_om&w4?P>5ymD_kh>dVSBKfjGduesTZtFI1> zplQ>nxb^@=3nwc&GlJoSzTv&&oi{;fOp9o_SR?VQ2E9$D{qg`oI}3Y1E>I;C49OP$jH}vty=#BIjt# ziIi=KPE0}9B};QD`xZW#hG3S%@|>9HcIxQkgPla)hqCdo7hk)Huh!D8T}51zFmN<{h-LGa5jP7n`*X zt~E891@9o_T0TAlB7Tv6oJT3{nv80c{=9Caoyzo@5>MY*)`N7eo8BT=?r!^aVz_?p zrtdzAy05E#;K2j-+J_Yn3pA*^rxEon1aQo4x^; zBYbc^n}iuR`k}H-#tP1gPtpI;_{8*H+|QcZk!%NQXjPxO#?ja$c6YqHZz-s;q^%;b z7w|TUUOa~1@!wX4R3k1LKoed)QFOD!8zLi_#&ryu8y8>#2(IecAh>fPQ&sD#_1%x6 zfb3>JYS4Ic=(OfqLE+9tkm+ z`oiIzjm!k&@10i<$h4Din`oqdK}o&X@Z%|C;$lP$lkizHPR%)gleVkis=LeO^5?10 z`9oj}9eD|XV+!xT5p~hjY%aBndp}H1dg2r|sC)Sx5EZY$7X>_NZ-^P3C-zxa&3B7q zW1W4(4SUwhvz{w!1Qv8NgR~nmcPsQP2ECj8w(nqI+J^<`L#SBrE?-d=2OGD}#l_>q zeFlVY0;N8gQL&ct7Ms5TG?%7(J3*cQ@`8E0i2E{^`wqTBXWuK1!Aur1IO+esz&6_g zQd?%R#Y1?880_OE(O*VCdK|6|HJ)JOxZ7&$Lt@O{DGKGmEtZ>Zq`z zqfJ$m>7b-p17lfC-*~jZnASr`%ni3EQOB5n3JQoX9}LGYtiSvXVZB2Jl7c@i&ZFR6 z-BRtGaF=C(wg|7}CgA1j+7Fn8?Go zVZ{S6Ou@sWR_=mH5~g2pz-vJQsLwW+w9|dod77?0+zjOYgc9tu@?ario(Bn)WF}Fr zAv*SvdGNZ4*<&D5s#Z}|q!bds4A;;oN(dJN92Cbu6!(c}Ii;$n5Q}sdqRD*(Es7Lw z%LedAoAbmNsqMaCKIxFS3&|<-F#Mg<^1)EVeIxutix!7~%@K|ZExv`@Hu`;|(oX}- zrEv?F^qSGOneR5LA?4u1s7fqj3buiJ6TH64z zK~_PK!UjSL7V@rs!|lFUPVxF&r}o0n4W{U zJ~$_PeA;!{!xT*#VD@#m4_@~-bbDA6i<nYMkFX((!M+*xVnKH9Z>DR{S`F-CH~aVboO-%oFWiGT!d0?`G&UU%L2<}4+gZ$Zun5FS25 zJFlU={Ao&E6^Fi8OL2xwSCfnoC3q9#}1KkR7a;b;F?L0RWP7;l{ z8l%~@4jDJWM(2oXEt-%~f21AwZ9*1bFWjHrOqsxw$T%Lkjvb5i#Y|>fZy*CR8*k8) zhu2+m5yqfdA9)-yMp?e$GY%^%F>ux~%pLqFnTHKA(&s51<3kUa2XVfCNoOEA>28o> zv>-Xz3?M&n{ z2E(k8!6{QzQnE}k&dTh{^mOGt+G9)?E-)ri9TI~Z{_3DwV#(CXTm5j!i!F!d|C%>f zfOD!t0V^;0Awj*1*-YX0-G%rja6vvW$Mhrl1ZRGSdN2^mRw9Lq*ItJ}YG)@e(Vkz1 z`MdD$dpE*)1g;XC8v;Fa=z<9VO1tX!bp_J|1Z@Ty=6+NTCZn!;%|?FHe$Jlil&m>{ z{@>aGWEZT(?%}=?qOyT8b+N&AIYv7=yQ}MnioC6=YTzT(TapqewzE%XA^2a z0(;!-ab}+BdPiFn4|Z}*;++e!C*N>sb`vz*BHBz5e75_(0~#*_@!8W%i=L0c!o5{} zbqK-pnOG&|arohRNN}`E@ zIHP&bEg>oWB&B0QLj6igv!33CcsvT^Zz^EF?{MarUBd_{Kn5bRTWuGaJN91e0g-fG z*e@(xkcZSx~_D5{+-i%j~U4IV+CKwBA9P2e7!n?{(CD!C?*F;>=g z3?z}?PDi+6-wTEt7-5Vf(>Mj?*pIZH>a7E#utoxTou?koOg;Ly4i+H>t$#D_DhP{s ze+nWK8i@#6deu+g?1($Si`e!HiTlkEvYil5tt&1T1QjcULN%uzO{2=xa>#TG;;D4+ znw>rIvKzMSYo$6Fh=-i@%Ro-khMwI~U+-wE-wFE6F}n9uwgLC-&LCVjY+?=yi<*#c zp(-*w8A}SbVySsZKluFkj$9M*?gd%)0qEP!Ge$xHrJJ5n z;LIr2mo5wIJb}^20!z3@v;V^Ze-eaiV;XKVa`A%v(Tln#|{P~UvtYW*VH^}x$FKFBAuolCs^|sEgYgun@AsP zEQLS!PE}0uNiQ~;GmkiY>e;xq*LZ-G{5&6B z=BI^=7}_rkZ|xrP3i5W%BB_pT9tWf4=y2lb=0RP_*Fp7_(x+Bfz{BdCTR;Pd4md=; z4)%d|yI~;xKnHRV$<3UCmRQa}H05oQCWm)pSg^p#eC!4d>z6EXtz(3zy7x> z$5b~Kh?mYpKJb=&2KxBwf-bZL9_xD<$37~sk^5-0G1k%==8Q8u^!#_%jh*T%5o8Ag zeLqq{2}&|MxsXx=Bay<;;wiW=^+OLJ)?AjkOMC$xS)gwkDm))2i@d1GrAz!))u~)V5=y_;NM1>^ZK_6$qKnetP0X;HHb5M1pez^oyM=s_$ zf*lcK1sSV@Toc{|EQk4 zb_e}1R`7h5I%wh@-5Y2jsERA7PHK1@4nMFS?F7>@DxnM zmAb&=V!7w$^t0ZPmL+{Q&8K!jeNScwF^q9d&Dndc7fU==AhL{gD35JOKZx{m85d!; zI`YB#$*AVj?QS*G!Y~S2cDrC6P5Fe6#XrA0^kg^|4SXBLT@$Z@>T7 zL%H<@#`l*8;iBx`! z5Z68GyYm$Ut)FUB-SUHr66%{FrcrI(hi#? zrXBAwiP7ARD|7mXG?&(3zXK2N7#}e~*YO^_nK8HnZvD5=0}*dL0PZ!khlGZ?tXV%` z$=k!WjsI%On)oe1VyuHYx~E^RzfFFdv6KmJhubrhHJC}x8 z0L#W-nD+WA?2MH*#5QmTx(nz{gwY72g~{Zvt~!AS81J!te61^)O35|P45#`fk>aD9 zshWM6Bp1|JU!mRcQRO1Jh8eMW z{M-vFhBLLms*=AI#_?;&o*o^cVM$tNgWDbB38rU0Kf{pJ3q&hSXI#AF9)z`dtwH+# zAmezE>uI8F;c9BZ!D^b)k@oVu1%iJKDxx~dMpj zzLidk7D)|}LNzN|9P6#e-)#)$6zuhzXN5O1B=wUi*fb(vfNe*hY_R_e5QTG0vCo6> z{eT{K!#YJv;6SJ>V6AgxAQJHcf`n5%8!~q-&69=ng=-7?o~k8NL>c{UHr&DiUV!;K z3ySDsHYIa4jKooC(uLGIShg9whvPf7?=}EDmb7CJ$Sd^SR@z=T$nyc77tcXgFjBt! zV;}!5URxXK4O!JhV3P!rd9*Q*URmjA(LHqe^tm<%LuR40q6`MgEawfYQ*pZ%`ZAb>m8AAkZo8+i@9IZk`^6wJt@ zXP6>=Z@4vaPsn!Gpv0?wWh+s{@O4mytdG23yf#14GSvvw!(Oc4=J^xwUOk03f(+TQ z@!p3TKlk?%VR`6zu4f3ox4$TThoXFdqpUlqTDfNltT|##5!_x}wFzPa5$*?WV21Eh zA4Dm5P1srLE_0>vycnGcK(4c=5mLQZz|;Ba>mPT}(6?U~g1MfOPH`O$P8mx^v_a{p zNKscPXDR;~iCTPFd`oY=q$!z@XE-=@uh&Q?c^-aMfRbC(R*B%{AoZn#SH$5|w*H|@ zxlP0kjEV27H-oV0fUz4lQTz&cENm0Fjxzu9u!iGwyc_Z~E}*Z0@$UzzPeN!s0q_|4 zY}%DeSyP$Wj0W8N_Y7AP1XEt|mA15kGLO1NRa3lv-r;s-LN`I8pEP=fNxM|x=qCE` zA*juu;EeA`!MNMfaMtV0Gl9Bi0*j&#Q>~#CM1p!te0>uPM2@0QtG*cnl~gF}2lSA; zhH=YT9l9c_ma;toXZNWklo%o1`4x)$4#q(@{B2J)rxcD|OYdD=e}N(UHJb1%6m=y9 zj5DRQE9+_6ejkL9DNF}&mHsr5BYsV$kP7cN&aFr7@f+dH*~ZY<2p9XE%z8pwn6~%G zl0DO0Fe__RUpf2u>YAR>1GSum1oclo5X^w}U8CwsB<$LOw0wv9>KHw=Y9~Ec>y}3r zF)z#q*euemPeWHndVGZ5?KrPQM24uj7(0nH>W&#bC?*_H3;H!3Oca<0=~|m0_12nX zHq$JvpbD5uU)UYiz-pWj3w`0`3r%PH@pLMZIaswgGHw$%V@Ng+%2=ao`xso7_as@C zp#QBl_a*v3VlTyMhti#*FG^IeIpm1XVg42Yvnfc>K0MDR#Jgb{*@j zSLde&?gk(I)-Q-79+XvI_o&C$cq84@LB1QIW!J;!EkXp<%`Psx79kS}=CQ7u=o#P@ z0@t}tj99swVo?d1NIbv35+?cK86B$;9N81H16M1mTy=*hLudn2cg;rp7F-wo0VcZ6 zoCg8Zi$hfdg7vh`a*8FM%Ru~Qd0hMRSrGeduOA~{*Ls_>Hq7_ZbiZ{Jn-bS&ota<9 z08?OBsJ!l4rb%zgvj6;7IsTe(D?o>a6sjWAXbm`SA3%dHU?rB$L!@sQEvq--Uu0vK z$i*kESAP7xI1+mxI6iaA<^o+@oNG$J&hpIT)Ho@G+YHlM2?GFvKz+Zd!<*&@^IaGC zL~c7Jf}OU4*Lad?001BWNklRN@WO?^?V*uYxN67*}7cLROgb~<3pq}$yYh-xeuXy|)N6ij)!*BOYv(+265F5f1w z>vJNT2`|APS2?Tg5oe&!mPsTLe4a<=-3MNN79um61@#lm@?J$i>Ia;K$VdvOpI@Wx z9-*t!v1(B?lUI+gDzw~R@z{J+2K3wER2u1$X%K)U@3eniyU`TQb9->GxRyO3!=R3v zVC#Zn8ckVDfyqPLe*T*7+Kx0{`t10WiRwm4b*!@ruhN@E8klEmlLA4*4Cpr~x`fsp z^O{E2!S?+wzWwTnp?r^xMjg8C5iY0SAG!r;`U%vi(1u2!kVBjKvb*u?$V)ORk!s}a zSf1#HE}##XTR@CDs22FzI=E#IPN(aW|K~esoo@;a=i;sF6Hy8vl}1o<_y~-+13YhJ z3q(Ezy<#qgO9LWx)A~oLCQ|*?)#VBqI~zGmxbqBzz&uD;VqRMIgscb$dYq$>s=@3O zna2dml7htPMx==Z)W2G9yE31F7}sBb=d!=B3nJS^6=1#+gfk9Qo@3mQK<%I2a`ggS zfUfP+L1#I%Q?G#PtJI<x&N-DK@rL=1%%@ zW`i)-RuXrakLLJeH;;NIdjW15)MU2~L6t=}X`))f0vP|@vnuO-<+r8>1+u_I$RLcN zra;L%U5z}klePKtVO;|(>In*K?}spVQ7&xT&4R)LN?*Fx^UDQ6~?$d-01G{7~EJ(Vxj zTGc*v{Yid}(EOez?gCQ~KivOO2ldu3Y^c8-`K<)_=$)|CAIq}u{-*2>TF7&^b%`K} zjYWy~k%)P<|0NTR4!l);_3SpJui6(~%j=ULaQ2~PMIB0k?L`{dbb11LoP~&=hsXsY zO?}Ez7m?422@t)=4ua~dR--u#_?r=b3Xpk72VyAov+fluUob__^w0GgY3rj%W>JTe zV7KZB-E$~qw}F{xzFSC>GFQ(Ok9ix-tT&KU1)P0o36{dl8R)(iW*J1H)YqopYtM%$ zw&s&1$RuP;ky$7edkIqz$x789;T+A{zxM+VBAG3w|C_)xC!>-KKw-kH&BSZ4tH{eW znLc0w9d;=*kirdEA2G%lB<-*p-oSbY?WJ?cUJ%wjz@gEA%tHs732dsNLj0rUNK__0TVMBy5PN`Ti>U3RRY6l8~n;R*#|T$fk3Iq)k{4Cq{Uw zmij8g{U>1>GK@yYi}lC@{Qf)8zCNlgpR?H@+_{HI`f2|~aEJPB3!!t+lK_^Og336C zw(wj}F%Q-JzgufG$7p}chSR(oS_qN*KjzQujQ_di5V~UE)xTZ|l7H~6S@y&4f@4ez zvw}x><;EPVY1OSlTQyubk9)u>Nk6?6=W2T@uYw}Uabwm*@{5Bok5TCy^K!jOysZ!FC5(y8{L2Xmt z;a|p09x8S6y^JIEtEDOF8QMmZ&np=mhhdr$eARN6x7W-z$*a|8(82{+v(ev&s7G8# z57?JR<~gVWxlf^=`dDZ`$9W^?P-7_!SX62@{$Qde9wGkLjr}6}bp?1(N<}eH?S2Yo z(6q_27Oe8qvs4a<*CVixS7LeO6Y+}#+8Kyz=dMWv&F^)#A_(6NB-!hGF5y(%o7Kk7Nx z!5H_Q@!-J9*F1H1e$uPr@+tSE$vbdoBl>U6x`Ri7FU2)PkZ7RiZ8iaB-b)4YOHH0 z*PReKk9F+}NFdCz8Dk1%y}%92>-SQ(*TUL_n{c~9+H5hLOv7l#m5~3xhw@E*uNU*M z9N`#V9}=)k%8P+n1bR>_{anWL4TPHb0)e1M9bgJVyyw3L`(MkuOCpdJh*Vg)M*_P* z=Vuf&_-o+P!s|L0&{bW%yfsf!UG-b;KzD?sdkl$3b=TYPrjj5A;OQ;{m9IG zJ%LwBi87FwjiKy|jvcz2$ba?bd{dc$B532!Y(^u6UZCLFp*Pp3)@vZcWwg_4;G1xQ z_M9@Af)L?q1P}LHlwj$4z&x0;>@r0)0@vt3|#b4l$TxyhfdH2v;oUYb50(CZaZ8qc-#Z9GXX`mK>gAO3tat$)GNi?oQ?rq`@oVS( zXJ8(UQh)^JzkD3Y7*QdVRU$i`3*xg#W|xDG&0GViLpX>^sp#V(`{Y(E{jqYDWuEa4}TEFp&Xz3D+B_dpB_JhyJgMyl(>U zWa25Pb9G^`1k3RfOjawLI_P~Di!RqudVz!VYi;7r zwAyUfxYx}snL%Aenn92;AQU60NvNCn6lZ**C6{N+?mHhcj1j7%<4^|1&AG} zhP1^?hUmihxPZco_$xkLL7%94>I3TN7o#|%l~jfF%5}lwtLNNIZX5ST65>7o^?LlL zRQ1-UBR#}@8Ut`{LxDf|Xx>o8ETb%B!aO{J@-d=oYG>-9O}N){ig90rj;Ky)1YM=5 zG82&k&}o{hO=fKXU8o>Y{t<*&nMex82sFm2Z{2z;4LIuOqAadWTms@W!BpOR4oCu; zKSr=R;T(|oZXc4LrzEz4gwOSlOIz}b@w8&{T&xULeW;%Pvg0`7#M)ZJ(}_+0Up=o%zanwCe56{c8Pi%%7 zwhihcg}^M##Bf~a;8YV5{C3u%rQ-z(kRpbblm|~{Yi3@aEu$%>_rObOfcWmYLi(T@ z6)3p5fUgJReTXzk2xx>c@$j6rkK3QGlCtN^6iLoSj0~LmY{}gU%mU zAaPB7&qDMsL0U_Pmjr4t(sZ%|-KU zQ}Rp(nTTfNO`yN3Q!vFFn0d~;Wh6vhN*nn?LBUoH0o)7X?87?h+P&+bNfW3&yH0cG zjp6v)GaSczIaFynxGtU_3P@H9Kh~c%bdY|y*B73yrky-5BxN9~=TaB#W69r>C_R8o zTmr0~?rz*TSO>?vYn-Jz$Tcm`5?6TI&8)$8?*^_PhFLuUWf);iga~ID51Q0BCGa8) zpZ#1fE}ovfnR3|&5h#!- zoQhuxEKj|ZWqlMZrMn`IlwCmokjZVQeGve-NIl` zcOs|dUZk=Q~s&27CTiUq6st##+dPsTUxs zLl=*M*kr*c83QV1BAW3!3$a5y*-=S_sn9om~q!jZ9IXn!Cc;m_77A(Fp?BO{g%LX@c(59`(sNn>75vyJI1|b zNvQCsuqz$tn|bV`?mAoji^p?jp}U>Nbv9>33CK*mgf&~3>U;)*37*#W(a~ICcYg?% z{1YWh0W;1tA_MWaYla%LR6qoYkUqzE7yk}fFk`D#gDDWiHz-->+})1Q-Lccvcf&#H z>Y)FX2#VV-5IYO7AsSLMnF<*H=U^TkyUk-Lr-*;|Je(IKYyx-4vsuhM>n3qA_@_uB zz&;wk=>)?VaIE*RHo_Xq1c>(~G>+1*y5Izq-Zg!UAoC2;y6@bj?c(5Q;1rBY%PduS zL6=Nq5Bc$|@?!6Y$+>P(*Vx$RYoO^R=ra2SIzv>bgRZ(^N}6HYx7|QKw7F^Ax1DTg zVv`^sr|Dw{pQ@_F0;n-BO>Nh1p{;3S8P2l#NaHu;W#4unXEH|A*keDx!$P{)M&V>2 z?w{$#sG2f;6HH3laQsz-s>?aD{)%h@YekoyyM)E%q0Tj*rZfh5=fD#EJwJXH?G!E`Z>t(gHUE8aG4n*A(@+>ojei(?VESZLV zbdI_-B4Q;6xB}yC&#~-<%co^;q8Vm`3d!&afk`c-^vC_oJdRM`FR#pLj<|CKn$b%I zS1VHaQ-ZHr%bnvj2BJ4(O~C8m3V z_eTq_AsrnDv7$S27e4QSfh6GGlcJN$x0*Ir)|_-P@*+}Q6WmRDc=YXe0lkCJh+6JI zZ-VRRGc6Nq0L^jLH+!6C3KH)oM~kWrWG1T^>@RK48ILNiIPl!<9@gcky$Bp;I}}C+ z(l2N#>}ExM6uC=YAgx0uCuOG(pUo!1F|Q^0)H!7yXq^5#zO_P`LL1qR5qv+Bj=h#k zA)=d?-596uI~h5f*#aIb5ftEK@-w~;_jw?;T89#%3O6~%p!`;U2#e=d$W96!RS(hp zTaVmpc8A&D4$!8lY^LfAe54i)NvR%xX*kP%<1e%9KXH9=MZU%{DD#L}9A#`eGmf)~ z;(dKHZw&4|`2GvCWZNMDg{w^)5ssjVC3LM-8R}v`B;9U-ib6R!*Q}vYe~q4@@W9uQ zShX6`cT!Z%8re?j7i<=D(2VXcYjmQLhO-Zu$6k=63Ep}K>Z@7d%T0`-CNQ5+PCHN? zy3*t80h%LDK!Q_3Ou${caYpKE7n^O50H+`Vo)tO>Xy&U6Z3)RDW<86hR8rBPp$^*i zS706GO*i_bA7vnyPwct=VS8&^-?53%*;Nw*nRk6IjU0w?1;zo4} zL&)!42GL~3RR;;)a-=gIB8t1hEsKzDmV{Yq`0XHc?WjqW76R1%ncwx-&@QyCOe&5I zp3Y%Led55`Ovji?zH>Ve0R? z#cBFheOK$<BDER-QE$P}# zu6z8=(@ja`?_?lu?+09aX##cep^RGktb2(c+XyCc8coTYQtsoO=b!7LGyyFyY~7f9 zxd+5BdK*1N0}Toy)+rkGj;R&BwN`NM&QHPoE8ce{@S5*NsUQt3VY=n2K%kmTq|>0L z+vteZQ|{_VRc7|w64@U z&Ynrq)T3|(;;cZSVi*SU{QCX{i%LRWeu!(Tu@VCy$D~ie zDuFg7@(p;`eH5N_Ch#dbiADx!?(7%AEA6PAiF89Hfhm2Wb?U$XH-8%;V-Ml@uJ*G0*tH8A7=`-Kq;`&7Cmx=^5+kKV+v;zi7*@Lsi z%LsG-vS!s*NT~Sdj3e$V7&0>HIY^t}3i?ZR*_HI&Nf6iBjB7I~#91u3w{Q40Hcy{t z(8JRpQ1y0Bqg|9|Pb<{CRR-Pftg5vjR6^!)nt>fbt3a;=By#*Uf+zb`Kx-`bLAg7< z1QVdI&(Y6q7FK209uE@#jSv>Rb6YMCj*>pr!G3wHIuu8O=x|eaO_$a=%t(-dpCtTx z=1BTRHE>D?(zF%OA46SvX^H#ASJywDe~t>Wo)j5h8nNT~^~FSbxeHLKY~>0h)E6s( z_ERVIb+3TGf-?*)vy=p$V$A(_@bD*?4a#WrU|9^^JaD)Fa_oM} zl@NX5G&R{O>9Gy2*I-Y+3t)vD6x+CVaY-P2H_qT5kQxK2?*XZ(dYpae?qe*V)yo`I zSPAGxrVg>s%J6M{;ByF8Uq> zK_X~lFJX5kqQrJJ`KF*Ww*w)-L!>q^kOb3?s;#zN`Io~CoPmhtBBAMotJdeL#oT8i zY~IJF#f|xM{r_ItN&pXctv;2VKEyf*Nx2W9A19M}Z-3p5YBJ~v)xL_(f_auRby?SzfgVZ zIaoSW2hl{~r|t(X5O!zS9(3oPja2HdCo<^oo2a|9tpc=$1REQ{nd}YxyEd)~#!%b0 zGZTJ+%GC!~3@{#dTWK(GXcf?sh&x-q_yq*`Q!!xR_@2J?zm8qVevUEqPY?utmtbzv zai+1Fx~8~TM(p+=;rO%1@iFjJdnmc{Be&;LDxo?MwumVn1?w&el8a)V@>KytP|$1# z7lqH{Hsc6WU?57e1=zCAmSPLrHWfGOx^Z{2(pccZ>pIj0w^58bd=#2cfz^j;pN70) z9Puo55kHo_61Vsf+q*QIP6N6AVdSeI(#|g2>{iTZ%U~{WN8PhRL~tw8lH&o&>+E3l zaK1iaB5z#E{J&vn>evIVN&ko7&^s%E2 zJPYR`@bWBqXj~Gs0Bw~@Q|jlLbk0F=Rgo zu8bSdb~EUkJ77%7jKcM@Hn2EXvEJ1&WS@Q#p=J|x9brUmX?!EzJFHqDwlJSnV||*d zHibHgjr}3^E?iKm8wA?x@Eqv}ZVDiHDkR2Ky-Z0Qh9i^~#q)s@>R43fY| zypK~SslrmtQh*Y?5=I1b*_&qNV&zyE$P5O-&DX}{!+jY=s1FHEY{S}145{1ptu5_6 zjRclX2_d`fK#v2qRW0d`cuk8JO=mVka$iRkrT8TVJ8yNY`No~ub`EiO9VD4BRg!&6lNw8UrW#9?c%N=aDv5Udkm^83 zh7ekp(HOVh4$d<+3+T31CJt#CS=orI#h|kfO?XEIO^7q91d_nr(<*Sjd!Vq;`5%8N zpZTv3YbVtR1U89Op2)^d-F@abm@ zQkTWym*}C>sHVB{3rg6}{#tQe*?as{2`l7)w z6#S#xki3=X2L(!ansl6bSf4h~y^co=xFB9^CQ^-Mlo9M6i5z#O4?CP9xF726OW2sV zD!v)R-9B`TB80^A|9s_!W0=5!X_JG+RXW!A8gO?Zq`;YUdC*x(tK1UcdPO(k)r7hN zxH>dU2#Ea~K!p3=NQR_afL3a4E?2}C%j_=n3IkcOJYPV+sOqa&!oluMc+i~Eeg^xm zz(oG+PZ@yrS^;4?NbS=OiQjtN*CRRp`(Mto-~6xWGk1^%c?@j^JJ)arDbgvg>W_Pn z6x;&>kYg4to5G9a--d|5mg$W*W!b;{?i@jqFwKt;wIJD0mSC}!)U!E4=UaE5C+aH$ zI8zD^VT;h3@Rn;JF0vg0`I5!9&P2PsF~3KzuP`iUI}d`xDTt)5QI%kRU)aMqY@i_O zhIPh><34rA-4@VI&lJKYs50^7!L;1RpaVb;xNHVwQvg~JW%~fTdJsR;! zw#izn`71q>ssxDpR9IWtxA}B-X!~nn zVs4weAFA70Q6-)D!;bOl2VQ~b|Idv`-TV3p-4ce(WF99W#0_0viDbFHMmy>Xr~soh zTH6)h@28t9pijMr79fe!I0J(Pfw~4wfisUdz>5T3Gu^y9thc(L-UMJ^r^RN}s-LN# z001BWNklxNF?m$fyAUOqw+Wu@Bk|Zg<^HogW78Nw)x*M_cO3jt<9;^~q#-(b@-%Tp67m!H) z^}j`$`WTWB2wjJvBQTN;bj&bc5bKl>bSF`O5?{IXKfdH{iO<>_QK#;=x6z^h@O|al ziLcth6hzjYTnwJD=@O;lFLK_xcA}kfm}~)+|j}`MyxZC1avT$ zWEZ}C4q>tas;^eINU^G~79%+VmOV89sH9Q+u#0twSqF_A)IB=`(-n?sRS2v*=if3D zyY4$UxEf~iJ{U`|E&^{}CBbW8HiLp|C0bFrHWE#F#Y3%k;-Oq2?NPS*F8WH)c^=~U zmX}`*lSkWIYc=)Usk$y?6+Wc&e{gSlTZfI(f^ptqsUq&C_#O3UK)Bv7_b;=#wTQYuSJF}4CY$Jn86>XE)r-Z)<9IQYT zdat0+w=V?Wa-6S(Y5gJI9Acn7&z<}uxYqa9Z-OBq>=x>CXJ$>_jAIm2a_zWMZUuIY zmo#(#KNvvwUSRbi&=Ln>9RCvrvH}M1V?T_j`#=>j?379N6!CnHS4_gYGmroDo20RV zAF&|)c67-7K^PRCvvbRH&n!rtR7tFJcs~>m^0t|!ycmKA}0cd%c z83YC*VnN)(5*KNA0~uFx28g!bUMW;8Sx!JGRlx)wKs*nTS2!LwjnVQfSGpd?s_&r$ z-g9O0qj-FdCM-dMr0=Vy#d8C>qrEswT|gghz2p!kI3j^LA7a z*GY7{LZ#NhK<-B;c{NDsZ0#rfM?VQuq*kz>_JSMF&|sh1g-J66Yv8sZt-w5J z*M68sEYuO0hiWVr#0x3NJzXCXO=Fnku7Kc-d%bi&!jc)e8cQEmc+u?-qzh2hOd+Sr zz&hf)*K6gbZ1=;rXGiXuoz14Ib(|FkUCXO@4vq<_>b_|n41}@N&BJpHFC!b;!Y_z? z9qzm{B zY;}Js%YOa0Xh#No3Q8JI2PNbwxKR2f;{E);WAXD@>K4UT^N)-qjS!y+cgysA4TM(? zRPD}dsfWOyiTGL1TZz$G$a^1(iS~K7Y$EbjE>u3fOn()}wZbaE^9uBN7t3mD6+Ndj zkf3;b+;qtxhrj6H(@=!yArSR!`a6*P(t8(yRq`I z`onKZcRxEV%YFfR|07qSHKh77dA~_>ybPmP4rh(sq_J??o+7MzU)yr>$Uv;-+~+Ux zP=V$=X@(NPKwJlLCNe14poO|^-=;LpKyQAS>GqN`9let~ z`)=zgvGCX6t6=2_ylR`Tg5*%AP!nsDUL!%j(NB=K6k@YCRk!{Q#6Au|{cpd`wEF2R z`>qdg4#0!xDUdcCv`XSfXc;$$9fT-u+?3B+o`!J*^;b;KJbm_Va}u}S+)f2=qEp^* zS@`;95VXm=0}-?DouYX$`b3J?0j{6?^ml=mNHuMHO*$gQ7nTo6EFd?TWFTA9j6|2@ zvq7W+>ee~pdc_AA$8(kpB*YOW~Wq9kn%FB*vI$t~XXLz>s z<48C9>zT^HiOv{fO1eWS95OD<`AGcIc(-(M0Qg)8s+C^!eXNC6Y0|!?&F{e~42zl& zT9e+z+3`83<6sr9+pkuY>*8bPG<{eO$t_6s#cvHyDy>Q zZ!8bp-+xif%b_p_Zfv3t(z}6O~F(Tz-(Bpo6 z_+581`@J-~oV@G&Rk=iUYQ+;nOm5D#OcNF}+gsZpTv!p>d1woF`k)PNz9pZ1kiTFX zhzrho+CXQ@;z|X!l8?L3OV=fpulyk40G8_;3pEB33lj?#3mV_o?+!>hZuN4w|4ShI zJm#OLt^fgpdU%k75CI%;MX}nFOtE-AL zlm_WJo5Iu~-ABRcgR#)=^zR4KV4;g!BB|E$YNU6fotxL>EJ}j9Xjd|HG2L?)1_ck{ z3YJ);Va6_`>xl7+hQ{hA4-dJDK;J$6%!%xw2PS7%p}%oYh^O>93)B0^Ng`9=H~_P{QC!dAzadNg$LV=7 z$sT#|hDO5=%cY7{ z+F_0XoaNe{)1eD*T$W|O|2c*>X_dh95N#Yb9+xkR2l_^Jvtv_L>FxJ2%et`)+x9Y& zEgkU3f5KMvzlNJXMZ44ZVbPL?DNT`L{H_s4hfo}_>KZAkUA!wXe3jgo5;oIcC` zJ_6ehFcGMD35{Vi+xw*tmuo8V_2}*rH0m5ILzs!hskY~|Ck#X%QnB@{nTYFpK?zEe zB5@=5p22%Y1`Hyn1i}M*-ZZBYOFMHJY#ns-P=Z+dBI(8T5BuiuzMRk)$e9P;cLm#8 zwbOWl$=yOZzlZ+m0L!#p2EveX!CS_mbH!;RgsUS?KQD9{?*MnEHG%q@b~NSfCw`AG zXK}2!m(^Q)%f7bHT?gQAe87YSDUpT;G8LzJ`UZR7JgnNF5td@^+8{TFwgWXDsUX>L6pZE711=+q`?VL6-uwMH$8WZaF8( z)N7f1syvz;Var*C@$AN;D+40e)2jcjB$)qr(;G`&xDtKElBXfKuWUB=Li_}RMP(Oi z41d%0m?i%hE53{3n*r}qXH{F=qkbAq(>!g?cEe^oxh+{sRJk2^Rcv#bxmrz$#W z_oS?+4DoCWN8ceN)3%ce`z@KKy!yowL`D5#$v}Fxdx+8gPmjHN4Bqovwr(rFv5JP4 zcr2y~yKNk6PqdFOy1j`4fRtS3L7pSPyEyYGhTh1xQ9MQWBS#==&kw_l=$`^i_E49! z9djMRht4fMNz|hp!&)NaC0IKmfQ|=f{rTxd{Pdc%Ie7_%tWPawdmi|hccx_;?L(20RGV+PC2jASNKpF7b3YoZh%!CJa5 zS}DJhWWT%6RcpD({&k4zeY0RzAael@3=h_+!=IqatH4Vz3ax6I-~zK8#<%{jgf<;_ z_&COY64`gtwf0NM&BpRX#C>$ICg2Ji>fhavsrpK1hl4`UNt2;CBvOb!4pw*i4hk|4 z3qAv)gJ;~ApFI&wNKM)-RQ;*O85f}F6^JKY+Ge}xGhLdv&>n!7k$DU{^DtiOendul zhzLj--?Hf=5#H>k|tVU zUe0(Qyb;PzTS~)Z6oIB0As-V4<7Iw}|DAoj@4Y3Ba?i)#bM_IxH{A8r*I}u5fcAar z3C8DeLyY*!RAb8C#Ww3|`FxJ=Vi;bH8QRk#$EJq%UEBMn($K)ADk^?&il2Tfz6T_? zfU%IicQAm&N}!7tG8)m*7a(3dOXK$oHmk(-N12H{(nNz6&p{OUA$t6gJimSuZVD$e z(3ZRy;O>o6>%dX&{)AV_Cv!z!h|T0KI^g*A|)tE263KHs+|tO@TStPV}anAmkI@I zEYektH5LXEHx$~)EczeY@M@@!_-R$_dp#wj0z}v1+aT(Mn)E_`OF^W%jJ}ev>rJ`z zCcy78GY@7Ns-uG;N9dV6XT1nKxg{+{@Ojr%+!*MG;H@3t?Bhm0I4~~;oIIUf`1q6A z)?=>)g;-L9GPjwalzWsq!2Lq1%9q_l`PvF-??&L+b+r5L$%WkF^*edxxNFM7Aa>{P z)df4(KJ@GL)yKgBo*Tiu(^UO!YTn~FzsF}DFEWsunT-Z4a2=YusUF7P#&yIc5IDV} zb3?jHj!SQ(&C*6=k&=FH2%RKaeH0Z8|3PTbkAS-!RuOvR{Mqk;%X}MDxIv7sCfEK; zJ^Pi!FBG30Q+Q(9QWeQVw1FNy#i}3r4fc8198DSjEO29S+Jr1Dg&vD3?}lv{VQ_8Okyrf4*=!?wHdIfF;R-Dhs&ScxG^yIG#wprq2TV6G z5HcPM^RPY6K-HY#Hl5LNl$jwX0H$gznMa2@Ht7!Az?o(Rl=7F|K;u;Lw-RP7KWwX~ z^2PK+G*1(QQ_#A(ZJ5uT$>!Ea7{_pdUf?*F*?j-^mLZ*WX{K(q>s60|{@iA!m?ceVyaR!DiI*f#b>{z;o@^1dc6Nr-9fxub8zKc483yxqxWM$1_J%&Ut>YWKpHK`=n@9h zR6Ygkasp+6jxjL%Rbj>QJiHKz94swBgB*3Pbr^=o^EU#neGF6aHqf6|;S%06F50X| zjIL#=Gb!Epe-c%OUEyUM7m;0ma>3Hyr|C*fm)-wjd1N?lwsU}2%6Aw>5kcQrN_XxD z(YKH;;Qf69iF*);UU_9mz~rN@+-17@QX3QVAb!|;RAOe5N%5#z{tjk>uYf~$TnC++5XRFJpsy0Q z#jk_!ocaGc6Pglam75k0-qFwl(c+4-wJ*| zNz-+JvyjD$7+)0JlP)WeroxBon5}&914s!A%24k`Eo)zcWsTqr)i$euc(`f>R%B09 zUU&X5)mR3fB_K_Zev_e8Mp;vYf#0>&lLTWyo6=6d(crBWX^I=)S^1&?5}*0yJG)^P z#Qd&1VuWxv=eSX>t@$buk{`yk!s;kpT<=)qbVurk9_19Q4})O~2suh{F-^A!1!z)S zZ(xzDRL?2_d$#jvK%YXILng#V|3e*%^`u$Z-D+cfbq7?x3o>~OX>kBhHy7@mNpaRmbllJxwe{(NFSHiXZFc&K=!ToWVNW}^$MtbwDSZMudmc8w+_@=+R zQ`*EWw43_UTA7IDEvMDNI;b9^OI8w+2j??Oy1ERcnX*z(Jrxh~(tUdg=!An`qp-G6 zzO6p!byYPM;0&Z2*oI!m2BpDGopuzak%DK?NaVZ(3BF8z5YVlAAPBUSro4jb^=0jn z2k-iyPCbex)+wf2aRZ(0qpp3C6y;)o1_l$U!$~Ch*hc;4qlHyC+=*F5zavOhtET`S z84;o7`5l5lQU=?g$uo3@+mTEsh8GKV9>`w$%36+1xKLFW75S-JYxNj#%gxNPC|?jd z8Vcw*cWc2v`0mnd*HF4FvA%7fx>wWP3W$F%yukX$iwxpAqL`W^+xOlh_}nyr;&<2dBqr(wd_tmnsl3l86(BJ z=B#gCNO?viiiZ%&o7P%Z!!JsZW3AqwZyqdPHazI>h{aibcXg~2CBf4=(G{ZynV5Z_ zCUg=!*i+Lf=nT>6y)JOH#`CO@L9Ma0&kqae6qj>s0>O3gj%6XeUh|!=Wyj#C9G4!1 z1o6|EnuN;T_u~$xsq{Kp=5e0(JOk4SrnI9h)pOff_W_p*5T8|JdT)adv8gTQf8S zRi<{)GeA?k6t&W4BM|Fi{K^aly-lZnMflO(JuU_ zKZL&P+u0id0qX^-q&!BofT(JVzr6>ZnZB3+(VVIpE4E?!vGzQJGCaJf^74KdNWIl< zy)PiVm*A;#U)YvYwen@dgPRj+5KGd_g}bq3{T&;j{Ll?#9_17)3Ah@9wueqlLBgn` zJQ=f~)5(6Bc^+frKW=bB+;BEJuLHvH&%?~d3$~ul_Og(!skWDLmDsHyQQ5pUUisNR zyBGw01BE(Ec&)4k)r)U}Ft6H0$B*FapQEB|>e5&&nW*Z#3b-d^>AZ@-Rrx-qAN1)3 zsP&ewW~-igF55{_oAC4jP(n>cBiwo`Yc=;JpNfFaO5XA?Sjf){)hm`{SolC%)zs7l z^8JXa+u&>-ASK1|Fel^r{I|QX@aY(0xqjbSh-Y{>yYqNr7u5#=)mRr|&B)UMJYMS{ zmWK^K+h5|4DfBuT7({KM>e7V@f#VIf*Dl(&A5c~7v9jk4PvHgy7rochr+dWJ9PB>c zwt_AGeb2IuqjgiEGmr=0 zR4tiAMx!40d`x9pC4fVBL-RE%X#-u%ORIvxK;39SuO0dd427emT%&XIVgNJrLoB&1 z8NqM;LX6*U_!utco!;ZO{5}S>u2+CeMAA_ChHo7lP?WPlh!@(4MhmV^ENlTEVQTl4 zC-6r?XZ`vwSN4Mh-8B-x%GZXnKZJ>VFATtBVyYoYe%DJ9la6=4+g)lk^d$QijIXcM zG$}#F^xg+^HwXXWBS;M!V)V{?At5W-G+8lql;>)u$(l9>iEuY}20=EPt41W9eSFi6 zBszjbdOcOTtHa}I`CVvzYBN@4+ledE*V2uVor)FC@}}|FkZcSY?)DOg@r5feg5P)r zGsHbPb4WvKj&ud}n+oyPP0E$Dw(i^AtY{)C(2v6$o;#TTPUHIQ>{b<)3+dNhP4m#% z)97r~Tcd^4-&dgSRA4Noybbvud-+s$>>XESM=!r5xY423p)K80(VzRjJRtFg5F zb2@ny1mZp4#=_~%d0q&ylfm!5KehYpiYdV_nCe>f~q&8jh@AzbaQm_TQg!;Gq?a2RFuy`k4P=R@m zX%r3RVJd4OOwT@-Wk2`x`D`R)K^{&e3w_XYAn#`pY#mdk5L50|l2|6g*$`fybMVaw z;*D_65)ME5!Q2e7F#s>adQd(!ZpvSJT6wRx*@{#mLDf#IpxNPS#6oeg8H&bfsqv=b`DnGr8I9#8DX?nD-;o9I;22)tCa1a#`7R2L^KJRWOG@i^- zERlJP=M2PR?BJBb-Cqw9uT3MEnyTW#tzes^KGd|b>PJP|wFtJo zs;_N~!_9Dv4VBP;3XSd7g|>kv^c7GoECU%xElJ}JAt_A)hlaLPk_{~$2r>it5V-fb zuVl-?K`jQ0E-Ax1gV&`_2Z$$&79zAg$|p+?+7-f%@{7~UC6$(4)vsu*nOaKJ)Q4x@bji&^%4KbU1-etabHgotQP_!5Ga z6)I912{+28_kq{0Ei{69Th~Q2L#%_-@>97)XgQi%u>;v$Gf_QN0b_z-*)Z3BWp4&#lFf#~1x=J?ZKw7PEQkcx3C=SBv*J|j5U8ou9 zljL!LayBuhG><`_RbjcYP;*rm(~m=~CXcj5-^m8I?g%F$NW{bOW+0gJ?pyyV*0m$2 zW8?*+)m zx{)c{AUGF{5xl$i>h2raPjOB9w)gW8Ww-=<3(Ny)Nuz+!pAHCGdWduf?qQ_#SfZIl={hK=E^jFg7~kU{a4vI8+Qj>Tb=Roc{eXzO5Ya2Ql`nIVf%Uhe(+CUO`(Cp)P_Wh8BcZ>NdMS9;3{QJK~+?7qM4=k zszW?zseEr5tr8e*a~V?mcP?PzZebb42agVIQjt~8CO-^UeP%07Tx*HoQw!pg9$cjZ zNGz~yx4KJ|O2)+x>$X-Nq&HzzDQ6hON10i;ZgnxhS%~)iTA;ar+rf1E$khH(dMt61 zTAUf@^0KZo{LJy}=#g{b-1~^tmQKHH9a4B7#qJ1V2Q*Kmz^{9U`ysjrD2+ zPe)at3v@$#jm%^H2KIe?idhJCX#`S@VaxC4l;)N`mw{RyXp;b=iPK-$Kp$IjO;*6_sAv2pL-8^!JsH7IU-hb{001BWNkl=VycN55td*c08rHnr-|Nazav?M`Sx$@CZm=d^>{ij5=0SqQ$4!YsrY z$!HhTFQbkVVmn$(%Gm06Xuz^tZB$r?u*TASR5hPk3tziuM>jlU28+HMJky1V38xVD zcc>Og5g`rG&$AtCAA;v$P0rs5C`ft!#yY-hC0D@5C{o*av&go?k4}xDi@R#9hi>g6 zL>1wN6drbg{QIj3C=3NLFCk^lgrjAsh$^9GpT%;Hw04tgy~$KBdI(kr829$unR&b; z%ii`VV}w~q0e_ETcQbXj9X^|rf*2*gYj*wdPp}xap2o6WZ5gi!@wfN*-EXE?>jz)= z1=ctUPJKn_J5bW!p>=DFFUk5eWcfJ+Twfg-ZFgv0JIzV&96^yeIzPgzi5sa=I zxHfVICgRFDQj%jv)a?egsSu9lRT8c*@6@-Ql?g3JcG!V{MC>Y*9hgSdO`F(6KY!8TiAup&|mQn_!51CX&ab z9Ux|k+-AgeF5-8ZG3`^XtMXn!^Z6Apk(V;P;Oa&v1*yui`k0IXTnG8V@6R_57PAk1 zUA+zAvJEWBAHaWCDp#4esw=^Md+HgCO}>QSHNtrFkM;irtt&^Psao(@cz^c-!}Jrb zDV=`e^|g_(7dc5YH&Yr(=_j09!5}Zmx9`1T!MvxJVdHNeBN(NG*nm&xU0i-MaX34PJIeMN!HgO}@Hp*iDy!V?Dase-k zKn+ka>2!18tZO<$xw!sg@4?B{(#ki>b5Db`Wc@5-*<5Rx3B0hA7k=phv&id_xzuH- zFYmEYMHm>QW~3f>T8E(0q737y(vm2+{-L>aFzKaZl8u}7A~gPXFx!Y>T2Qo2R82NU z7~myTbn9mhWrs0Si~he%#Vi-VK&Zvo;4t;}M9I`G%>@Wj*x%7de>diCsYo-ZtNNTl zZUDbH#3>4K=In8?Z6%=k0V=Ltlvw6Yhd?ic!z!*tAQjbBmuv?wJI8kj6@*e#HAnAW zKtTW;OVR%{~IQDJN(F1l-F;qkkl)LvG5HQsKhsIuSjntL@mUq60hxtX$kc^)yqG$ z{qLuOO>twv(+uOY;nU}O{BGZ3*rEYlB>Rhx;RNv~QOK{0AIrN0)dTB4;&=c|xg@aR zO@IHCID%JI5yJD__cCZ=9fp|hOk^Nk@(QiV8UQ;|UtH-agO2qp+0B)q;raIvF?OEM1 znJfXG#5#uew{6=qlu=Y2W8JKeE8d`fOOiT6BXPc&v@f_-JKyWosN=WAB{80~Vvt4p zQhYe9n*Y-)dxK$=gC}9*w_Q%s?Zat=9{6kX>;EbnVP!kLLM=f$l zTdsBVAs!w9O0XZmcrFS{Xaf`t$Z6u3Vw}UCGT2LWj|Q2t@sJwd$3CSum3~Ptqy6zf zLo2We3u5yYqSgL^KTRn{27=I zcH_)s2w8y^SHccRRXwYY1e3%iN0lbuDkzndg zZ8jbm-*S@I?~r%bY2j3WW31ujQX^ByF6>F_>MW!N;27)M&(&jUrz=ApmE)?z?qiv7 z;ONWF&GN(Q|HB|lzJ&9x#hN>WxIqiO3qI6+SRMM-M%Ng7EZ$mwQC;&Ci5>&``uQ?@ z?HDhPu0E;>{&( zjw8qTz4(YbHWUv2*^rgiOtpdJw{SwQ_`)&^EzZ7CD=41O`j@}nJT~DtiQUK@Wvm;~ zvSJ|4;d;Fm53yo-SR=vJR||uGvX7ir$dh8_Ct2AQ#8VieHbBXZ^p)R;s1wtyntkOryl3-ZPA=x&Q6;hv$Hh4rF~~%!L)%q9g{48?h&9 z15IfMJv|97oG3mT4mYv?(LdGk&;O)Fl~x-SaHPd=6Y!~zxxmD8xyL--e%70#1pY6Ke`fvKr$@?srM)Wl)zyHDRKR)eHOlD@u z;ms<~aKD95eVl)hY*0bNH<_{#=T`{1DJ`H$Zn`h+8oCyraD;Lj1JO+2e#ku<_;+!n zb)U+|#Nl1YOcUZqrIj^3GCnAG(le)k&j!)n1~}_9jnFU9*9J6^ zjDpI_#1Zv|7r6*DfyCe%Ef|FUh}#N$qzk^A)ITr0sQakyPt}V%zSq^dzsQ3RKd(cA zqD`{afwjorlUuEEptw=v&>P>ZiR;q?YFd)W))ZCcib;hXi9J}#H@ht?rB9}>=$LgA zJu~kozUCDPqaXkw6G4Wxs^~KZbnOJCW7VMn@on$Wk=B2yJ6WH|0wc~%&0o8>Kk~8m zHKK%IMLxXz$Ex=--Rp=Nraa2@ipRBnzgDwXT{B4Fw=ZfvG*rIM%IDr!fTx6pl~c*l zdk;_66Ds^*RLg_7gNZRFIa=|Jvhf1S{bgM`NA5NZ65ND-V!wi8@@VOhkO87BB8vMT z99?l-wgeaee5Az_VA}%6PB-a{{FJ9IlMp{`t9qmFQDA(=&hmiZ=8xRh-F?e9x~rrD z-*Vx@pIK=3VBU>tUtiFm^tGkOR%m6i7cVcT?q}B_?iJukEM6=uz+_oJ>Et}ZSZ^s@ z`;g)DzODZapiCUz!gfKd%xUo@9mw)8CJ{Om9xf28_=@&HZ4o~8neL7+U8|$T<6eFa z5`U_y7aqO-8>dX)_rRh{)D3(@ZuQ;WcX!=e-=_Zf0WIhjv@uNf4l9J^GUT|%i&+o? zMd@%BQ$>{Z?#1aw36k>@_F$tn#)Wf;)*P>`u<4nGsw@rc(#yK;Z~xbNp6<7YdlHtw z(?kDKlL*IIP&15iWl7NT3_l%VnA$j=;vPueapVRI69d#IKSL~F>}NH(53=!Qs`NZj z6UhIm-#{O$8P0N0p1u{B86P)yQ?nJ~pi<>M1prYoP5S>xIs zapyzbO;>-dyQz#H_AhUw_tW-5(Rb*G=kwPtWTJIz#}bprf*s>rEqAM(ag3FI#q-yh z-$sC*OBed9^}u|NcH%F4iRyzkMO)QXf~cdFLA4exLRRLy=R-(K#@Rj!vLNc2{`rZ| zbRX64&v5kX_q9;P!tS}HVpur-4ILYwintNLQttWuW_%|F2?f5c8oiCN#f;J_qpKSLt=U^Kz6s_kCIC@UGB2 zteNitO(GA;DeMLVe!LK$Y4_8>8^u-2aa~Pf8y@$i+4X9 zC)K&taIU@>?oy-t^2F%8B9MBazHijUqJoL!06_QX;;nRjF2uk?C-Q6)>;rc9D}CS$ z9be^R0(J;zt3g&J=$<7# z+)(A4QW+@8Piiau?>uF?X>e?X?R2kzFX?#VgPOdW02Py;2B408x;pC-^%RbRBOPRSFaXR>en&2K%K~BBJ(5dx5O>haEKi@_Eng zzdOYz&WB-rj!AMT+nQ+1CC+5R!ZIHB1()Q!?*n@J@XvN1JNKF0^VJr30*h=!@GZFW z)SMYbxaf~#@cR3XtNDwHMOf$;C7&w!y+2UBU($~kW6WcC`a}TQCm_b5;$Yqb+84BR zfivE5hrO~X-|WkrRpwlCt2uqjM&dXII(51*JgT%OSt$rKy28=$lD5+!C+@UD#9VQ? zzUccu_SdbqLKML6f}3ef9sq$~G_qBZ!OkLH03x-aJa_82Al(Pye6$7pl3*NT(Eyov z6moy$SDvFoW=B%;ZNOFx8T*z}o=@Q28w!^6f;oa*I6 zE#EZ(sLXurH@<7O;yH_-4ten~-Wk!1jz5;bb=US!WNmr^z%t`rQ)&7vM5xrP~I*|+~Yvg|A_sBuCt1<4(P{m>6>Zbz*nhiMC8crw*J$3V; zk9K!{>H6+->YtoA1Y5~=Fg8GnyyI6tKf&XfdGfef_Z{E-R=qoLQCXl^(vpyJ&ndfU zuv{yXwT~}O>9h`qrghq~!5e29hmYt@bSoVTZKMrnnF}~goM98Z8tX7=fTKDcLQfj7 z%+fS?+UAXK>bn2r7rO2PALvQu{=Zv;r#LO#EX&UEZb(8r8)k2~7Gt%KL^3RDTKu z9I>w5SS~iv_Njr>^l#;xQm1Jb`u&X@-*r==#2h|>J&1HW;v^yH5uvTNeliuXOZS-%)0FItDkuT27MA$$Oq?FTGp zOvZZtrg3Ua(gEV_M29$q3#SrRg&2}VpkZ<`Z>|W6stccAeU%=Y{V%i|`R~=j+3hsI z4bNG;fqt)+RC9o*diZ8jk-`r++DVqS#-r<7q1Qr9^3Xs;oIqXP8Q`gxFeIpU?jHoll zeTiCrgC5kaJaHy?qGsexK)HvBPsGC~FE%kQ$Y)o>3y%Qzi>}d5h)_urrorTv2LS6rJ3`#47r`CR-Kt?Y&mpjpm3TaS^hFI}Sn zaBmgJuad2NDYvlFcUXZf@zO7=eO|*nX<+64!Ov@1q*-MNFp%<_3+W1pF>Y+-y~;82~sw zIh4LLGvVSfdq3(h3P93*WD^m{YBW2mjA(}fsLE({3bUy z`<8T)uWOa~fcWM-?#pj`+}f{xvjuDM6V>eFW_>BOCyyo1>aPh+2--_I#u>1*g^yj^ z-FU^l@fmzKB`lb=3%N-X>8G{B@W2&=geIxsUPtaDgVuwM#Fuhq*9n@u;)923Pn4ab zp{uV8-P~j3sl74aKG52n_=5BFX_J@C{9ON7hmznti9i;89*-yBsmcpK5|8%2Tf0L) z+Mg&Q3OmJkuhyN>hdnmjetZ9x`M>^6Z2&dF?-yqG4J`5{%Z~4jHTyN8=SOx8#yN~L zoto&8OjngTsJ3J16kJr@p3yy-X$pSGhJHx&q%l0!IAuj6kPX*e*LDBh-_;x3?=18R zp8TY;0#cmcfdvM!SLppVj!ba??BIZHjUVa;+Ad|4ifXn)bJT zNM~f~$V-9akn$#XKGA83K_{z?OLIHrE&2M#s#?r}lLQ+1L$Z^}WXVMG4e>FF@CN%Z zD2ym#$FgZBaiY%Gxd+0{Pe01bCssyxQzN>@&^(0~kDe9+?&t7;!0nnmKYT;?mfNID z;MV_Y&EY&eF$(1I^wpPDwy1pCxP17i?K;#S`Bqg-9I~ta;Ng{5_wQPiZ^rS{3Ttgv z*3+JzqJL|@(nyaFM_^87Jg4848 z{E@>N)D?UjA!v~1i@KBGLJ$H;ZjVSf(+n9Y4?ecAxyZuBgdiN}w*Sko=$FFYzQ@d` zH@KH^hw?7ESomDIwrh`kCB`83`afJjv2x*86IsQyEL|Zk3AWVSLt*lHgLoM_RzTnN z=`Mc11Tvsx`&Ovh30B2+=L~~b{I0yy!uOaK-+Y#km`G%A{Iu@O9SNO_o9p*!BH46< zea?$pJjNS0R*M6eJa*9$srPTFOa=xhCJ$tD1bXqU-8Glp6K+Sd-OeveP6GEo_<&>_ z>)xX9HeDLg9#N3B{3ZuK>U4qz&z0ZjNQN+RT>K|mnB5pizLel{CaUm(Y9UIL@ezN? z3%huvHxe!GHI4?N)U6jCV`9Fc3H|Nw((354?!$V@fgMv#is%1#Rl$J2P5%EEzt;b* z`Pbx=eS;+DMaPOfwE9}fD2aYSve%hgG#NLPLP*P<3MsvL9QN`U)eitvafhF%^5_c1 zr6SS9;Bic&VdR0wIKoxKR{6*?9kfZFQa!C`XecXLPB3xQMMWN<$s^t;5iQ>r`uo44 zM{vKSpW1wh9^1V^4}`y<-%5Y+Qqf|E=ok!`cp^l$;x%wA!h0k7cw6_1?_9}!tNPc~ zs`G#MB)xMY^}hFjbhi9#qd%;%`D(f89;Nw=3BPZ`M6v=5-fz^6yL&W1@wLU{n(U6A zDpzSq+p=keSqZisF@cui)cJK<Bj%yU%v=w?tv+w=V@nn_riK1_nlN}3RMCPYR$KVOlXAf2vFf~e2G85}w`%opOl9w` z*X04D=Y2%}v&-Q3Ik-5wngaUav5w6_MwitCvV# zET?>O1wB7ew?Wdi_9TsWh~E5;?&=pjue;~D z`7^y1Pz88}&?6@PV>}gx%u22&AV?z1H0Z$=((ppyLEmZeieq@1;$Qr8-PzNi$jan9 zzDuM0S-R=2M#BKW2kheUK;(*#frphWJ1SNXaidOI8Q&8MCm`IBNe{jJG}WWIxM@81uYGgBbN+cyrS#=?FXf|*zVOK69^N@ahE$Y zr8vLCF!M7YXyE4gUAT;`2;V;X^v9J@`A>YQz7Bb&CNbG}tqOI&2Jo0*MK_$;C%ttv zCK8=<98y6K$?y1i3K)<%(mE>ICu@@M{jAKx&zSO)w_`WeIih3&VKIY^!^ah~kcDw} zAN+Q^fj8`#@M57+%EaXNv77b#MlbB1`+}1@-UXso`C#97scSHatO0MH^OV^`*C<)`dI za27N-PG=G@h8&X;#-(BWh@1`oRG64}cCnzyjv=0}aWiPUI|kL##$&0hHXB}>lJn|# zjAUYPK@;zB*}xSOg*q++OjHawgDNW~7Q$>#$>*bp+_?ROj;`MG#|0@}gB&`tDxMB~ zOamW{AUb!lhk^aw@6)3wpDO$*P#%;_7_2()lf69QG&Iyg3Qe5pN2DMLzM_HY|Nc$g zQP;q`0wO%Dyc2cAa72S_eLkIOxq)5=cs%2ID3dr&KA(IEpwaRHJ%0b4Pnlf*X&nKa zuT|$w8rYR)^57FGPtgR%cecFJFYN6=cE{1yopOQ(%uN#yHt+^JU*&BbX_3!jAUaq> zBM(WOpb?v$GEaQ5L-1P6gseH@ZM_)#a0td>k3n3Bg3ZU6uv07*naRKtSj#xLt5QLhi< zc>jeLcI(Y4ZJ%EQTmd)4XFsd!&O3J{YrBM$1mNun;OOlm7whXdcg9cB{;sy$AG-G; z-TRf$BA-~L^FHT$=9o8mJ8(U(g0)%wghj`LaP9%9=@scuNkM z#ycDsG{PP_^_TnPHVXFyt;nEL&IUO!95Ka^ZOd``nQcx&E6s>-_ai;&oYTCfRyebWA3&9>)(!2IS|Qp%vGw;$0A)g!zf5 z?s<;v43wPDzHpu$J0ad5q3m}sh%18u_+jln=n%(M|NK@6H|ZHMU|s~0#gki6H}?IA z0Cq1-0Qft8LnW1wiG{~E$6iWfhsh4XH{Fk@ZJc)ch@uT>WU%Vyr9|X@MFR}}Y1NOO zT>HkCZ|P3|q33qbe)?162-7a&+h!|IEs=4>O&ZuP)%H&l(jx(fWIsEO6I7pL_c`X+ z!7(RCdawDR?moTOamB-j;>Xm^R8`U5D4HnZdvp)j0m#K~T)d-o^)>xbF!;Lt2Cn{> z>VG9`48KC8_MkSSqqC#We1?80`+@Eu9*DS2b$P*sI^ueZP881X?}-j^5x+$1zo8%8bJYPdbGm<6{^5-gS$tt`tFf&-q z1Ufz|&q=85a+~tPC$a(jJN$WukINb1V)hV5yhX=HSy!pC&yBGcRi@Q^va5x51j&r^$ww3pV zD9Qt}lOGA=YtRP@^5YRrf=9HwWZ|(gsBNhjzi_|lyI$6PRY%wSZVfM@QY^lvaD!BS zTvfNyBiX&MNMiD(@5BQv=uh=JYR(vq@U8l&<nG?2a$Xc69plcoED*iSukefipM7;na<%V>5e9lWaN=F zK(6WWDGFnipjtOW#-HDB_7#0hlm=_0Hl#;(BN|TDe7DrWdU|s zT-^MP2}Tu57;*T-&nn8mDu%}e`P%4HB*#Fbp3|`DRM%YJb-(jQ-J|)ferFR6NjhSc zi@ku$(x-<1-1uZ7iK7VF$wb13?|$<8REEPbalDS=Swa5Iua5ksIOsj{NYc z67Z72{g8TM;Dy3_G(fR~0jP(koFe`O3n2Iybne%riGC(f-Y03*DFX&?=*Q%Eyn9IZ zHlFa3v%6=$=*(dkLNWR6kd>S1N7csem9IHMxmP=bor8SDgmD5BhsrU0q;!EI+Th7* z3zVDkF_9BeA4~?CK)SP@rfNJCyI4N7$diRv>C)dSxZj+ny7Y|UXlCGyl z+DFvKNM07g0`EJ%U7wZL;)o--fBqY4`0wfKm-2)SGvs8M5tok#5P$rVBxO1%$ol5! zfWE#q^Qi~z7iwo>M2(x$p-Q3gMWZpVL->dT#yO1+F5?xCdoLOsSM)ny=oWAU!ss;Y zN?P>7oygHfan}(|92s~pfB`GEmP{hDC2pt_y3vV&n{*6fKmQlI?!0g7KSR#IwrRk+ z@|v#u!?){>-sk$KTS6vs0ofM1BzI`s!Uf=;48nUi!j1N4F556SA;3>*JxO#tr3D>3HEyb(-Z-9Ock&ID9Cvcxg%xI=;PEx(DeucPH1?A@$1VKs zJCn$oCnYz2epWk_p*<_Ar>j2nciz=K?>nE~z2v;p;yylKf_}cn-uOg66(ZGP+w(Qq zzxvhsu{8Pc-g|}I1<0;=i(K*!%eUFKx#DT-PtpYUJPo+t{sX-aF8P>jl%4nMLMCr} zU+|Hxd&W6B#yu@0^Fka=hw6-Y}UUhjdv@nXM&0j>{mRk!jFj zClUjF(uK;yFwOeW{*Vu0i6AO2bT5To3`(rDL_`RG&I~nE4u4n71EUp^J3_mXjc>u zRMc&Fg`<%ep~s}?-y`|lv-zX<=)oEJn1^WM*DA$?y)4vX7Yi?fW&(8|H_EBV1$=|} zr9AtgU&dRF7ch@Fb|_4aG-z@1QLXm)gz_PE&e@>G7`+7sdJq@(;B?6fV6*GWbErWf zj;w4uJn*NVWJx*69{aBYhc zGl{S};FB0UcfJu+?kI}%=K+=aAR~NK2|4Gi6$DSoto&Ac$~{L#`meNjy7rPK9kN7OS%KucA`6QM9*DmV1fAYZz@svpu&o^`h$WQD7PmpXTa@P;{ zMeb3Xd4dLCKF;@m26A?L>^cniJ02^?dGg)Y?xnAKaradX%CsO#5nTLJF+%p!p4RU|uD?#ZxGO+z z0kV0U$8u{;XFt2^zWddx$Jgne!3+D`+rO+&0=-p7wb#mK`7r}KG(VvR-jfGMvpoI8 zM8V6v*Wb{;`*HE7N*}=+Tyvq+;}kh0(I*Hi+4Ozv3|nbuic^p5LgHirdIac-b|L#i zMkPnsfiB+P3B=5QVc<;KrDT?!L*lIq*{yQz>7<=*3Dbh3b8R3Q6vq*ai3v5BOjZgs z6qtddRRk&(85y9rj*N${46>0=+RiL=J{pTv6SyqPwh$)yE5}Sl&Qt(B9}VQAS==bM zs6mwxMF@>ICOQZVk`YP%Q4Y!DBZeHUouHjg4QK7`5O`9N_f5to5LkK4lwU|hIy;j0 zsNZu>g!e=EnP4s-O@wW%9NAfTu&DJvSpvCgU?QQoD4GRya$Ou>alCb+CXARcB?Q0n zJ*}hi!xPvU3wQQenjo0u1sqo~h@lIe@#Gef1bH$^=oZ zrV61!mCupLw)g$*-|W8jYk#vlG|U0SKn z1_|Rqio@F3#RC;nc8v&qvL@lv<-1qBM)$q`Y(H_Zt7CBGBZ}|&J>3z1k8H)aw7&%W zyg~k&H3Kv|x2vwzqw;^E8zP_AyDsu2G&gH!8vd;6A&Hxgx@;Tx-Jc_b*7V|!zQwoz zBs_gIlKitC`8LXITJR+=?sb5l0?V1AnVYvn)*MlfVP;8K=$=wiTO9 zg04VW){qer!nRobTTYLj{x8~C)f8P2r|2H9k%U=qiN`|;%8Qi~gA`fvb*>#O)y`)T=Fytd7}8-r8@Syspkt87$tWnpt5fQ zFT#Q}(-X&6lt&k4nZ{wrR$C>X(}P&hVmk!#%h9g{#rVGvG@gCnITVUAVn=NC1rsY#y?+%{dNjZjA64 zpwkuGQsZ)1>|uw)oAoU~L;!LecL+|pqnvA*CaOZ{xDf1kMM82QK|Zux4it}@e)w38 z+rT;OAqLa}9OLAp9HDs|nlXFqQC_pwA?5%yCO%ie#aq=FdR+BNEwDTJhz7uq>xT8( zCs`oPaL>(3F)%ZFY9fdNE0_%`1m)%Cc|2OJ!S0Ca&=biWH}uDYXOwJEm2%>m+AKT(Ub2{_!!yz0BjP#~a`D5q(=%&ih+Gr=3|i zFy_DRS)xPagYq=>&AlIPsIyc3z=g^qvj)*|pM$UD9@a`fYN4iSr0EYQNd9S>IL`eu zdPMsbUH5G->31F{pC(zd&v2{!_`Wx)V$avatlghf_CVVs;g+E|Pr_Y&wI++}9-aTiCi+o47(-cVP#IXDxzO=*1s-dlZ}A{w3{T!cL#>-M{;u)1 zV+`;7zR&NaHpZ4#t_;A*(K+StFxCd+Y_3{noz6xaA~58ft}6KHlMZ!1srWy<>1*BfPZ*h$8C-7E1ag$s zIh-2&J9bLgPI?Kb?D3SH22nmi!^0iyO7PKbHJWBozhuz!{8_zt<9NxTA%{Qg8b-}fecy56-VE zOlMmhCv<$iEsY(>7_%C{)?mkCAaZDAO9um#!#icN@$lU)6mK21X2wUqT!a&N~e^UL$@4806!JHTcJQxBcxrLU1}l ziXVQWOcQX^o%+ha`@4>pJbAwcdw8q=A=M0GqTY)Rp4$7d*Y*zxy!Vf_Bhuu=ZX@31 z$o5U>bJi(m=%)CO=*7^V=wj!=y$t}LumB{DZf=x+9(nFbIn#fC2%^4<6Fc7Wrg7Do}hHx?Lth+v|M79EZVa;y_O4c%OT4|EF}-d3D<5 zbUoGiZL6yn2~A{SV`<~(gvj#6@Wcc_xF1mAR_=dnvX^`ulIiGRcGj3J@QCIJt6*$~ z-ZIGZWt>n0K&xwI5-FKA`H)tGiDPB*ATwWs0-?dn2FwT`0xkn~2*O{=^Fs$OI9H!B zVLz}3&(M7HJoV%JGT~GS_c)iuUVQqKyNfjr#}D(=to*k7Z@ou%@cW zlOtDMUZJLd-3KowaumaP9baKRS-X(0AzNwR4>?W8HR0bRj3cp|t`RLZ7{t?h$HUp3 z3K~B(%LF3YO+b6$mnAQ|K`*nNs}Ff^L>Fxv zd(>uECJ^yPJ60Yt0Bol1xqVXy_(SMDP@P1Ye=T3F5bv?=D^}~lUU1SCW;hMb7YfZ+ z$_Hw|)$z#O@jvTdDmL@EJPs`@(-_wd8O>(^0=KO^^TJPu-!HV}SchfTY2zJk$~PUM zX!*udOe72{Etlm+#6$zg&Y)G^(7B3Uf(&tVVw>z|6B)n4u$PF=tIi#rnGT3vIy4t{ zG4KMC!)g-q&d|!0H{y8;hNG+k7pPCaObh+9CC0yx&eK`k{N@uByot{JjgzI~WXa)$ zH}0EoL!D33+j7fmg_lYWpXz8%9x(93Sd%}^%dSy3WMf6I`slEq-N_PAfgaL;9s{%Z z+$@LlefbF=vddub1Q>B_%^5JnNpBj`GcG7l;F96=&{@m4F_c#Ap*Zrek z)KgC{&;nh~=YG&pX81}LpRNC%AJjRaCYv|^s_r#h+7nR!G1)X~=G3RD0$-+^RX@^o zFZwRs^Egv-tG0~~_}mLG1b*ft`q|_^>Yuiv9j$=MM_V7-xie`Ll}u+5B0m8CNanEX z2MKS^Z7{sE}XF|&`j&$J##j2U}l<(fpA!2OTg zHL!ETbt6E-M8bg1M54iS@_19(HSqf>ykdX9F5X+>jcRVFpRE;r+!HAyHIv7!H|xgv zZF>@E6Gz3*V+N-J4=Vk_kheJ8c`IXWh3q;mkr34J+JY5LMeeE#wk-rKvkFa2}z*Pa8Q}C(rF6N)m*PK9XN#@IO@-@og zxOh6LZtyj&A75nW z@*A3%m^>z*z+&Ryx82{bqmtP`J+eAy(8h1HwTAzMZG#FLzXhTKa5I=mgdc(8<;|GP zCF`c^HF#?<4iFu6dQ=lv{Dwo8N~xJRH1H2A*_^*coUa}8Ntp9A(DSJ1U8<4zL`y>! z?dPf5k@57@D_$)dW#@f5YT`HGPdi%^%=h-kR6qPP`r_>OX#t^$ci44R@>pbi>GRsr z{JMU>4auT29fzO9lnX=UxIIRUCV?*R-JnU2_{4venV!ml`c( zLuhkX$V&O>1axYA7{zg!6!J6{PZ|BvU+=oV@RMsd(^tf8lW@I7T}go7>nPvd8WjoM zZ@x>%Hg6myna;o=s+&%$>4nL>3OPb`YS)ub+37~=1G<9(9`Rp9 zgH8-QBf27Qj?5AMu!Ty``E@*}E923Bq#9^U!VZN_6z9Q;50zqq4Plg>vgJy)Elfm? zPsj-p(IP9_gvttTcq5!ntBViRee{ER3{!(1H<7t7!Y5Sr3v{+PPE*Ly8ep@X?y>9t zIs5;>=k$o^mFs!4F&gk=H-i5u5628PK+#cPqR?Owk2)86j&Q!AV;dd;KB`?wJnN7A z3^ha(9BF z?hM3B8nv zqBfHd@MU01*zqX*hQi0Q@u4RV%9#%OI&B$pGVhMiusAn29Myo#J1<_nP$`S-EQ0*B zl;uX{x?%}iSGHAgc0IB4p}cegE=6r`=nxGHsLQX=&C!ed>xyf1M52L`M^yn<;J%66 zV>bWCuS`~XvLK$*V^TP(IsfDO&XXp!eF24~43Zav7xlEMEs7_0ZK}igbPfLDSd2lG zfuhAPzs3uX+>4(k<(zJocb4yht3*^ zo^$0GC^fWAawFf3k;Xur!BkhQeB5xr8|rwn!z4qPX*Ed3gdyAGvj!rHPRt;_0OF;^ zEO!oXr6UHy(y56vxcMoWIBOO?_~@|MOI;P6e8llo?MU?74c#-edOi0!TEU*v$DgKM z3VHlqHFUg)IA>xQD+2yumCufa$9MnmgZcvNztw`CfqR#rm3t@K~;p^J|n6#e$eT#b~H>PEuf9@DUnyaMo%pK<^DcKi_Q~BD=*{t z=;395qHkEq@0Wk3zyFi-$Ko+*$lmCiBSbNQO!c4CZYh^v4vv1bv=5BfFrc#?#C=h} z0BOZ3&+rqorg44_sekf!4f~N<^E#bF;`K!tOtY*!2Q-1u;aZ(88&?`gOc*pI7Ye)^ zj|-(RH`J*|16NeIftnw=ZZL|+;EIl{69LwrEswBI)P=IenyBq z-%y-E-Xy_SakNnEilY}Om5w8t!UYYw2A#RwmE`z}ttJe9zvL+@A1@+u?8Ss~royw% z&^rqX`MrlzPwgKM=2I!uFOvk{K4N!s_dU8PtO4={?J{oCvClmWl;Yv$@Rh>x+ZzW0 zlufpGni%5~DHCOl7cSVn@RS;pPo~AE8g%13R!la#01d?aP7B|wn*9^9vgvjIVb}fm zU+N#hU1A3Jb-toHxI_N`{73cR!Ut6s*J*9V?yDSQt_|WUcl1Hpmh7Da8z&HzAr>(R z!^h}W7>g3pn}E8QOJ`Z|0E`2~(-jLZ%BPEmV1_ZrH1JV&((oSyAbVS=d7UO~UFb1> zJDpohASjxuGzM)}a3c^6W{SVXR|@G0U7J9PJQ^N@d0u_R?k4lA0mKmnJi^D|O1^D! zh#hqtx*DX@li*+^dkwHWPz%#e_1ZtKNxV59QS$AIDbPPIP79VTTb%sX7kj^Xf|`j(lJ7Cp3Zl&`;?G z`Ez@JW9Ar8PrPw|(K6l2|h!#4cdr&6Gu6en`;3u7{|+kn|P!n+PWtX z=?xgGmn;vP=F*vuvbrpelUDpFb*?arbe|r04r=FN`)r%jbHkd?=^PTTFXWqMuC6`0 z#sorU_TV1zUTi9#k%UIjpz&-c4FCWj07*naRM~3suvQAG%8lbER?X<)5>UxB_P_-~ z|E#|_$25Tlr+jenD5f1~9*4-vandb-h7MpkiZTgslohM|i3znO4xKU3H#0XQJt;CU z#J9c_VjKS92{Jl%Oj6hkNMB5N_|xSrzK#4%|Inj}IXYX>wTWdc|2Xz(mvEdx-nNVp z?*~sC)$S?YAz_!X30Qe@uY(CB)$=B{AzwW4Ymk~i<8$g{;H#wpA2;C0fKO80uxR?e zAJdDWukE_$y;Mh9r;iJ~@hZI^@;3cA*#)cbw2X6XmlJJ4gK_MFr$o4Z6~<1Og_FzX zyeWS2sEa9D*A-!orKQY_N^98ARCPF^;fxAwScQ zUJjZ-o-HY@3TWZ7g0Xz9JX^4@$pe9Q0+lM=A&-Gsc<(rd#s_@{XjJjuDTFLF)L327 z(2uWT_UQ)pIy)wkGbKj%TbBB+mNl8C4Qcli6Nx9(nt_!m zlZWn4Yy*e1YCWRkyKR3qHcuF1zIggG^%2BZ_FvCsA~{vQGu(cY-X#B^eiiUd{rA6& zKaf!EKL%u0>T`g$$e2O@P@5axOIg@oMpfmuNSyv@oWi)@QN|Qc4rCL@g!tkvY5K#q zyH5BwK`7lsG?HKQI-Nt}^@TXojELTVE)xh;b%oXGmZX}7^hhUUz}gp3P~=nDRIcR3 zpl7_pF(ovd#-JEmZ3YM+m&b93b$&23{+V83Od{?a#y41+DADg{7xJ(MJIWURQV_=x zgj#ts(Z>5G#b@|2c1q;6>M7fv0Fm`Iq68}+wO@q6r)i(QZI z$HdVVy1;27?rznkqo&26^2e|L-6c_T2h>^#JEb`wzw_l`eq#2e->)6XkE`l6;C)HQ zRhNBApEtQgM~573wq!MtEy59;+l1sqf12wn_|*1d;YXWPIuQX(Hl2EOcMx9wUKqY7Tn5j z>_FT=YWBrxJEt@Po*s&dZVh^KgiBuBFHpzx>YP>d3b>38$!x`KoAXIC$?1xxoJeOr z=r%wM^bLQGu`z)2q8p87m^{#1I;RJACXD8bkg{*^>Da(U8IU;waU|%x2|AMuA+!_z zVJE__Y&Gmq;CFKw~z&#Fr{qKk#9@vIIgpAceWUl@jCU4ow z0}s!AasM6%kLU8C$QUGH!N;|qw%^a#+TVm^e%$+%SO%2ijtY#14e=SWcySC&{eT$~|F`w(cCaV&~Oq@Xm8QhtNCU zyvxHKPat&W#$dj)38XlXuZ_mBlfqb0FBoLAk7($z!l0vKyBrz=FGQ}$9M8Cncia_X zI%F#D8|r~}9z1hE^sy5`c8eE0cB?FLWK|}>X!xEC3t#L)@R{t2-J8libl_r(C(;@} zWh%Pj7(ztD6JJvdT zK>Jw&_>h4Izp&#`dhK{N%bV-x%rg?-_{3GsC*ASbuJKAYkFS>4NZA2+@I`$&pO8EN zAE}?LEgbvYegbhnGEd3dNnn|@T`tntZyO!DOv)O@0hh;lmX$-|^@R+;bbV@@|J4M7 z2#m>4r*j_hoR0%YR}FtB6Nuy@dgu^kmBT={WU!NnJx~S2B%+XkGa8at8z|$-;Iu>M zWm;DXK9J0?Ez!q>m(mt7H)MwpKavDPX&9kW|7?HU>nUX$*lGt_JTXr4z zb3ZW0{;~RzAE}pUd$MC?SGbK$Q?^JKAC+7@7|Hhfvpp-n0y(9VGUR;PO$O5Wa$U4S z(XsGqLG0M^BW;UGWQ4B8I~(T(cP-d%%z(DGfzIc|EF343gt?Q>Y$>av3$qp5i|r#<~8N`%{B&~-YIMl|Qc z$3Rp=rm6Fmrg5SiIEb`Um&!4{2Tm%*F|Kn=j$Ml5NG3`wF+0>l__Uo7`es`R==ZnwwrDv0jrGE0Hk5QXsLo+46 z@U!?B79Q{bW3tEOweVvydJXOW<{_MWS(53Uu0#3~3j#vyr47MDf7t~fv*m}DZ1h5l zZsNcgugjIgo@3Yl%LHQMEWS<~KNfDF-)f+&bxB7wS}IYFixn0XyC3iXj0{}CiY-?V zcq)nV8FHl=507mz&i7@Y&pbtrS8lNbvTQ>5MIS!1%$%>h*m6T>U4))AphX`xZGf0W ze2m2no}p?y+d%m5T0or2j2qO5l<*0i@r#?H}SOO)HupF zR`#0KY5T+>{4S#x3Avo+b7;FA8o$3#_duR0i5O+WEO1lWbPh8;gM78(%ST0KSrk%m z>0n#wqo!fdUL+_HXJ<-wY|B+C%}FG&4gShy_FzxB9anTHccx9UB40XPrs$xiE%ptQ zjMBrF+qTn)pjSHVb|ZIw(lr_tKl%@IjoXZ|b%77guOlSimvAd( zf^G~{&Y-nFJXnv>Z^F9{7$Z_WY+{T2y1h|0+vB`k-W*2&>D@w_KoDFPXj8g2#`J`& zXcNT1u(ZP_{)oy+AxDmgr--btrrR

          hX~9M`x)vaGDnlLR;}%0>vE%b6OA^_iN06WTC?=x0|e0GG79L7DCZT*WWwckij**Ri< zphx)ljrPzpl5df;vlVlchzWiLY3dS|r@Ja_pRDzfwk*dTD(jH$!L`ax8)&uz%j&iD zvcVbexYMqul3tlSkYPH@8w*7je%bG$0r`|)<;#mq(6hkhF){YL&l9gN=!|omaCbmS z1SkO<_NnFn%}-brcJ_>)wOS6cbkP9fOuh`JnY08|yc-ga;ew}W3{L|?$J3@!^e;td=`d7@BEw-k?kOBcA9R>OF7)O>hIKeZP79DlW6uCBvc(&=BZHle@Pn_Q zw`}5LQ1s%jXj5}|YFU!O#J~%G@lHvx1+r*o?Cj7}bb((C6TH#Bi;qU@dP*U(Q@LX@ zqMzUs_&iv-45lsVm_(ohU)yO~@(pfdHLddijur>qiFm5L#{y=g8V0O&ZBjY(sM4jJKjX zZM;M0Q^~|>z;48*q0r#69_JC3{Ak?Ba3>c1FtAxq=G#SFI$|Y={4v1pa_ka=p6SFB z4ZoBt@=82>;f8MCw5sXBk~7&;Y~B}O+_R#2BOrQr^uUm*u?_{&CGou8-B60 zjqMEHIR+&<76E?LJ5;ML4fTaAkh+FJTk&BMv0)BFKuOpRx1XG6`W#x9ac;}-6Q_>@ zvNt|lNE@I}!KeHXuXu=2I?7<3t+2)++u%G2<0yFSy$_Q&Lu6nxA@*+r@Y;VAY%bV- z(>rZh;Egj)#r{53Cm_+ZLj zc(M%J>=1tPi|->Y+^`E%6B+DK8Hd3LxdIP9Yk0|YUQek1rMyx9=o3v08ie={I{@2O z=zC=K-?RlCJCKUxF`bnC!;zK!!fp~D(=EYGmA@`r@khOw7(`fJ=}+NrWKh@1mqD+8 z85gQdQ|hf&-%KOS^-3HWT*xrq@)Xiu;$)%3@ejvww5|Bsffoq2#quOBAmfe8A^F%b z7cxD3=Cz)=a-cJh%S-v^fca`#`Yj9V4AAB)=N(MkHBuC32RV*njG9VAGX+cr@F#VU z4+9KNRX!xqaEXB9s(}2J!KTXJZxY!QcMViw(Xpwx4A=^o$>|>3|F83$&gFB1DtR7U zhQY-7)|LH3ocyfY^yFbPdB`>`AvlN5hmQ$KJYfo*n0q6_#VQ}Rq{{ zwmm?X^%eb;H_Dpr+2hz48#@Zw$as(h_D4fU)Gs~&G9Be7?L6{l024mnK^yvydF*G> zl8cY=m36QaiQgq*^$%Y3F_4Qk%*b|t!#>xMq61_-AZa5AFu2Wx(1N60BFmsQ5Pp%3 z(Z*CJ?}np2VV~t@+3-8}lO*N>JMGX4>$LH6LU_46V=|G{@{|U(326NB2@V>*pWfNTG&jFAkQF=djjkBn zXuO-i%-N^raUN;%ohI&%WWLf-qO&V6z8h3%0>`9W1M=X{vTZYADPMHLB0p?!9C>9B z@gxFjxS20HRG>d5TH6ef%TnT=SV*qqxqRT^M>l|MbPIS?n=-^=A=5{${$*VS7Xyy- zcM)1gOaFf5BU@LjtgWZWq|7mBDouWTaRD53@((^5K6qLB(NVoP3D4kjXtUk;7+DIe zmt!2?Y>&1L4}Gfeg$T=0ILJmP^+X=m6d)_N5!ZLo5v;_q&w0qEEMykFOmM>@h%v-% zrq-X+#8cY#&zeBQx&|(@$FMbmgh+Z5b}wrC_b~HfwcPAm`!tukrk|%}2^Fm&0SYn1 zVai&IZbRb&`|VB~i5w~iAZ?R4_EKdH4H`Q5b;W9x)ypmcxmO$M1R&$1nBdVI2-dGJt(d9zNr;K5)bdxzK0-qs#hCBa~sK zBU+v_$3oL7bTkGB$|pp;<0JhHh74-1`!R7DA8lgC3kqzE$qYsKXTJ~vB}B4fCqS9i z#zC(@LEw|4dI>UoEgxkQ;(>=!w<~pFLC8o9;Y-VKSZIg)A*99UbPT#mN8LzPq@ii` zJ#^7`0OGVILN06}ZOHlHOiOz+z*8>zB=<@9sAznGhx>DsJwuTZ_kXNcILd;5h6N8Y zmx6g5F6FQ3nS|(PrT%g~4WzZMu{1I$JHCUarW5J_f!7xsDVK z0GB(JpqISmb0);t^k{{mvWZ+4bhZ+Opo#KlrjeoY3Bu^ zkv4v}VX0Xw&y@+zg=yh!i0PcJ!%g`$J&y5BcX)A*8dAJSM~73I#^6=zit}q(3(^c0 zyx2tJj0R7ceJzkPN=jLP?8_e0|F83%CO60N4*<@x9LHDS=ysHrg#?QF=<5m zm0y_*_<4c=>GEJXh{N|7;z4-Gm=VFxy27W#w*W67ngcL)(H;qF`PdB(-w{INOVNlE zW^g-$4n78d%eIe-jAIWf4|-q1$Kr!EF%ymWV{*1`p+>^I2yJqWf zIAy>6W1Gz5(D;K3Q>(O68{7(Q2(;wSg{Aamr4ej$a5Q4+izhVHVEJ9|T>}$SyhO)S zA8!1+R)ReHnRv^GDW6F#I)Q1OXFjLN2f*hJYaHPiz+*XfQmLI zW{n-uu4?%`$M}Ef(LxE4}^{*hw|q%aV~>(IIWQSTWLEfZ!&7Rr7mJ;Y}_Q{g3MYTY0Ax2??w>o ze22!_$KZ))-$C=pfO?t@Kp}AegA8N&84qopHh&$?rIQWO2OQT&T9mdKBrx(uc&PyDi^LVkcLo`4z( zpA1xfI0b#4Jjl-VOL_w^hz1MtYOvl`UQJ8CFn!L;yySbJH;v0dn*2I#I^<`74xHti zm%^Af%K}&H7Ao2SJeH&AY;buA9iPp-1)3-aAKbN+tglABle*s)R%Du<7?VxnPEz!t7ekbSU;w#tt|2U{e= zpPYvzY{do*NK7C>MQgU*k9J+QF?*iHEy636$(F&Hidc&EU+#%Pr9 z)%?&G;o$;o8=)`fk)PvrJIZo0E%@4Q(^{Ts2$4(Js*hTZ$mRfL4OYvZ!!(D+_K(pr zIRN&R=}B{yqkTxC%;cM9%d&>7?f<162!_~*R(#CROgq<*IXr3*`?>kI(G*oyn4zPS zxc5N=bonFJVgU?+Hr>v9W>kII5L%YTrbBlP;S!> zVxZRwAKqp=Kt}~J$QR$lPD8rm3&<56M^X$fNBBA5a+JWm2DdrmC|fK{;CI>RZupc- zGO#TMD$<;PLsw)f)(?*46}wg@njjeew|4JioV3rejp#Fg<5ItgY$ghhSW-WV3=h(l zA(Ebfh`@M<85acQUn?Jfpf~HpMqjMT;iEl4XZwW%r{;G8!WCNZ<3mQxWAE4&InD@o&! z+*pNDJT)43>bP;K4iGoXMaN)(u2^-rbI(%JAfhY=`_JiZLgd*$j<@8X%bkmS*OO^m zwq#pdbVXl~>0b=OEgtjE4Ur*RW6;EA0301V%U3+=41A%-1_t(kR+&oH5Fk$j0{2y7 zCu`n;U@w9$w-M-L)eV2`OIWZ+*TZEXJ))n>^;e7^)=PiUo|I>Kp#?eUFJXu+16Q=g zbn}!QOALmD2I5Y`oM8-~X_mw-51ueo<@2DL?QooaV;+ar=d?rcIbPE_?GRe7V#jby zm3@GI+s6c8KPx(bWQ1DsGfF zrE~C6Gjj{18#;E|7la1KU8X!Z)_LZcs$0|4p*xfPSLbh&#tu5IZAXS}CT<{Keu&8( zoYFCYfS(C57>kxVj$HzSzM<$3nf717na`vvA+*><9qD@b?vhIxbg}DLo9K#M^22=n zi_m(D2!gQF^`8CWx&Q|=11AuI6dE7Ml6HK*q3uAI?Z`5nZyR#jbjCSN*uv#}^tpWC z(T&fn2ORZ)F9^X?$IyU-p0>sWo#iMQVEs(^@U+TSNEZiVzM2wbdvfTw`AF9|=e0u9 zw#wh4Uxq8K5G5#Zh>#p74H#F4eePcVSlakHv^?1mKdV~j&rPcV#F;b4AIJpiu;5l! zh-y4cJaKNmjia~W3FE4NwiUB!%%t66AWiusSMqBcOiM_fL-P@4$oVZOAFbj0SU|vObdNG=R5_E>ot>bdEdB@{Jn{U9ORG z4wFaSPw<`XCG>=AJ+{GN{ZNDH=7zQtdLKuk*EY1|ST}h&UZ=_PMV_JNF}@W-n{8~- zEXUPem4vLwafc{y++oJm@m3mK3nXt}y8y|I0Va34mYx=lN_GRybtub0As`!lA7j`x%8tm^zbJys(Q_>N z?@5{+194AKqe7rzMT-Hnv#i@T!_4uN%bAX+R_LJ{1LPvlA@M99zT9R>yDOUyT(*z& z6x8xdI(AybDX-h4<(Mb?!Z_39a4Ij;u2 zgxKJ8wu`v^LmV1H(D=l>fp80M#alQ88}BgVhyyvV z$29-1>T4aO;qfsK3`IzXQD1Cjn^{m_uE zX`Oa{Vqb~Y`852(i%oItXPc}i>t7MJo|s)P(!rqa_d$>p>U0zpgS^WlWZXl5ptc>{ z2Jpl&kXi14ND&R5(LOXG47(`nG#^IdAJSY)+mcv-p-hTLTTr=I`X)pGI;_tV8#c_< zYrByJjHQ`4+!lf}`|1Dy7mrCqK~zjb=%XRx#w)r8Q+aE|BM8bh1?0Qz=(Ek{AXW`3P{j z4twFN|4p-sT~9#=Y*D~iMY@snQda*X)ACny_Er#E=&eOH(_?yTV(453Y@y>$L2d6Q zJ$3#Vzv*m)(mn<{#HVDO@36Mfa><962}qqN-asGY5h;VGU$|QnsRthLO*}m#`7zL< z2l=`}Wl7IzKha*Wg$q9ODmp-w7w>hD3Ep5nLh4K5*2kfiS;7$QRk+(lMKeqo)xgC4 zm^EK!yOC3;6YdzFiN^rI6G)%xeMNkN-=zBrk#8F;sD%qhiNN;MJmz)SlHt5fA+lX3 zwI1uwGV+98=R55XKH|P|nmCYYd(86xmQmZkOj0Qs!YpW0-1&3EY>;^}F2|M6Te?S1 z5^@u5<|7V0LEgH$Onuhgf8z^}2Mz|for2|03H6|WO}b*m318;5y;E|Q<{=-sS&wC8 zedK$^R_Np9Mt2I~hI4-S@gY2A;-fy|Xi{O64Vp19U)EpIQb&A9kAaO(p~n+6nsoe7 z1bV$oS+UD9tMUe#f5tnmbhIVPp}`{B26?4iitT}MmZ2P%b+BuXdRa{6b-P??+m=H6 z$@=ksN#i3PB#BAH^n}UI0c{-RmdtqaiV4ZG2g1Zp9zL~y$j*@L%;+I*deaRV zjR-WRZ)A_6+{OvbKUZHCYMvYtcN*GOI?LE^9QiK8a#);xWjPzaK!>805|d4YY-x!G?h*%D|vl%OO2ccIB=^ zEu+PsX>z{t4v|irG62M}6CRon$2tsT1&1$Vup>`A&9~{5H2`vouHYk{?HLGrJUb8Q z2EU<~6`^>TG#GHPXP8J_@5&1``WJNQC^%0x5h_1E=dSFa=jaUDNGQyZal}OzAN|ZU z`;3QgImQ|T+dxP?BwIlpX9C1O8O)P$#D(Vt$SfmBYI@T6U3Jm)OE5i(|7d&of@=yW z2mYD^(Akem$BLH!&}lrOFXMCCIKo|nZJ6taJ^gsO079~WoUY@rnAUll!lEVu(`HI1+5&9TN&^M;qpiP`p9=Cl$H<-EnwR|RB>|z22$j>x& z+BAd*3FxiMHm&bacj#%^@`ivcu#VShlo>Y`)&`lb#ur)q9(Qi|oWuKB`(bd%ykqic zOk4)&>@eb7s?^wtq&x=0SiON;0+tOAal2V^Vt_6BhDpQuQ#x8Ua9>~!ZfKvQMvE`wivMB^DT|B9-XyEeciN8)lQz!roJNV$q3{v-=dx~A zCg*McGjYIMuaSX2}{hsgvw+vZTH0P1;Upl8({$4444hFw)* z8x1U9gK_MJ@?bN{G@TJgcHV{5q}FGAoz8gWk$v=j`HVKLa>veB{)zh}uIJ3-_*e)J z{^i;wU}!CKtZe9=%G;G)*h5=ESIfRyPi>Ra=EZjzM?9yI=QQz03eZ{mzO8%a$e0Dz zaSKMF^TtAG$urbO<~(Rhe*F5Fc{YXCo%o~DZJ!&!m>hM~IFf;m!3B99WNLfIWO(us zeGELvU?8EvxWj?tS_(A}t1Gs|b8SOkEu+TO`J^+>aYE~LXj!H)p0sh$7*E_#8KQ{^1ln>jal{0ZR(+eCNT2Bo7Obo zXM&%88|>U9V=O=62btI)eC)PLe5P4F8SQ!IFtSMQE{N-$$1Y^zLoUXLDM-E!GN;(^xsG+f0*jExES0l?M(R0q86<5F`IG zO^#=BY$DHL&U0M(+;@lxWJJ!e6D_isEQWy|Ig%fb(OQ>f6I$k!4VhkXzNHnv$6eQ* zWmWW%#DAsU!@h~Gw!+?$nFqpF{)zx4=Fq@1m#&td(=I2n=9V$@x8lge*K=U13@qAm z-?O|0b#Imku?v0JMu?mi)HXTo&~ixU3t6VA#4z&{!! zoh<`8Hcn@hD%m)hE+qCxYTa7f%Vnt1Bib z4G_bF58QV!9{a@;6N+s>&KTI9R({d9R*$vqmSK7ZFX;{&pmlyr2e^jM!(W^Dvb-g< znQy;w^p^65DAKimrgY?f0xwstH_}UCSCfbJW*Z#OWi+m)H=YoiTvpOKujX_5u@GWs zE^BYoj0pt7nmMO)Jkx@&A$OuWo@r~DId4-Oxp`2`dN%R4@?F^qU8H!g?o+$@Z<*L=J=Q%(1N^qvvPc6?_o==A##`TBPS_Bi;+G9^a~4|Jmfwqr z-}%UO0!>R6tULv!E1t@-UhFfy^zcJRu?rEJdiSHa@njaC>KA?B%mdvNSdVFx9?D{z z!$6b(S0X$op~kbO6sX@s!$9ck(?k25VA#2HUWIa_5lO{ORQSOe@_t<%P1yi-Q6 zGS|XZ)0x)su@Ifk%lccmoZpJW!$sw;7r4c-8AoG5mMfY;+G+1ZoQH1b*?#9KYbP)! z54+rPJ@8C*K+e`}FNS5g#=8vU*8sip83+&YxHb9<9|Is4k6{N0PdauGwyk8X1S9(R z-3>!LRH1Tlv=~nhxjx|KQYR&E_*FvTVwYk83qs^D3B@rcd@8diq&T7)lZ8#T%QU1Z zJA(+ogqQ0_dBdV)%11r-`u|*i>$%gI5x-9}jpQPWvbt=gokY1Q7kQ>3O`P3u3;dYy zSlL>5aAWeUqs8aE9FEaZHp)R=x}5N3ddCSVC*ueq>71uzfN@SgR>QrvvTy>SKzq!6 z@ut!_&+)OaC3_6lYaahk#WJv4*Er>Ljw_T(cg0V09Bi)bnXAQ(9DlT6&du4D4`oLT zeDd+=kAJoJWJ63Mda-R1YTi=rBc~!jeU`^iRVI$ByyJ=bp`6&p&VvbzZ$a_hF3WQ` zsk~$sosl9Aufo{busBhg$#9rhg0T7r4>r+ufFdIX56dKJ|X!%V|Qu zynX7i|DQ7Ag|!z6=bGLN=&5tO7rQ4V=Q%zW*1VQtdZ))i=%@&HO7l4!{cwq{<@#-JEr}8o_c0o%B5cfqITP(}? zoQ4K4u1|gQ{6Dmx=k6$Ub{xfSrE9wEbmuulMvjvPTDU%E{Xde&J@pzvd2Io+v>VmY8EoG zoTdEG!_RJ+HisQ~LMB}w#R|0sb8VPI2TiU|+A?V_LvG*D`yxN<$Z_+2vxLX@GlAF< z*=abVmCks_$3n{`tYv`%GQP+3|B<-~YML=wS&okwYTit!2>V{oqUeJ%tg*2)J*z6XIqx)!u}OGowb)v($W9+BAO$s^?1jy2(1B9JG$ z;@GOhH%c;Ht2`T-A43G${$2Z(VrKbc#rC2H{Tz?6<1nAY7VlJErk_JMMMIt^4&tV* zAsoLlp|k{wC(8Lbd%gR&Gq>lx=cg7?oS>g$TMvnUuu`>ADbc5_znOk zl};Se?7S(QdFl`W#?|o3uu$q4k&n{^;>2Kv5=g{quv@dLQejV=8{zp&NHlyu`wK%A5I5m#6 zanL$Wm?7tZH(jPNo-pejqpf*c>1;=q*;;Y8_*=Lvvz4E5OK3CSocIo9Pu`er*)paZ zJbrfPTfz$~%~$*pdNYkI$z?Y(JjPqgZP}A?wrhkBx%hzJtyzIABWH}^GtIYB{LwD& z68)QK>-?N{oNz2oz2>}crF!lU5_ec4J1P&pQ#h+OJ+#E@5W1Ee@PO%wGk`F#5PDEi zbTL>Tasa3MRR7<08`q+7UL7u>t$FJ-vT9pQvqaAvIp~@4Yb|3;zwq&5UB1DbZFV~_ zE{D0SipPt7nDtctDXrs;#gm-n+ulYw&=WW8^|aUH@EG-g>u(q4)v|Khal$&D)3(Dn zr@uAAsgYnGC2TpX#yL&s3zZq~v~f-o)?gWg9+YaDZPIzLs`<0dY-3GFdI@cde<{xT zw&AOJTsDO~>9lt5qNXRkNx$+LjJKNjESu)b1R^=S?H-Q^bA07TKA~FzHGNJ?N7(BH z#ay{r#$2Aq>9+I09A85-mo8gj9`jFy@R`1jXPMvp@dKJb#++uS+i`ZX@j0wznAUjH zT9!jPI7d!QB1=2FWjNechHcBCWgb*$|5)dK^jH=$EU)0Wzp&^L)-gLIZ@)LZ*=fY? z!;`#Z`YrL8n2aB@VGh2On@31vVp?+QYu-6}9;bO^J>a^j+X#5)VNp&SpTn`ZOXGZ} zzqP_8y@*x+4>GO< z<1>xprm>tH)&owKV>P ze!fw~6G?F++q_dDI~dW&C)qPyOP_JIoz#nQVT@$z{seEgQ*XmlSXus5+{@E&Tz-C`Hgqze5W0Pcidr3 z>vRsGWg_v)H|OOz6OJd2jDM`gTaA^nw(xZsYX6ZxhfieO2Z>LH6raZ6?H!5rSe8QH z*d}DKpQ~q}t8J~*=q&nTM~XQ@>euVFJ)x5|B%+ROC|I;qiW@hcO=E@w`_IS=gdLY-2{eG?#yL)2&fgTz`B{eJtDjxpFdINZ@+Q)>f?+gNx&pLr}N zGv@q^e>}ch4~+SF3~%kucW6AJajh`pa=gW#ao_s!M|lFVgIk@^c^)X7HmyVOWAQrA zGFoAl(aL|caBi>%q2IEn%07n%+blyNH?iZ$svKzz_YEwoRhFD*SuMJZD?C0<8wLT> zAV)Oh$7kKKC+mTZbk^sILtok@FD60q(`2Yr51Fr)YnsQy-FRS*f5&KAc;g&mrQ?KS z@l038N&o4B$H)YN({pF6E5UhnSo1l*#<$Y7jyj!X)p-YTE48I{leDqWEwGQzQ zgH4_HczQP;$aOs>v8Joj<^`Ygh*OVVB;@=Yhri|n_oo*gLlcNAfr=ah=hY$fQ@AY8 zbQw1lUrIkEYb-A}$}yU4@Rpm)U|dTcber;9d}BE4C3NRB4xVjvjq!M=YCSERpn;#O zlr<(1KUu}`8#nlug5@pcdz^l=2gd5V=B(-JH1rwgcn-(nW4yHufBMpo!3o5bkO!Lo zznybYQ6P$8=>Pw<#^Fea?Y;E{f-|tTP1Cf~>jQUT!DJIx42Dgfx4Ulo7!;$StNzc9hUIB>=CW!=Aq_a_N89VWcH=u6(Uz}zO^ zbD#8geLTOLc`}#uDjoWCdDn*PSmnFcq{jKuV@}~-Z@luq>Q=K*CAuBcb%cWOY$@MCaqNfgk<=@gw5!ctcQ5SjNf#iO>u&{TF O0000 + configurations."$variant".outgoing { + capability("$group:${base.archivesName.get()}:$version") + capability("$group:$mod_id-${project.name}-${minecraft_version}:$version") + capability("$group:$mod_id:$version") + } + publishing.publications.configureEach { + suppressPomMetadataWarningsFor(variant) + } +} + +sourcesJar { + from(rootProject.file('LICENSE')) { + rename { "${it}_${mod_name}" } + } +} + +jar { + from(rootProject.file('LICENSE')) { + rename { "${it}_${mod_name}" } + } + + manifest { + attributes([ + 'Specification-Title' : mod_name, + 'Specification-Vendor' : mod_author, + 'Specification-Version' : project.jar.archiveVersion, + 'Implementation-Title' : project.name, + 'Implementation-Version': project.jar.archiveVersion, + 'Implementation-Vendor' : mod_author, + 'Built-On-Minecraft' : minecraft_version + ]) + } +} + +processResources { + var expandProps = [ + 'version' : version, + 'group' : project.group, //Else we target the task's group. + 'minecraft_version' : minecraft_version, + 'minecraft_version_range' : minecraft_version_range, + 'fabric_version' : fabric_version, + 'fabric_loader_version' : fabric_loader_version, + 'mod_name' : mod_name, + 'mod_author' : mod_author, + 'mod_id' : mod_id, + 'license' : license, + 'description' : project.description, + 'neoforge_version' : neoforge_version, + 'neoforge_loader_version_range': neoforge_loader_version_range, + 'neoforge_version_range' : neoforge_version_range, + "forge_version" : forge_version, + "forge_loader_version_range" : forge_loader_version_range, + "forge_version_range" : forge_version_range, + 'credits' : credits, + 'java_version' : java_version + ] + + filesMatching(['pack.mcmeta', 'fabric.mod.json', 'META-INF/mods.toml', 'META-INF/neoforge.mods.toml', '*.mixins.json']) { + expand expandProps + } + inputs.properties(expandProps) +} + +publishing { + publications { + register('mavenJava', MavenPublication) { + artifactId base.archivesName.get() + from components.java + } + } + repositories { + maven { + url System.getenv('local_maven_url') + } + } +} diff --git a/buildSrc/src/main/groovy/bluelib-loader.gradle b/buildSrc/src/main/groovy/bluelib-loader.gradle new file mode 100644 index 00000000..cceaf529 --- /dev/null +++ b/buildSrc/src/main/groovy/bluelib-loader.gradle @@ -0,0 +1,44 @@ +plugins { + id 'bluelib-common' +} + +configurations { + commonJava{ + canBeResolved = true + } + commonResources{ + canBeResolved = true + } +} + +dependencies { + compileOnly(project(':common')) { + capabilities { + requireCapability "$group:$mod_id" + } + } + commonJava project(path: ':common', configuration: 'commonJava') + commonResources project(path: ':common', configuration: 'commonResources') +} + +tasks.named('compileJava', JavaCompile) { + dependsOn(configurations.commonJava) + source(configurations.commonJava) +} + +processResources { + dependsOn(configurations.commonResources) + from(configurations.commonResources) +} + +tasks.named('javadoc', Javadoc).configure { + dependsOn(configurations.commonJava) + source(configurations.commonJava) +} + +tasks.named('sourcesJar', Jar) { + dependsOn(configurations.commonJava) + from(configurations.commonJava) + dependsOn(configurations.commonResources) + from(configurations.commonResources) +} diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 00000000..6b1daf45 --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,41 @@ +plugins { + id 'bluelib-common' + id 'net.neoforged.moddev' +} + +neoForge { + neoFormVersion = neo_form_version + // Automatically enable AccessTransformers if the file exists + def at = file('src/main/resources/META-INF/accesstransformer.cfg') + if (at.exists()) { + accessTransformers.add(at.absolutePath) + } + parchment { + minecraftVersion = parchment_minecraft + mappingsVersion = parchment_version + } +} + +dependencies { + compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5' + // fabric and neoforge both bundle mixinextras, so it is safe to use it in common + compileOnly group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.3.5' + annotationProcessor group: 'io.github.llamalad7', name: 'mixinextras-common', version: '0.3.5' +} + +configurations { + commonJava { + canBeResolved = false + canBeConsumed = true + } + commonResources { + canBeResolved = false + canBeConsumed = true + } +} + +artifacts { + commonJava sourceSets.main.java.sourceDirectories.singleFile + commonResources sourceSets.main.resources.sourceDirectories.singleFile +} + diff --git a/common/src/main/java/software/bluelib/BlueLibCommon.java b/common/src/main/java/software/bluelib/BlueLibCommon.java new file mode 100644 index 00000000..e0a9bf2b --- /dev/null +++ b/common/src/main/java/software/bluelib/BlueLibCommon.java @@ -0,0 +1,59 @@ +package software.bluelib; + + +import software.bluelib.interfaces.platform.IPlatformHelper; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; + +import java.util.ServiceLoader; +import java.util.concurrent.TimeUnit; + +import static software.bluelib.BlueLibConstants.SCHEDULER; + +public class BlueLibCommon { + + public static final IPlatformHelper PLATFORM = load(IPlatformHelper.class); + + public static T load(Class clazz) { + + return ServiceLoader.load(clazz) + .findFirst() + .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); + } + + public static void init() { + if (isDeveloperMode()) { + SCHEDULER.schedule(() -> { + BaseLogger.logBlueLib("**************************************************"); + BaseLogger.logBlueLib(" "); + BaseLogger.logBlueLib(" Thank you for using BlueLib! "); + BaseLogger.logBlueLib(" We appreciate your support. "); + BaseLogger.logBlueLib(" "); + BaseLogger.logBlueLib("**************************************************"); + SCHEDULER.shutdown(); + }, 3, TimeUnit.SECONDS); + } + } + + /** + * A {@code static} {@link Boolean} that checks if the mod is running in developer mode. + *

          + * Developer mode is active when the mod is not running in a production environment. + *

          + * + * @return {@code true} if running in developer mode, {@code false} otherwise. + * @author MeAlam + * @Co-author Dan + * @since 1.0.0 + */ + static boolean isDeveloperMode() { + boolean isDevMode = PLATFORM.isDevelopmentEnvironment(); + if (isDevMode) { + BaseLogger.log(BaseLogLevel.INFO ,"Running in Developer mode.", true); + } else { + BaseLogger.log(BaseLogLevel.INFO ,"Running in Production mode.", true); + } + return isDevMode; + } + +} \ No newline at end of file diff --git a/common/src/main/java/software/bluelib/BlueLibConstants.java b/common/src/main/java/software/bluelib/BlueLibConstants.java new file mode 100644 index 00000000..ead38611 --- /dev/null +++ b/common/src/main/java/software/bluelib/BlueLibConstants.java @@ -0,0 +1,27 @@ +package software.bluelib; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +public class BlueLibConstants { + + /** + * A {@code public static final} {@link ScheduledExecutorService} used to schedule tasks, such as printing messages after a delay. + *

          + * This executor runs tasks on a single thread to ensure delayed tasks run in a separate thread from the main thread. + *

          + * @Co-author MeAlam, Dan + * @since 1.0.0 + */ + public static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1); + + /** + * A {@code public static final} {@link String} representing the Mod ID for the {@code BlueLib} mod. + *

          This serves as a unique identifier for the mod.

          + * @Co-author MeAlam, Dan + * @since 1.0.0 + */ + public static final String MOD_ID = "bluelib"; + + public static final String MOD_NAME = "BlueLib"; +} \ No newline at end of file diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/entity/variant/VariantLoader.java rename to common/src/main/java/software/bluelib/entity/variant/VariantLoader.java diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/entity/variant/VariantParameter.java rename to common/src/main/java/software/bluelib/entity/variant/VariantParameter.java diff --git a/NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java rename to common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java diff --git a/NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java b/common/src/main/java/software/bluelib/event/ReloadEventHandler.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/event/ReloadEventHandler.java rename to common/src/main/java/software/bluelib/event/ReloadEventHandler.java diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java b/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java rename to common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java diff --git a/common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java b/common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java new file mode 100644 index 00000000..be1187e7 --- /dev/null +++ b/common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java @@ -0,0 +1,36 @@ +package software.bluelib.interfaces.platform; + +public interface IPlatformHelper { + + /** + * Gets the name of the current platform + * + * @return The name of the current platform. + */ + String getPlatformName(); + + /** + * Checks if a mod with the given id is loaded. + * + * @param modId The mod to check if it is loaded. + * @return True if the mod is loaded, false otherwise. + */ + boolean isModLoaded(String modId); + + /** + * Check if the game is currently in a development environment. + * + * @return True if in a development environment, false otherwise. + */ + boolean isDevelopmentEnvironment(); + + /** + * Gets the name of the environment type as a string. + * + * @return The name of the environment type. + */ + default String getEnvironmentName() { + + return isDevelopmentEnvironment() ? "development" : "production"; + } +} \ No newline at end of file diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java b/common/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java rename to common/src/main/java/software/bluelib/interfaces/variant/IVariantAccessor.java diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java b/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java rename to common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java diff --git a/NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java rename to common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONLoader.java b/common/src/main/java/software/bluelib/json/JSONLoader.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/json/JSONLoader.java rename to common/src/main/java/software/bluelib/json/JSONLoader.java diff --git a/NeoForge/src/main/java/software/bluelib/json/JSONMerger.java b/common/src/main/java/software/bluelib/json/JSONMerger.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/json/JSONMerger.java rename to common/src/main/java/software/bluelib/json/JSONMerger.java diff --git a/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java b/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java rename to common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java index ca1dfd26..d70b0364 100644 --- a/NeoForge/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java +++ b/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java @@ -3,11 +3,11 @@ package software.bluelib.mixin.variant; import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; diff --git a/NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java b/common/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java rename to common/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java diff --git a/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java b/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java rename to common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java index c20bad2b..0d6f3707 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java +++ b/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java @@ -2,13 +2,13 @@ package software.bluelib.utils.conversion; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; + import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; -import software.bluelib.utils.logging.BaseLogLevel; -import software.bluelib.utils.logging.BaseLogger; - /** * A {@code class} providing methods for common unit and date conversions. *

          diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java rename to common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java similarity index 87% rename from NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java rename to common/src/main/java/software/bluelib/utils/logging/BaseLogger.java index fcc6e141..d6a4a6f6 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -2,23 +2,24 @@ package software.bluelib.utils.logging; +import software.bluelib.BlueLibConstants; + import java.util.logging.Level; import java.util.logging.Logger; -import software.bluelib.BlueLib; /** * A {@code public class} responsible for logging messages - * with various logging levels and configurations for {@link BlueLib}. + * with various logging levels and configurations for {@code BlueLib}. *

          * Key Methods: *

            - *
          • {@link #setBlueLibLoggingEnabled(boolean)} - Enables or disables {@link BlueLib} specific logging.
          • - *
          • {@link #isBlueLibLoggingEnabled()} - Checks if {@link BlueLib} logging is enabled.
          • + *
          • {@link #setBlueLibLoggingEnabled(boolean)} - Enables or disables {@code BlueLib} specific logging.
          • + *
          • {@link #isBlueLibLoggingEnabled()} - Checks if {@code BlueLib} logging is enabled.
          • *
          • {@link #log(Level, String, Throwable, boolean)} - Logs a message with an associated {@link Throwable}.
          • *
          • {@link #log(Level, String, boolean)} - Logs a message with a specified logging level.
          • *
          • {@link #log(Level, String, Throwable)} - Logs a message with an associated {@link Throwable}, if logging is enabled.
          • *
          • {@link #log(Level, String)} - Logs a message with a specified logging level, if logging is enabled.
          • - *
          • {@link #logBlueLib(String)} - Logs a {@link BlueLib} specific message.
          • + *
          • {@link #logBlueLib(String)} - Logs a {@code BlueLib} specific message.
          • *
          * * @author MeAlam @@ -32,7 +33,7 @@ public class BaseLogger { * @Co-author MeAlam * @since 1.0.0 */ - private static final Logger logger = Logger.getLogger(BaseLogger.class.getName()); + private static final Logger logger = Logger.getLogger(BlueLibConstants.MOD_NAME); //FIXME: Set to false before release /** @@ -50,7 +51,7 @@ public class BaseLogger { private static boolean isLoggingEnabled = true; /** - * A {@code void} to enable or disable {@link BlueLib} specific logging. + * A {@code void} to enable or disable {@code BlueLib} specific logging. * * @param pEnabled {@link boolean} - Indicates whether to enable or disable BlueLib logging. * @Co-author MeAlam @@ -98,12 +99,12 @@ public static void setLoggingEnabled(boolean pEnabled) { } /** - * A {@code void} that logs a message with an associated {@link Throwable} if {@link BlueLib} logging is enabled. + * A {@code void} that logs a message with an associated {@link Throwable} if {@code BlueLib} logging is enabled. * * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. * @param pThrowable {@link Throwable} - The throwable to log with the message. - * @param pIsBlueLib {@link boolean} - Indicates if the message is {@link BlueLib} specific. + * @param pIsBlueLib {@link boolean} - Indicates if the message is {@code BlueLib} specific. * @Co-author MeAlam * @since 1.0.0 */ @@ -118,7 +119,7 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, b * * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. - * @param pIsBlueLib {@link boolean} - Indicates if the message is {@link BlueLib} specific. + * @param pIsBlueLib {@link boolean} - Indicates if the message is {@code BlueLib} specific. * @Co-author MeAlam * @since 1.0.0 */ @@ -158,9 +159,9 @@ public static void log(Level pLogLevel, String pMessage) { } /** - * A {@code void} that logs a {@link BlueLib} specific message at the {@link BlueLib} log level. + * A {@code void} that logs a {@code BlueLib} specific message at the {@code BlueLib} log level. * - * @param pMessage {@link String} - The {@link BlueLib} message to log. + * @param pMessage {@link String} - The {@code BlueLib} message to log. * @Co-author MeAlam * @since 1.0.0 */ diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java b/common/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java rename to common/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java diff --git a/NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java b/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/logging/LoggerConfig.java rename to common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java b/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java rename to common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java b/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/math/GeometricUtils.java rename to common/src/main/java/software/bluelib/utils/math/GeometricUtils.java diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java b/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/math/MatrixUtils.java rename to common/src/main/java/software/bluelib/utils/math/MatrixUtils.java diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java b/common/src/main/java/software/bluelib/utils/math/MiscUtils.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/math/MiscUtils.java rename to common/src/main/java/software/bluelib/utils/math/MiscUtils.java diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/math/RandomGenUtils.java rename to common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java diff --git a/NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/math/StatisticalUtils.java rename to common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java diff --git a/NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java b/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java rename to common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java diff --git a/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java similarity index 100% rename from NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java rename to common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java index 875cf9be..5a604b87 100644 --- a/NeoForge/src/main/java/software/bluelib/utils/variant/ParameterUtils.java +++ b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java @@ -2,8 +2,8 @@ package software.bluelib.utils.variant; -import software.bluelib.entity.variant.VariantParameter; import software.bluelib.entity.variant.VariantLoader; +import software.bluelib.entity.variant.VariantParameter; import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; diff --git a/NeoForge/src/main/resources/bluelib.mixins.json b/common/src/main/resources/bluelib.mixins.json similarity index 100% rename from NeoForge/src/main/resources/bluelib.mixins.json rename to common/src/main/resources/bluelib.mixins.json diff --git a/Forge/src/main/resources/bluelib.png b/common/src/main/resources/bluelib.png similarity index 100% rename from Forge/src/main/resources/bluelib.png rename to common/src/main/resources/bluelib.png diff --git a/common/src/main/resources/pack.mcmeta b/common/src/main/resources/pack.mcmeta new file mode 100644 index 00000000..52854ec4 --- /dev/null +++ b/common/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "${mod_name}", + "pack_format": 8 + } +} \ No newline at end of file diff --git a/fabric/build.gradle b/fabric/build.gradle new file mode 100644 index 00000000..ff277547 --- /dev/null +++ b/fabric/build.gradle @@ -0,0 +1,37 @@ +plugins { + id 'bluelib-loader' + id 'fabric-loom' +} +dependencies { + minecraft "com.mojang:minecraft:${minecraft_version}" + mappings loom.layered { + officialMojangMappings() + parchment("org.parchmentmc.data:parchment-${parchment_minecraft}:${parchment_version}@zip") + } + modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" + modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}" +} + +loom { + def aw = project(':common').file("src/main/resources/${mod_id}.accesswidener") + if (aw.exists()) { + accessWidenerPath.set(aw) + } + mixin { + defaultRefmapName.set("${mod_id}.refmap.json") + } + runs { + client { + client() + setConfigName('Fabric Client') + ideConfigGenerated(true) + runDir('runs/client') + } + server { + server() + setConfigName('Fabric Server') + ideConfigGenerated(true) + runDir('runs/server') + } + } +} \ No newline at end of file diff --git a/fabric/src/main/java/software/bluelib/BlueLib.java b/fabric/src/main/java/software/bluelib/BlueLib.java new file mode 100644 index 00000000..3600b465 --- /dev/null +++ b/fabric/src/main/java/software/bluelib/BlueLib.java @@ -0,0 +1,11 @@ +package software.bluelib; + +import net.fabricmc.api.ModInitializer; + +public class BlueLib implements ModInitializer { + + @Override + public void onInitialize() { + BlueLibCommon.init(); + } +} diff --git a/fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java b/fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java new file mode 100644 index 00000000..ec55e2bc --- /dev/null +++ b/fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java @@ -0,0 +1,24 @@ +package software.bluelib.platform; + +import net.fabricmc.loader.api.FabricLoader; +import software.bluelib.interfaces.platform.IPlatformHelper; + +public class FabricPlatformHelper implements IPlatformHelper { + + @Override + public String getPlatformName() { + return "Fabric"; + } + + @Override + public boolean isModLoaded(String modId) { + + return FabricLoader.getInstance().isModLoaded(modId); + } + + @Override + public boolean isDevelopmentEnvironment() { + + return FabricLoader.getInstance().isDevelopmentEnvironment(); + } +} \ No newline at end of file diff --git a/fabric/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper b/fabric/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper new file mode 100644 index 00000000..5fdff29c --- /dev/null +++ b/fabric/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper @@ -0,0 +1 @@ +software.bluelib.platform.FabricPlatformHelper \ No newline at end of file diff --git a/fabric/src/main/resources/bluelib.fabric.mixins.json b/fabric/src/main/resources/bluelib.fabric.mixins.json new file mode 100644 index 00000000..dbb95ef0 --- /dev/null +++ b/fabric/src/main/resources/bluelib.fabric.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "minVersion": "0.8", + "refmap": "${mod_id}.refmap.json", + "mixins": [], + "client": [ + ], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} + diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..5a78e1ad --- /dev/null +++ b/fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,36 @@ +{ + "schemaVersion": 1, + "id": "${mod_id}", + "version": "${version}", + "name": "${mod_name}", + "description": "${description}", + "authors": [ + "${mod_author}" + ], + "contact": { + "homepage": "https://fabricmc.net/", + "sources": "https://github.com/FabricMC/fabric-example-mod" + }, + "license": "${license}", + "icon": "bluelib.png", + "environment": "*", + "entrypoints": { + "main": [ + "software.bluelib.BlueLib" + ] + }, + "mixins": [ + "${mod_id}.mixins.json", + "${mod_id}.fabric.mixins.json" + ], + "depends": { + "fabricloader": ">=${fabric_loader_version}", + "fabric-api": "*", + "minecraft": "${minecraft_version}", + "java": ">=${java_version}" + }, + "suggests": { + "another-mod": "*" + } +} + \ No newline at end of file diff --git a/forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java b/forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java new file mode 100644 index 00000000..0905e124 --- /dev/null +++ b/forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java @@ -0,0 +1,26 @@ +package software.bluelib.platform; + +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.loading.FMLLoader; +import software.bluelib.interfaces.platform.IPlatformHelper; + +public class ForgePlatformHelper implements IPlatformHelper { + + @Override + public String getPlatformName() { + + return "Forge"; + } + + @Override + public boolean isModLoaded(String modId) { + + return ModList.get().isLoaded(modId); + } + + @Override + public boolean isDevelopmentEnvironment() { + + return !FMLLoader.isProduction(); + } +} \ No newline at end of file diff --git a/forge/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper b/forge/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper new file mode 100644 index 00000000..0031c488 --- /dev/null +++ b/forge/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper @@ -0,0 +1 @@ +software.bluelib.platform.ForgePlatformHelper \ No newline at end of file diff --git a/forge/src/main/resources/bluelib.forge.mixins.json b/forge/src/main/resources/bluelib.forge.mixins.json new file mode 100644 index 00000000..2618edd8 --- /dev/null +++ b/forge/src/main/resources/bluelib.forge.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "software.bluelib.mixin", + "mixins": [], + "client": [ + ], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..dd4fe5db --- /dev/null +++ b/gradle.properties @@ -0,0 +1,44 @@ +# Important Notes: +# Every field you add must be added to the root build.gradle expandProps map. + +# Project +java_version=21 +minecraft_version=1.21 + +# Common + +mod_id=bluelib +mod_name=BlueLib +license=MIT License +version=1.0.0 +group=software.bluelib +mod_author=Dan, Aram +description=BlueLib is an All round Minecraft mod library that offers data-driven features, allowing users to implement and customize its features with full freedom. \nIt supports both Resource and Datapacks, ensuring seamless integration and flexibility. + +credits= +minecraft_version_range=[1.21, 1.22) + +## This is the version of minecraft that the 'common' project uses, you can find a list of all versions here +## https://projects.neoforged.net/neoforged/neoform +neo_form_version=1.21-20240613.152323 +# The version of ParchmentMC that is used, see https://parchmentmc.org/docs/getting-started#choose-a-version for new versions +parchment_minecraft=1.21 +parchment_version=2024.06.23 + +# Fabric +fabric_version=0.100.1+1.21 +fabric_loader_version=0.15.11 + +# Forge +forge_version=51.0.17 +forge_version_range=[51,) +forge_loader_version_range=[0,) + +# NeoForge +neoforge_version=21.0.167 +neoforge_loader_version_range=[4,) +neoforge_version_range=[21.0.0-beta,) + +# Gradle +org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false diff --git a/NeoForge/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar similarity index 78% rename from NeoForge/gradle/wrapper/gradle-wrapper.jar rename to gradle/wrapper/gradle-wrapper.jar index 2c3521197d7c4586c843d1d3e9090525f1898cde..e6441136f3d4ba8a0da8d277868979cfbc8ad796 100644 GIT binary patch delta 8662 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 delta 8703 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 Ojj7^59?Sdh$^Qpp*~F>< diff --git a/NeoForge/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties similarity index 94% rename from NeoForge/gradle/wrapper/gradle-wrapper.properties rename to gradle/wrapper/gradle-wrapper.properties index 09523c0e..a4413138 100644 --- a/NeoForge/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/NeoForge/gradlew b/gradlew similarity index 98% rename from NeoForge/gradlew rename to gradlew index f5feea6d..b740cf13 100644 --- a/NeoForge/gradlew +++ b/gradlew @@ -15,8 +15,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# SPDX-License-Identifier: Apache-2.0 -# ############################################################################## # @@ -86,8 +84,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/NeoForge/gradlew.bat b/gradlew.bat similarity index 98% rename from NeoForge/gradlew.bat rename to gradlew.bat index 9d21a218..25da30db 100644 --- a/NeoForge/gradlew.bat +++ b/gradlew.bat @@ -13,8 +13,6 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java b/neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java new file mode 100644 index 00000000..35be15f5 --- /dev/null +++ b/neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java @@ -0,0 +1,25 @@ +package software.bluelib.platform; + +import net.neoforged.fml.ModList; +import net.neoforged.fml.loading.FMLLoader; +import software.bluelib.interfaces.platform.IPlatformHelper; + +public class NeoForgePlatformHelper implements IPlatformHelper { + + @Override + public String getPlatformName() { + + return "NeoForge"; + } + + @Override + public boolean isModLoaded(String modId) { + + return ModList.get().isLoaded(modId); + } + + @Override + public boolean isDevelopmentEnvironment() { + return !FMLLoader.isProduction(); + } +} \ No newline at end of file diff --git a/neoforge/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper b/neoforge/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper new file mode 100644 index 00000000..f06837d3 --- /dev/null +++ b/neoforge/src/main/resources/META-INF/services/software.bluelib.interfaces.platform.IPlatformHelper @@ -0,0 +1 @@ +software.bluelib.platform.NeoForgePlatformHelper \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..9821e417 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,61 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + exclusiveContent { + forRepository { + maven { + name = 'Fabric' + url = uri('https://maven.fabricmc.net') + } + } + filter { + includeGroup('net.fabricmc') + includeGroup('fabric-loom') + } + } + exclusiveContent { + forRepository { + maven { + name = 'Sponge' + url = uri('https://repo.spongepowered.org/repository/maven-public') + } + } + filter { + includeGroupAndSubgroups("org.spongepowered") + } + } + exclusiveContent { + forRepository { + maven { + name = 'Forge' + url = uri('https://maven.minecraftforge.net') + } + } + filter { + includeGroupAndSubgroups('net.minecraftforge') + } + } + exclusiveContent { + forRepository { + maven { + name = 'NeoForge' + url = uri('https://maven.neoforged.net/releases') + } + } + filter { + includeGroup('net.neoforged') + } + } + } +} + +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} + +rootProject.name = 'BlueLib' +include('common') +include('fabric') +include('neoforge') +include('forge') \ No newline at end of file From b6f1f5e506aecb68211823e37ecb14f8dec7e986 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 01:57:23 +0200 Subject: [PATCH 33/62] Added Fabric to the Workflow --- .github/workflows/ci.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 61217505..1eba62f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,12 +34,16 @@ jobs: - name: Grant execute permission for Gradle wrappers run: | - chmod +x NeoForge/gradlew - chmod +x Forge/gradlew + chmod +x neoforge/gradlew + chmod +x forge/gradlew + chmod +x fabric/gradlew - name: Build for NeoForge - run: cd NeoForge && ./gradlew build + run: cd neoForge && ./gradlew build - name: Build for Forge - run: cd Forge && ./gradlew build + run: cd forge && ./gradlew build + + - name: Build for Fabric + run: cd fabric && ./gradlew build From 3f06c90c276e42421b88a68ac6d9ee344e09974a Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 02:03:23 +0200 Subject: [PATCH 34/62] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 91829bde..2cbaeeef 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ replay_pid* # Default ignored files .idea/* +.gradle/* # BuildSrc buildSrc/build/* From 0cf5f48f8ca54c09a19bbd65bb17f76f5c698260 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 02:15:03 +0200 Subject: [PATCH 35/62] Fixed Code --- CONTRIBUTING.md | 8 +++--- .../main/java/software/bluelib/BlueLib.java | 6 ++--- .../main/java/software/bluelib/BlueLib.java | 6 ++--- .../java/software/bluelib/BlueLibCommon.java | 4 +-- .../software/bluelib/BlueLibConstants.java | 4 +-- .../bluelib/entity/variant/VariantLoader.java | 8 +++--- .../entity/variant/VariantParameter.java | 12 ++++----- .../entity/variant/base/ParameterBase.java | 26 +++++++++---------- .../bluelib/event/ReloadEventHandler.java | 4 +-- .../interfaces/logging/ILogColorProvider.java | 4 +-- .../interfaces/variant/IVariantEntity.java | 6 ++--- .../variant/base/IVariantEntityBase.java | 6 ++--- .../software/bluelib/json/JSONLoader.java | 6 ++--- .../software/bluelib/json/JSONMerger.java | 2 +- .../mixin/variant/LivingEntityMixin.java | 2 +- .../bluelib/utils/logging/BaseLogLevel.java | 10 +++---- .../bluelib/utils/logging/BaseLogger.java | 26 +++++++++---------- .../bluelib/utils/logging/LoggerConfig.java | 10 +++---- .../bluelib/utils/variant/ParameterUtils.java | 22 ++++++++-------- 19 files changed, 86 insertions(+), 86 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9eb82b88..4e1f0391 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,7 @@ *
        • {@link #loadJson(ResourceLocation, ResourceManager)} - Loads a JSON resource.
        • * * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public class JSONLoader { @@ -48,7 +48,7 @@ * @return The value of the custom parameter identified by {@code pParameterKey} * for the variant specified by {@code pVariantName}. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public String getCustomParameter(String pVariantName, String pParameterKey) { @@ -67,7 +67,7 @@ * @return The value of the custom parameter identified by {@code pParameterKey} * for the variant specified by {@code pVariantName}. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public String getCustomParameter(String pVariantName, String pParameterKey) { @@ -101,7 +101,7 @@ * TODO: Testing with Multiple Entities and Datapacks required before Deletion/Refactoring.
          * @return A map containing the parameters added to this builder. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 * @see #newMethod() */ diff --git a/Forge/src/main/java/software/bluelib/BlueLib.java b/Forge/src/main/java/software/bluelib/BlueLib.java index 64ed593c..87d8aef9 100644 --- a/Forge/src/main/java/software/bluelib/BlueLib.java +++ b/Forge/src/main/java/software/bluelib/BlueLib.java @@ -32,7 +32,7 @@ * * @see
          BlueLib Wiki * @author MeAlam, Dan - * @Co-author All Contributors of BlueLib! + * @co-author All Contributors of BlueLib! * @since 1.0.0 */ @Mod(BlueLibConstants.MOD_ID) @@ -42,7 +42,7 @@ public class BlueLib { * Constructs a new {@link BlueLib} instance and registers the mod event bus. * * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public BlueLib() { @@ -55,7 +55,7 @@ public BlueLib() { * * @param pEvent {@link FMLLoadCompleteEvent} - The event fired after the mod loading process completes. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ @SubscribeEvent diff --git a/NeoForge/src/main/java/software/bluelib/BlueLib.java b/NeoForge/src/main/java/software/bluelib/BlueLib.java index c0f36398..03f8ba47 100644 --- a/NeoForge/src/main/java/software/bluelib/BlueLib.java +++ b/NeoForge/src/main/java/software/bluelib/BlueLib.java @@ -32,7 +32,7 @@ * * @see BlueLib Wiki * @author MeAlam, Dan - * @Co-author All Contributors of BlueLib! + * @co-author All Contributors of BlueLib! * @since 1.0.0 */ @Mod(BlueLibConstants.MOD_ID) @@ -47,7 +47,7 @@ public class BlueLib { * @param pModEventBus {@link IEventBus} - The event bus where the mod registers its handlers. * @param pModContainer {@link ModContainer} - The mod container that holds the instance of the mod. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { @@ -60,7 +60,7 @@ public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { * * @param pEvent {@link FMLLoadCompleteEvent} - The event fired after the mod loading process completes. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ @SubscribeEvent diff --git a/common/src/main/java/software/bluelib/BlueLibCommon.java b/common/src/main/java/software/bluelib/BlueLibCommon.java index e0a9bf2b..e8921b59 100644 --- a/common/src/main/java/software/bluelib/BlueLibCommon.java +++ b/common/src/main/java/software/bluelib/BlueLibCommon.java @@ -31,7 +31,7 @@ public static void init() { BaseLogger.logBlueLib(" "); BaseLogger.logBlueLib("**************************************************"); SCHEDULER.shutdown(); - }, 3, TimeUnit.SECONDS); + }, 5, TimeUnit.SECONDS); } } @@ -43,7 +43,7 @@ public static void init() { * * @return {@code true} if running in developer mode, {@code false} otherwise. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ static boolean isDeveloperMode() { diff --git a/common/src/main/java/software/bluelib/BlueLibConstants.java b/common/src/main/java/software/bluelib/BlueLibConstants.java index ead38611..85821c46 100644 --- a/common/src/main/java/software/bluelib/BlueLibConstants.java +++ b/common/src/main/java/software/bluelib/BlueLibConstants.java @@ -10,7 +10,7 @@ public class BlueLibConstants { *

          * This executor runs tasks on a single thread to ensure delayed tasks run in a separate thread from the main thread. *

          - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan * @since 1.0.0 */ public static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1); @@ -18,7 +18,7 @@ public class BlueLibConstants { /** * A {@code public static final} {@link String} representing the Mod ID for the {@code BlueLib} mod. *

          This serves as a unique identifier for the mod.

          - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan * @since 1.0.0 */ public static final String MOD_ID = "bluelib"; diff --git a/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java index b2c3971d..ac421efd 100644 --- a/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -30,7 +30,7 @@ *
        • {@link #getVariantByName(String, String)} - Retrieves a specific {@link VariantParameter} by its name for a given entity.
        • * * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public class VariantLoader implements IVariantEntityBase { @@ -40,14 +40,14 @@ public class VariantLoader implements IVariantEntityBase { *

          * This {@link Map} holds entity names and their corresponding list of {@link VariantParameter} instances. *

          - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan * @since 1.0.0 */ private static final Map> entityVariantsMap = new HashMap<>(); /** * A {@code private static final} {@link JSONLoader} to load JSON data from resources. - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan * @since 1.0.0 */ private static final JSONLoader jsonLoader = new JSONLoader(); @@ -57,7 +57,7 @@ public class VariantLoader implements IVariantEntityBase { *

          * This {@link JSONMerger} instance is used to merge JSON data into a single {@link JsonObject}. *

          - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan * @since 1.0.0 */ private static final JSONMerger jsonMerger = new JSONMerger(); diff --git a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java index fce2f18d..7069ef69 100644 --- a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java +++ b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java @@ -25,7 +25,7 @@ *
        • {@link #getParameter(String)} - Retrieves the value of a specific parameter by its key.
        • * * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public class VariantParameter extends ParameterBase { @@ -35,7 +35,7 @@ public class VariantParameter extends ParameterBase { *

          * This key is used to map the entity to its corresponding parameters within a {@link JsonObject}. *

          - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan * @since 1.0.0 */ private final String jsonKey; @@ -56,7 +56,7 @@ public class VariantParameter extends ParameterBase { * @throws IllegalArgumentException if {@code pJsonKey} or {@code pJsonObject} is {@code null}. * @see ParameterBase * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { @@ -100,7 +100,7 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { * @return The key of the JSON object representing this entity. * @throws IllegalStateException if the key is unexpectedly {@code null}. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public String getJsonKey() { @@ -121,7 +121,7 @@ public String getJsonKey() { *

          * @return The name of the variant, or {@code null} if the variant name is not found. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public String getVariantName() { @@ -138,7 +138,7 @@ public String getVariantName() { * @param pKey {@link String} - The key of the parameter to retrieve. * @return The value of the parameter, or {@code null} if the key does not exist. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public String getParameter(String pKey) { diff --git a/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java index 69d1682d..767fd17b 100644 --- a/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java +++ b/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java @@ -30,7 +30,7 @@ *
        • {@link #updateParameter(String, Object)} - Updates the value of an existing parameter in {@link #parameters}.
        • * * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public abstract class ParameterBase { @@ -40,7 +40,7 @@ public abstract class ParameterBase { *

          * This {@link Map} holds parameter keys and their corresponding values. *

          - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan * @since 1.0.0 */ private final Map parameters = new HashMap<>(); @@ -53,7 +53,7 @@ public abstract class ParameterBase { * @param pKey {@link String} - The key under which the parameter is stored. * @param pValue {@link Object} - The value of the parameter. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected void addParameter(String pKey, Object pValue) { @@ -69,7 +69,7 @@ protected void addParameter(String pKey, Object pValue) { * @param pKey {@link String} - The key of the parameter to retrieve. * @return {@link Object} - The value associated with the key, or {@code null} if the key does not exist. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected Object getParameter(String pKey) { @@ -85,7 +85,7 @@ protected Object getParameter(String pKey) { *

          * @param pKey {@link String} - The key of the parameter to remove. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected void removeParameter(String pKey) { @@ -103,7 +103,7 @@ protected void removeParameter(String pKey) { *

          * @return {@link Map} - A {@link Map} containing all parameters. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected Map getAllParameters() { @@ -119,7 +119,7 @@ protected Map getAllParameters() { * @param pKey {@link String} - The key of the parameter to check. * @return {@link Boolean} - {@code true} if the parameter exists and {@code false} if it doesn't. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected boolean containsParameter(String pKey) { @@ -135,7 +135,7 @@ protected boolean containsParameter(String pKey) { *

          * @return {@link Boolean} - {@code true} if {@link #parameters} is empty and {@code false} if it isn't. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected boolean isEmpty() { @@ -147,7 +147,7 @@ protected boolean isEmpty() { /** * A {@code protected void} that removes all parameters from {@link #parameters}. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected void clearParameters() { @@ -159,7 +159,7 @@ protected void clearParameters() { * A {@code protected} {@link Integer} that returns the number of parameters in {@link #parameters}. * @return {@link Integer} - The number of parameters in the collection. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected int getParameterCount() { @@ -175,7 +175,7 @@ protected int getParameterCount() { *

          * @return {@link Set} - A {@link Set} containing all parameter keys. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected Set getParameterKeys() { @@ -190,7 +190,7 @@ protected Set getParameterKeys() { *

          * @return {@link Collection} - A {@link Collection} containing all parameter values. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected Collection getParameterValues() { @@ -207,7 +207,7 @@ protected Collection getParameterValues() { * @param pNewValue {@link Object} - The new value to set for the parameter. * @throws IllegalArgumentException if the key does not exist. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected void updateParameter(String pKey, Object pNewValue) { diff --git a/common/src/main/java/software/bluelib/event/ReloadEventHandler.java b/common/src/main/java/software/bluelib/event/ReloadEventHandler.java index 53c35347..f590f02d 100644 --- a/common/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/common/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -24,7 +24,7 @@ * @see MinecraftServer * @see ResourceLocation * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public class ReloadEventHandler { @@ -61,7 +61,7 @@ public class ReloadEventHandler { * @see ResourceLocation * @see VariantLoader * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ protected static void registerEntityVariants(String pFolderPath, MinecraftServer pServer, String pModID, String pEntityName) { diff --git a/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java b/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java index c0a48b1c..34ecbbdc 100644 --- a/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java +++ b/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java @@ -17,7 +17,7 @@ * *

          * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public interface ILogColorProvider { @@ -31,7 +31,7 @@ public interface ILogColorProvider { * @param pLevel {@link Level} - The log level for which to retrieve the color code. * @return The color code as a {@link String} for the specified log level. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ String getColor(Level pLevel); diff --git a/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java b/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java index 2b08cdac..f2a57fdd 100644 --- a/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java +++ b/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java @@ -22,14 +22,14 @@ * *

          * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public interface IVariantEntity extends IVariantEntityBase { /** * A {@link RandomSource} instance used for generating random variants. - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan * @since 1.0.0 */ RandomSource random = RandomSource.create(); @@ -45,7 +45,7 @@ public interface IVariantEntity extends IVariantEntityBase { * @param pDefaultVariant {@link String} - The default variant name to return if {@code pVariantNamesList} is empty. * @return A random variant name from the list, or the default variant if the list is empty. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ default String getRandomVariant(List pVariantNamesList, String pDefaultVariant) { diff --git a/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index d89c5499..2e18ee26 100644 --- a/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -24,7 +24,7 @@ * *

          * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public interface IVariantEntityBase { @@ -39,7 +39,7 @@ public interface IVariantEntityBase { * @param pPath {@link String} - The path to the texture within the mod. * @return A {@link ResourceLocation} pointing to the specified texture. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ default ResourceLocation getTextureLocation(String pModId, String pPath) { @@ -55,7 +55,7 @@ default ResourceLocation getTextureLocation(String pModId, String pPath) { * @param pEntityName {@link String} - The name of the entity whose variant names are to be retrieved. * @return A {@link List} containing the names of variants associated with the specified entity. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ default List getEntityVariants(String pEntityName) { diff --git a/common/src/main/java/software/bluelib/json/JSONLoader.java b/common/src/main/java/software/bluelib/json/JSONLoader.java index 25a6f80b..f44a4c05 100644 --- a/common/src/main/java/software/bluelib/json/JSONLoader.java +++ b/common/src/main/java/software/bluelib/json/JSONLoader.java @@ -26,14 +26,14 @@ *
        • {@link #loadJson(ResourceLocation, ResourceManager)} - Loads a JSON resource from the specified location.
        • * * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public class JSONLoader { /** * A {@code private static} {@link Gson} instance for parsing JSON data. - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan */ private static final Gson gson = new Gson(); @@ -47,7 +47,7 @@ public class JSONLoader { * @return The loaded {@link JsonObject}. Returns an empty {@link JsonObject} if the resource is not found. * @throws RuntimeException if there is an error reading the resource. * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager pResourceManager) { diff --git a/common/src/main/java/software/bluelib/json/JSONMerger.java b/common/src/main/java/software/bluelib/json/JSONMerger.java index ac300db6..5cde178c 100644 --- a/common/src/main/java/software/bluelib/json/JSONMerger.java +++ b/common/src/main/java/software/bluelib/json/JSONMerger.java @@ -24,7 +24,7 @@ * *

          * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public class JSONMerger { diff --git a/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java b/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java index d70b0364..5298977c 100644 --- a/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java +++ b/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java @@ -39,7 +39,7 @@ public class LivingEntityMixin implements IVariantAccessor { /** * A {@link EntityDataAccessor} to hold the entity's variant name, which is synchronized * across clients and servers using {@link SynchedEntityData}. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ @Unique diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java index 15f8ab85..de34f76b 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java @@ -22,33 +22,33 @@ public class BaseLogLevel { /** * Standard informational log level. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static final Level INFO = new Level("INFO", Level.INFO.intValue()) {}; /** * Log level for error messages. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static final Level ERROR = new Level("ERROR", Level.SEVERE.intValue()) {}; /** * Log level for warning messages. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static final Level WARNING = new Level("WARNING", Level.WARNING.intValue()) {}; /** * Custom log level for indicating successful operations. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static final Level SUCCESS = new Level("SUCCESS", Level.INFO.intValue() + 50) {}; /** * Custom log level specific to BlueLib. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static final Level BLUELIB = new Level("BlueLib Developer", Level.INFO.intValue() + 50) {}; diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java index d6a4a6f6..4b2d3bc5 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -23,14 +23,14 @@ * * * @author MeAlam - * @Co-author Dan + * @co-author Dan * @since 1.0.0 */ public class BaseLogger { /** * A {@link Logger} instance for logging messages. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ private static final Logger logger = Logger.getLogger(BlueLibConstants.MOD_NAME); @@ -38,14 +38,14 @@ public class BaseLogger { //FIXME: Set to false before release /** * A {@link Boolean} to enable or disable BlueLib specific logging. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ private static boolean bluelibLogging = true; /** * A {@link Boolean} to enable or disable general logging. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ private static boolean isLoggingEnabled = true; @@ -54,7 +54,7 @@ public class BaseLogger { * A {@code void} to enable or disable {@code BlueLib} specific logging. * * @param pEnabled {@link boolean} - Indicates whether to enable or disable BlueLib logging. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static void setBlueLibLoggingEnabled(boolean pEnabled) { @@ -65,7 +65,7 @@ public static void setBlueLibLoggingEnabled(boolean pEnabled) { * A {@link Boolean} method that checks if BlueLib logging is enabled. * * @return {@code true} if BlueLib logging is enabled, {@code false} otherwise. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static boolean isBlueLibLoggingEnabled() { @@ -76,7 +76,7 @@ public static boolean isBlueLibLoggingEnabled() { * A {@link Boolean} method that checks if logging is enabled. * * @return {@code true} if general logging is enabled, {@code false} otherwise. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static boolean isLoggingEnabled() { @@ -87,7 +87,7 @@ public static boolean isLoggingEnabled() { * A {@code void} to enable or disable general logging. * * @param pEnabled {@link boolean} - Indicates whether to enable or disable general logging. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static void setLoggingEnabled(boolean pEnabled) { @@ -105,7 +105,7 @@ public static void setLoggingEnabled(boolean pEnabled) { * @param pMessage {@link String} - The message to log. * @param pThrowable {@link Throwable} - The throwable to log with the message. * @param pIsBlueLib {@link boolean} - Indicates if the message is {@code BlueLib} specific. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, boolean pIsBlueLib) { @@ -120,7 +120,7 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, b * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. * @param pIsBlueLib {@link boolean} - Indicates if the message is {@code BlueLib} specific. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { @@ -135,7 +135,7 @@ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. * @param pThrowable {@link Throwable} - The throwable to log with the message. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { @@ -149,7 +149,7 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { * * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage) { @@ -162,7 +162,7 @@ public static void log(Level pLogLevel, String pMessage) { * A {@code void} that logs a {@code BlueLib} specific message at the {@code BlueLib} log level. * * @param pMessage {@link String} - The {@code BlueLib} message to log. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ public static void logBlueLib(String pMessage) { diff --git a/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java b/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java index dad4027d..0c794f21 100644 --- a/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java +++ b/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java @@ -28,35 +28,35 @@ public abstract class LoggerConfig { /** * ANSI color codes for console output. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ protected static final String RESET = "\u001B[0m"; /** * ANSI color codes for console output. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ protected static final String RED = "\u001B[31m"; /** * ANSI color codes for console output. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ protected static final String ORANGE = "\u001B[38;5;214m"; /** * ANSI color codes for console output. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ protected static final String BLUE = "\u001B[34m"; /** * ANSI color codes for console output. - * @Co-author MeAlam + * @co-author MeAlam * @since 1.0.0 */ protected static final String GREEN = "\u001B[38;5;10m"; diff --git a/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java index 5a604b87..020bd929 100644 --- a/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java +++ b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java @@ -32,7 +32,7 @@ * * @since 1.0.0 * @author MeAlam - * @Co-author Dan + * @co-author Dan * @version 1.0.0 * @see software.bluelib.entity.variant.VariantParameter */ @@ -46,7 +46,7 @@ public class ParameterUtils { *

          * * @since 1.0.0 - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan */ private static final Map> variantParametersMap = new HashMap<>(); @@ -61,7 +61,7 @@ public class ParameterUtils { * @return {@link String} The value of the custom parameter for the specified variant or {@code null} if not found. * @since 1.0.0 * @author MeAlam - * @Co-author Dan + * @co-author Dan */ public static String getParameter(String pVariantName, String pParameterKey) { return variantParametersMap.getOrDefault(pVariantName, new HashMap<>()).getOrDefault(pParameterKey, "null"); @@ -83,7 +83,7 @@ public static String getParameter(String pVariantName, String pParameterKey) { * * @since 1.0.0 * @author MeAlam - * @Co-author Dan + * @co-author Dan */ public static class ParameterBuilder { @@ -91,7 +91,7 @@ public static class ParameterBuilder { * The name of the variant being associated with custom parameters. * * @since 1.0.0 - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan */ private final String variantName; @@ -99,7 +99,7 @@ public static class ParameterBuilder { * The name of the entity being associated with custom parameters. * * @since 1.0.0 - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan */ private final String entityName; @@ -107,7 +107,7 @@ public static class ParameterBuilder { * Stores custom parameters being built for the variant. * * @since 1.0.0 - * @Co-author MeAlam, Dan + * @co-author MeAlam, Dan */ private final Map parameters = new HashMap<>(); @@ -118,7 +118,7 @@ public static class ParameterBuilder { * @param pVariantName {@link String} The name of the variant. * @since 1.0.0 * @author MeAlam - * @Co-author Dan + * @co-author Dan */ private ParameterBuilder(String pEntityName, String pVariantName) { this.variantName = pVariantName; @@ -133,7 +133,7 @@ private ParameterBuilder(String pEntityName, String pVariantName) { * @return {@link ParameterBuilder} A new instance for chaining. * @since 1.0.0 * @author MeAlam - * @Co-author Dan + * @co-author Dan */ public static ParameterBuilder forVariant(String pEntityName, String pVariantName) { return new ParameterBuilder(pEntityName, pVariantName); @@ -149,7 +149,7 @@ public static ParameterBuilder forVariant(String pEntityName, String pVariantNam * @return {@link ParameterBuilder} The builder instance for chaining. * @since 1.0.0 * @author MeAlam - * @Co-author Dan + * @co-author Dan */ public ParameterBuilder withParameter(String pParameter) { parameters.put(pParameter, "null"); @@ -166,7 +166,7 @@ public ParameterBuilder withParameter(String pParameter) { * @throws NoSuchElementException if the variant or entity is not found in the database. * @since 1.0.0 * @author MeAlam - * @Co-author Dan + * @co-author Dan */ public ParameterBuilder connect() { VariantParameter variant = VariantLoader.getVariantByName(entityName, variantName); From e8c86172fd2d009c63865a2a5868cf7507dddebb Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 02:17:50 +0200 Subject: [PATCH 36/62] Updated CI --- .github/workflows/ci.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1eba62f5..293b32e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,18 +32,21 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - - name: Grant execute permission for Gradle wrappers + # Set up a single Gradle wrapper in a common directory + - name: Generate Gradle wrapper if not present run: | - chmod +x neoforge/gradlew - chmod +x forge/gradlew - chmod +x fabric/gradlew + if [ ! -f "./gradlew" ]; then + gradle wrapper + fi + + - name: Grant execute permission for Gradle wrapper + run: chmod +x ./gradlew - name: Build for NeoForge - run: cd neoForge && ./gradlew build + run: ./gradlew build -p neoforge - name: Build for Forge - run: cd forge && ./gradlew build + run: ./gradlew build -p forge - name: Build for Fabric - run: cd fabric && ./gradlew build - + run: ./gradlew build -p fabric From d76537c555afec5e0df99779cc327d69081baa62 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 11:52:19 +0200 Subject: [PATCH 37/62] Fixed the Welcome Message --- fabric/src/main/java/software/bluelib/BlueLib.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fabric/src/main/java/software/bluelib/BlueLib.java b/fabric/src/main/java/software/bluelib/BlueLib.java index 3600b465..876f8311 100644 --- a/fabric/src/main/java/software/bluelib/BlueLib.java +++ b/fabric/src/main/java/software/bluelib/BlueLib.java @@ -1,11 +1,19 @@ package software.bluelib; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; public class BlueLib implements ModInitializer { - + + private boolean hasInitialized = false; + @Override public void onInitialize() { - BlueLibCommon.init(); + ClientTickEvents.END_CLIENT_TICK.register(client -> { + if (!hasInitialized) { + hasInitialized = true; + BlueLibCommon.init(); + } + }); } } From 22d2aec945382b075d6557a63a3ab895722c7c64 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 11:59:09 +0200 Subject: [PATCH 38/62] Cleaned up all Conventions --- CONTRIBUTING.md | 8 +-- .../main/java/software/bluelib/BlueLib.java | 12 +--- .../main/java/software/bluelib/BlueLib.java | 14 +---- .../java/software/bluelib/BlueLibCommon.java | 5 +- .../software/bluelib/BlueLibConstants.java | 42 ++++++++------ .../bluelib/entity/variant/VariantLoader.java | 39 ++++++++----- .../entity/variant/VariantParameter.java | 33 +++++------ .../entity/variant/base/ParameterBase.java | 29 +++++----- .../bluelib/event/ReloadEventHandler.java | 22 +++---- .../interfaces/logging/ILogColorProvider.java | 3 +- .../interfaces/variant/IVariantEntity.java | 10 ++-- .../variant/base/IVariantEntityBase.java | 8 +-- .../software/bluelib/json/JSONLoader.java | 15 ++--- .../software/bluelib/json/JSONMerger.java | 12 ++-- .../mixin/variant/LivingEntityMixin.java | 7 ++- .../utils/conversion/MathConverterUtils.java | 9 +-- .../bluelib/utils/logging/BaseLogLevel.java | 21 +++++-- .../bluelib/utils/logging/BaseLogger.java | 18 +++--- .../logging/DefaultLogColorProvider.java | 1 + .../bluelib/utils/logging/LoggerConfig.java | 7 ++- .../bluelib/utils/math/AlgebraicUtils.java | 17 +++--- .../bluelib/utils/math/GeometricUtils.java | 29 +++++----- .../bluelib/utils/math/MatrixUtils.java | 9 +-- .../bluelib/utils/math/MiscUtils.java | 11 ++-- .../bluelib/utils/math/RandomGenUtils.java | 11 ++-- .../bluelib/utils/math/StatisticalUtils.java | 29 +++++----- .../bluelib/utils/minecraft/ChunkUtils.java | 57 ++++++++++--------- .../bluelib/utils/variant/ParameterUtils.java | 37 +++++------- 28 files changed, 266 insertions(+), 249 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e1f0391..882c9e7d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,7 @@ *
        • {@link #loadJson(ResourceLocation, ResourceManager)} - Loads a JSON resource.
        • * * @author MeAlam - * @co-author Dan + * @since 1.0.0 */ public class JSONLoader { @@ -48,7 +48,7 @@ * @return The value of the custom parameter identified by {@code pParameterKey} * for the variant specified by {@code pVariantName}. * @author MeAlam - * @co-author Dan + * @since 1.0.0 */ public String getCustomParameter(String pVariantName, String pParameterKey) { @@ -67,7 +67,7 @@ * @return The value of the custom parameter identified by {@code pParameterKey} * for the variant specified by {@code pVariantName}. * @author MeAlam - * @co-author Dan + * @since 1.0.0 */ public String getCustomParameter(String pVariantName, String pParameterKey) { @@ -101,7 +101,7 @@ * TODO: Testing with Multiple Entities and Datapacks required before Deletion/Refactoring.
          * @return A map containing the parameters added to this builder. * @author MeAlam - * @co-author Dan + * @since 1.0.0 * @see #newMethod() */ diff --git a/Forge/src/main/java/software/bluelib/BlueLib.java b/Forge/src/main/java/software/bluelib/BlueLib.java index 87d8aef9..c58de55b 100644 --- a/Forge/src/main/java/software/bluelib/BlueLib.java +++ b/Forge/src/main/java/software/bluelib/BlueLib.java @@ -7,13 +7,6 @@ import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.fml.loading.FMLEnvironment; -import software.bluelib.utils.logging.BaseLogLevel; -import software.bluelib.utils.logging.BaseLogger; - -import java.util.concurrent.TimeUnit; - -import static software.bluelib.BlueLibConstants.SCHEDULER; /** * The main class of the {@link BlueLib} mod. @@ -30,9 +23,8 @@ * *

          * + * @author MeAlam, Dan and All Contributors of BlueLib! * @see BlueLib Wiki - * @author MeAlam, Dan - * @co-author All Contributors of BlueLib! * @since 1.0.0 */ @Mod(BlueLibConstants.MOD_ID) @@ -42,7 +34,6 @@ public class BlueLib { * Constructs a new {@link BlueLib} instance and registers the mod event bus. * * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public BlueLib() { @@ -55,7 +46,6 @@ public BlueLib() { * * @param pEvent {@link FMLLoadCompleteEvent} - The event fired after the mod loading process completes. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ @SubscribeEvent diff --git a/NeoForge/src/main/java/software/bluelib/BlueLib.java b/NeoForge/src/main/java/software/bluelib/BlueLib.java index 03f8ba47..ad53369f 100644 --- a/NeoForge/src/main/java/software/bluelib/BlueLib.java +++ b/NeoForge/src/main/java/software/bluelib/BlueLib.java @@ -7,14 +7,7 @@ import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLLoadCompleteEvent; -import net.neoforged.fml.loading.FMLEnvironment; import org.spongepowered.asm.launch.MixinBootstrap; -import software.bluelib.utils.logging.BaseLogLevel; -import software.bluelib.utils.logging.BaseLogger; - -import java.util.concurrent.TimeUnit; - -import static software.bluelib.BlueLibConstants.SCHEDULER; /** * The main class of the {@code BlueLib} mod. @@ -30,9 +23,8 @@ * *

          * + * @author MeAlam, Dan and All Contributors of BlueLib! * @see BlueLib Wiki - * @author MeAlam, Dan - * @co-author All Contributors of BlueLib! * @since 1.0.0 */ @Mod(BlueLibConstants.MOD_ID) @@ -44,10 +36,9 @@ public class BlueLib { * Registers necessary mod event listeners, and if in developer mode, additional client-side listeners for rendering and attributes. *

          * - * @param pModEventBus {@link IEventBus} - The event bus where the mod registers its handlers. + * @param pModEventBus {@link IEventBus} - The event bus where the mod registers its handlers. * @param pModContainer {@link ModContainer} - The mod container that holds the instance of the mod. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { @@ -60,7 +51,6 @@ public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { * * @param pEvent {@link FMLLoadCompleteEvent} - The event fired after the mod loading process completes. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ @SubscribeEvent diff --git a/common/src/main/java/software/bluelib/BlueLibCommon.java b/common/src/main/java/software/bluelib/BlueLibCommon.java index e8921b59..fdc1d205 100644 --- a/common/src/main/java/software/bluelib/BlueLibCommon.java +++ b/common/src/main/java/software/bluelib/BlueLibCommon.java @@ -43,15 +43,14 @@ public static void init() { * * @return {@code true} if running in developer mode, {@code false} otherwise. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ static boolean isDeveloperMode() { boolean isDevMode = PLATFORM.isDevelopmentEnvironment(); if (isDevMode) { - BaseLogger.log(BaseLogLevel.INFO ,"Running in Developer mode.", true); + BaseLogger.log(BaseLogLevel.INFO, "Running in Developer mode.", true); } else { - BaseLogger.log(BaseLogLevel.INFO ,"Running in Production mode.", true); + BaseLogger.log(BaseLogLevel.INFO, "Running in Production mode.", true); } return isDevMode; } diff --git a/common/src/main/java/software/bluelib/BlueLibConstants.java b/common/src/main/java/software/bluelib/BlueLibConstants.java index 85821c46..c5934a6b 100644 --- a/common/src/main/java/software/bluelib/BlueLibConstants.java +++ b/common/src/main/java/software/bluelib/BlueLibConstants.java @@ -5,23 +5,31 @@ public class BlueLibConstants { - /** - * A {@code public static final} {@link ScheduledExecutorService} used to schedule tasks, such as printing messages after a delay. - *

          - * This executor runs tasks on a single thread to ensure delayed tasks run in a separate thread from the main thread. - *

          - * @co-author MeAlam, Dan - * @since 1.0.0 - */ - public static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1); + /** + * A {@code public static final} {@link ScheduledExecutorService} used to schedule tasks, such as printing messages after a delay. + *

          + * This executor runs tasks on a single thread to ensure delayed tasks run in a separate thread from the main thread. + *

          + * + * @co-author MeAlam, Dan + * @since 1.0.0 + */ + public static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1); - /** - * A {@code public static final} {@link String} representing the Mod ID for the {@code BlueLib} mod. - *

          This serves as a unique identifier for the mod.

          - * @co-author MeAlam, Dan - * @since 1.0.0 - */ - public static final String MOD_ID = "bluelib"; + /** + * A {@code public static final} {@link String} representing the Mod ID for the {@code BlueLib} mod. + *

          This serves as a unique identifier for the mod.

          + * + * @co-author MeAlam, Dan + * @since 1.0.0 + */ + public static final String MOD_ID = "bluelib"; - public static final String MOD_NAME = "BlueLib"; + /** + * A {@code public static final} {@link String} representing the Mod Name for the {@code BlueLib} mod. + * + * @co-author MeAlam, Dan + * @since 1.0.0 + */ + public static final String MOD_NAME = "BlueLib"; } \ No newline at end of file diff --git a/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java index ac421efd..af8e039e 100644 --- a/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -29,8 +29,8 @@ *
        • {@link #getVariantsFromEntity(String)} - Retrieves the list of loaded {@link VariantParameter} for a specific entity.
        • *
        • {@link #getVariantByName(String, String)} - Retrieves a specific {@link VariantParameter} by its name for a given entity.
        • * + * * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public class VariantLoader implements IVariantEntityBase { @@ -40,6 +40,7 @@ public class VariantLoader implements IVariantEntityBase { *

          * This {@link Map} holds entity names and their corresponding list of {@link VariantParameter} instances. *

          + * * @co-author MeAlam, Dan * @since 1.0.0 */ @@ -47,6 +48,7 @@ public class VariantLoader implements IVariantEntityBase { /** * A {@code private static final} {@link JSONLoader} to load JSON data from resources. + * * @co-author MeAlam, Dan * @since 1.0.0 */ @@ -57,6 +59,7 @@ public class VariantLoader implements IVariantEntityBase { *

          * This {@link JSONMerger} instance is used to merge JSON data into a single {@link JsonObject}. *

          + * * @co-author MeAlam, Dan * @since 1.0.0 */ @@ -68,12 +71,13 @@ public class VariantLoader implements IVariantEntityBase { * The method loops through all resources in the folder and merges them into a single {@link JsonObject}.
          * The merged JSON data is then parsed into {@link VariantParameter} instances and stored in {@link #entityVariantsMap}. *

          - * @param folderPath {@link String} - The path to the folder containing JSON resources. - * @param pServer {@link MinecraftServer} - The {@link MinecraftServer} instance used to access resources. + * + * @param folderPath {@link String} - The path to the folder containing JSON resources. + * @param pServer {@link MinecraftServer} - The {@link MinecraftServer} instance used to access resources. * @param pEntityName {@link String} - The name of the entity whose variants should be cleared before loading new ones. */ public static void loadVariants(String folderPath, MinecraftServer pServer, String pEntityName) { - BaseLogger.log(BaseLogLevel.INFO,"Starting to load variants for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO, "Starting to load variants for entity: " + pEntityName); clearVariantsForEntity(pEntityName); @@ -82,19 +86,19 @@ public static void loadVariants(String folderPath, MinecraftServer pServer, Stri Collection collection = resourceManager.listResources(folderPath, pFiles -> pFiles.getPath().endsWith(".json")).keySet(); - BaseLogger.log(BaseLogLevel.INFO,"Found resources: " + collection); + BaseLogger.log(BaseLogLevel.INFO, "Found resources: " + collection); for (ResourceLocation resourceLocation : collection) { try { - BaseLogger.log(BaseLogLevel.INFO,"Loading JSON data from resource: " + resourceLocation.toString()); + BaseLogger.log(BaseLogLevel.INFO, "Loading JSON data from resource: " + resourceLocation.toString()); JsonObject jsonObject = jsonLoader.loadJson(resourceLocation, resourceManager); jsonMerger.mergeJsonObjects(mergedJsonObject, jsonObject); } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR,"Failed to load JSON data from resource: " + resourceLocation.toString(), pException); + BaseLogger.log(BaseLogLevel.ERROR, "Failed to load JSON data from resource: " + resourceLocation.toString(), pException); } } - BaseLogger.log(BaseLogLevel.INFO,"Successfully loaded and merged JSON data for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO, "Successfully loaded and merged JSON data for entity: " + pEntityName); parseVariants(mergedJsonObject); } @@ -103,10 +107,11 @@ public static void loadVariants(String folderPath, MinecraftServer pServer, Stri *

          * This method removes all variants associated with the given entity name. *

          + * * @param pEntityName {@link String} - The name of the entity whose variants should be cleared. */ private static void clearVariantsForEntity(String pEntityName) { - BaseLogger.log(BaseLogLevel.INFO,"Clearing variants for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO, "Clearing variants for entity: " + pEntityName); entityVariantsMap.remove(pEntityName); } @@ -115,6 +120,7 @@ private static void clearVariantsForEntity(String pEntityName) { *

          * This method processes each entry in the JSON object and stores the created {@link VariantParameter} instances in {@link #entityVariantsMap}. *

          + * * @param pJsonObject {@link JsonObject} - The merged {@link JsonObject} containing variant data. */ private static void parseVariants(JsonObject pJsonObject) { @@ -122,7 +128,7 @@ private static void parseVariants(JsonObject pJsonObject) { String entityName = entry.getKey(); JsonArray textureArray = entry.getValue().getAsJsonArray(); - BaseLogger.log(BaseLogLevel.INFO,"Parsing variants for entity: " + entityName); + BaseLogger.log(BaseLogLevel.INFO, "Parsing variants for entity: " + entityName); List variantList = entityVariantsMap.computeIfAbsent(entityName, k -> new ArrayList<>()); for (JsonElement variant : textureArray) { @@ -143,7 +149,8 @@ private static void parseVariants(JsonObject pJsonObject) { *

          * This method wraps the creation of {@link VariantParameter} instances for easier management and potential modification. *

          - * @param pJsonKey {@link String} - The key associated with this variant. + * + * @param pJsonKey {@link String} - The key associated with this variant. * @param pJsonObject {@link JsonObject} - The {@link JsonObject} containing the variant data. * @return {@link VariantParameter} - A {@link VariantParameter} instance. */ @@ -156,11 +163,12 @@ private static VariantParameter getEntityVariant(String pJsonKey, JsonObject pJs *

          * This method returns a list of variants for the given entity name. If no variants are found, an empty list is returned. *

          + * * @param pEntityName {@link String} - The name of the entity to retrieve variants for. * @return {@link List} - A {@link List} of {@link VariantParameter} instances for the specified entity. */ public static List getVariantsFromEntity(String pEntityName) { - BaseLogger.log(BaseLogLevel.INFO,"Retrieving variants for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO, "Retrieving variants for entity: " + pEntityName); return entityVariantsMap.getOrDefault(pEntityName, new ArrayList<>()); } @@ -169,19 +177,20 @@ public static List getVariantsFromEntity(String pEntityName) { *

          * This method searches for a variant with the specified name within the list of variants for the given entity. *

          - * @param pEntityName {@link String} - The name of the entity to retrieve variants for. + * + * @param pEntityName {@link String} - The name of the entity to retrieve variants for. * @param pVariantName {@link String} - The name of the variant to retrieve. * @return {@link VariantParameter} - The {@link VariantParameter} with the specified name, or {@code null} if not found. */ public static VariantParameter getVariantByName(String pEntityName, String pVariantName) { - BaseLogger.log(BaseLogLevel.INFO,"Retrieving variant by name: " + pVariantName + " for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO, "Retrieving variant by name: " + pVariantName + " for entity: " + pEntityName); List variants = getVariantsFromEntity(pEntityName); for (VariantParameter variant : variants) { if (variant.getVariantName().equals(pVariantName)) { return variant; } } - BaseLogger.log(BaseLogLevel.INFO,"Variant with name: " + pVariantName + " not found for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO, "Variant with name: " + pVariantName + " not found for entity: " + pEntityName); return null; } } diff --git a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java index 7069ef69..c5b4b01b 100644 --- a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java +++ b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java @@ -24,8 +24,8 @@ *
        • {@link #getVariantName()} - Retrieves the name of the variant.
        • *
        • {@link #getParameter(String)} - Retrieves the value of a specific parameter by its key.
        • * + * * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public class VariantParameter extends ParameterBase { @@ -35,6 +35,7 @@ public class VariantParameter extends ParameterBase { *

          * This key is used to map the entity to its corresponding parameters within a {@link JsonObject}. *

          + * * @co-author MeAlam, Dan * @since 1.0.0 */ @@ -51,29 +52,29 @@ public class VariantParameter extends ParameterBase { *
        • {@code Other Types}: Stores "null" for unhandled JSON types.
        • * *

          - * @param pJsonKey {@link String} - The key that identifies this entity within the {@link JsonObject}. + * + * @param pJsonKey {@link String} - The key that identifies this entity within the {@link JsonObject}. * @param pJsonObject {@link JsonObject} - The {@link JsonObject} containing the variant parameters. * @throws IllegalArgumentException if {@code pJsonKey} or {@code pJsonObject} is {@code null}. - * @see ParameterBase * @author MeAlam - * @co-author Dan + * @see ParameterBase * @since 1.0.0 */ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { if (pJsonKey == null || pJsonObject == null) { Throwable throwable = new Throwable("JSON key or JSON object is null"); IllegalArgumentException exception = new IllegalArgumentException("JSON key and object must not be null"); - BaseLogger.log(BaseLogLevel.ERROR,exception.toString(), throwable); + BaseLogger.log(BaseLogLevel.ERROR, exception.toString(), throwable); throw exception; } this.jsonKey = pJsonKey; - BaseLogger.log(BaseLogLevel.INFO,"Creating VariantParameter with JSON key: " + pJsonKey); + BaseLogger.log(BaseLogLevel.INFO, "Creating VariantParameter with JSON key: " + pJsonKey); Set> entryMap = pJsonObject.entrySet(); for (Map.Entry entry : entryMap) { JsonElement element = entry.getValue(); if (element.isJsonPrimitive()) { addParameter(entry.getKey(), element.getAsString()); - BaseLogger.log(BaseLogLevel.SUCCESS,"Added primitive parameter: " + entry.getKey() + " = " + element.getAsString()); + BaseLogger.log(BaseLogLevel.SUCCESS, "Added primitive parameter: " + entry.getKey() + " = " + element.getAsString()); } else if (element.isJsonArray()) { StringBuilder arrayValues = new StringBuilder(); element.getAsJsonArray().forEach(e -> arrayValues.append(e.getAsString()).append(",")); @@ -81,13 +82,13 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { arrayValues.setLength(arrayValues.length() - 1); } addParameter(entry.getKey(), arrayValues.toString()); - BaseLogger.log(BaseLogLevel.SUCCESS,"Added array parameter: " + entry.getKey() + " = " + arrayValues.toString()); + BaseLogger.log(BaseLogLevel.SUCCESS, "Added array parameter: " + entry.getKey() + " = " + arrayValues.toString()); } else if (element.isJsonObject()) { addParameter(entry.getKey(), element.toString()); - BaseLogger.log(BaseLogLevel.SUCCESS,"Added object parameter: " + entry.getKey() + " = " + element.toString()); + BaseLogger.log(BaseLogLevel.SUCCESS, "Added object parameter: " + entry.getKey() + " = " + element.toString()); } else { addParameter(entry.getKey(), "null"); - BaseLogger.log(BaseLogLevel.SUCCESS,"Added null parameter for key: " + entry.getKey()); + BaseLogger.log(BaseLogLevel.SUCCESS, "Added null parameter for key: " + entry.getKey()); } } } @@ -97,10 +98,10 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { *

          * This key is used to retrieve or map the entity within a broader data structure. *

          + * * @return The key of the JSON object representing this entity. * @throws IllegalStateException if the key is unexpectedly {@code null}. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public String getJsonKey() { @@ -110,7 +111,7 @@ public String getJsonKey() { BaseLogger.log(BaseLogLevel.ERROR, "JSON key is unexpectedly null when retrieving from VariantParameter.", throwable); throw exception; } - BaseLogger.log(BaseLogLevel.INFO,"Retrieved JSON key: " + this.jsonKey); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved JSON key: " + this.jsonKey); return this.jsonKey; } @@ -119,14 +120,14 @@ public String getJsonKey() { *

          * The variant name is expected to be stored under the key {@code "variantName"} in the parameters/JSON files. *

          + * * @return The name of the variant, or {@code null} if the variant name is not found. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public String getVariantName() { String variantName = getParameter("variantName"); - BaseLogger.log(BaseLogLevel.INFO,"Retrieved variant name: " + variantName); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved variant name: " + variantName); return variantName; } @@ -135,15 +136,15 @@ public String getVariantName() { *

          * This method looks up the parameter's value within the internal data structure. *

          + * * @param pKey {@link String} - The key of the parameter to retrieve. * @return The value of the parameter, or {@code null} if the key does not exist. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public String getParameter(String pKey) { String value = (String) super.getParameter(pKey); - BaseLogger.log(BaseLogLevel.INFO,"Retrieved parameter for key " + pKey + ": " + value); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter for key " + pKey + ": " + value); return value; } } diff --git a/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java index 767fd17b..9769ac9f 100644 --- a/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java +++ b/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java @@ -29,8 +29,8 @@ *
        • {@link #getParameterValues()} - Returns a collection of all parameter values from {@link #parameters}.
        • *
        • {@link #updateParameter(String, Object)} - Updates the value of an existing parameter in {@link #parameters}.
        • * + * * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public abstract class ParameterBase { @@ -40,6 +40,7 @@ public abstract class ParameterBase { *

          * This {@link Map} holds parameter keys and their corresponding values. *

          + * * @co-author MeAlam, Dan * @since 1.0.0 */ @@ -50,10 +51,10 @@ public abstract class ParameterBase { *

          * This method stores a new parameter with the specified key and value in {@link #parameters}. *

          - * @param pKey {@link String} - The key under which the parameter is stored. + * + * @param pKey {@link String} - The key under which the parameter is stored. * @param pValue {@link Object} - The value of the parameter. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected void addParameter(String pKey, Object pValue) { @@ -66,10 +67,10 @@ protected void addParameter(String pKey, Object pValue) { *

          * This method returns the value associated with the specified key, or {@code null} if the key does not exist. *

          + * * @param pKey {@link String} - The key of the parameter to retrieve. * @return {@link Object} - The value associated with the key, or {@code null} if the key does not exist. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected Object getParameter(String pKey) { @@ -83,9 +84,9 @@ protected Object getParameter(String pKey) { *

          * This method deletes the parameter with the specified key from {@link #parameters}. If the key does not exist, no action is taken. *

          + * * @param pKey {@link String} - The key of the parameter to remove. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected void removeParameter(String pKey) { @@ -101,9 +102,9 @@ protected void removeParameter(String pKey) { *

          * This method returns a new {@link Map} containing all parameters stored in {@link #parameters}. *

          + * * @return {@link Map} - A {@link Map} containing all parameters. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected Map getAllParameters() { @@ -116,10 +117,10 @@ protected Map getAllParameters() { *

          * This method returns {@code true} if the parameter with the specified key exists in {@link #parameters}, {@code false} otherwise. *

          + * * @param pKey {@link String} - The key of the parameter to check. * @return {@link Boolean} - {@code true} if the parameter exists and {@code false} if it doesn't. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected boolean containsParameter(String pKey) { @@ -133,9 +134,9 @@ protected boolean containsParameter(String pKey) { *

          * This method returns {@code true} if {@link #parameters} contains no parameters, {@code false} otherwise. *

          + * * @return {@link Boolean} - {@code true} if {@link #parameters} is empty and {@code false} if it isn't. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected boolean isEmpty() { @@ -146,8 +147,8 @@ protected boolean isEmpty() { /** * A {@code protected void} that removes all parameters from {@link #parameters}. + * * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected void clearParameters() { @@ -157,9 +158,9 @@ protected void clearParameters() { /** * A {@code protected} {@link Integer} that returns the number of parameters in {@link #parameters}. + * * @return {@link Integer} - The number of parameters in the collection. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected int getParameterCount() { @@ -173,9 +174,9 @@ protected int getParameterCount() { *

          * This method provides a {@link Set} containing all the keys of parameters in {@link #parameters}. *

          + * * @return {@link Set} - A {@link Set} containing all parameter keys. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected Set getParameterKeys() { @@ -188,9 +189,9 @@ protected Set getParameterKeys() { *

          * This method provides a {@link Collection} containing all the values of parameters in {@link #parameters}. *

          + * * @return {@link Collection} - A {@link Collection} containing all parameter values. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected Collection getParameterValues() { @@ -203,11 +204,11 @@ protected Collection getParameterValues() { *

          * This method changes the value of a parameter in {@link #parameters} that is identified by the specified key. If the key does not exist, an exception is thrown. *

          - * @param pKey {@link String} - The key of the parameter to update. + * + * @param pKey {@link String} - The key of the parameter to update. * @param pNewValue {@link Object} - The new value to set for the parameter. * @throws IllegalArgumentException if the key does not exist. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected void updateParameter(String pKey, Object pNewValue) { diff --git a/common/src/main/java/software/bluelib/event/ReloadEventHandler.java b/common/src/main/java/software/bluelib/event/ReloadEventHandler.java index f590f02d..c9e3e8ce 100644 --- a/common/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/common/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -20,11 +20,11 @@ *
        • {@link #registerEntityVariants(String, MinecraftServer, String, String)} - Registers entity variants from specified locations.
        • * *

          + * + * @author MeAlam * @see VariantLoader * @see MinecraftServer * @see ResourceLocation - * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public class ReloadEventHandler { @@ -51,31 +51,31 @@ public class ReloadEventHandler { *
        • {@link RuntimeException} - Thrown for unexpected errors during the registration process.
        • * *

          + * * @param pFolderPath {@link String} - The folder path location within the mod or datapack where variants are stored. - * @param pServer {@link MinecraftServer} - The server instance of the current world. - * @param pModID {@link String} - The mod ID used to locate the entity variant resources. (Use your Mod's ID) + * @param pServer {@link MinecraftServer} - The server instance of the current world. + * @param pModID {@link String} - The mod ID used to locate the entity variant resources. (Use your Mod's ID) * @param pEntityName {@link String} - The entity name to load. * @throws JsonParseException if there is an error parsing the JSON files. - * @throws RuntimeException if an unexpected error occurs during the registration process. + * @throws RuntimeException if an unexpected error occurs during the registration process. + * @author MeAlam * @see MinecraftServer * @see ResourceLocation * @see VariantLoader - * @author MeAlam - * @co-author Dan * @since 1.0.0 */ protected static void registerEntityVariants(String pFolderPath, MinecraftServer pServer, String pModID, String pEntityName) { - BaseLogger.log(BaseLogLevel.INFO,"Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID); + BaseLogger.log(BaseLogLevel.INFO, "Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID); try { VariantLoader.loadVariants(pFolderPath, pServer, pEntityName); - BaseLogger.log(BaseLogLevel.SUCCESS,"Successfully registered entity variants for " + pEntityName + " from ModID: " + pModID); + BaseLogger.log(BaseLogLevel.SUCCESS, "Successfully registered entity variants for " + pEntityName + " from ModID: " + pModID); } catch (JsonParseException pException) { - BaseLogger.log(BaseLogLevel.ERROR,"Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); throw pException; } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR,"Unexpected error occurred while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Unexpected error occurred while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); throw pException; } } diff --git a/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java b/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java index 34ecbbdc..58dfb234 100644 --- a/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java +++ b/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java @@ -16,8 +16,8 @@ *
        • {@link #getColor(Level)} - Retrieves the color code associated with a specific {@link Level} of logging.
        • * *

          + * * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public interface ILogColorProvider { @@ -31,7 +31,6 @@ public interface ILogColorProvider { * @param pLevel {@link Level} - The log level for which to retrieve the color code. * @return The color code as a {@link String} for the specified log level. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ String getColor(Level pLevel); diff --git a/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java b/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java index f2a57fdd..8abb3471 100644 --- a/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java +++ b/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java @@ -21,14 +21,15 @@ *
        • {@link #getRandomVariant(List, String)} - Retrieves a random variant name from a provided list or defaults if the list is empty.
        • * *

          + * * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public interface IVariantEntity extends IVariantEntityBase { /** * A {@link RandomSource} instance used for generating random variants. + * * @co-author MeAlam, Dan * @since 1.0.0 */ @@ -42,20 +43,19 @@ public interface IVariantEntity extends IVariantEntityBase { *

          * * @param pVariantNamesList {@link List} - A {@link List} of variant names available for the entity. - * @param pDefaultVariant {@link String} - The default variant name to return if {@code pVariantNamesList} is empty. + * @param pDefaultVariant {@link String} - The default variant name to return if {@code pVariantNamesList} is empty. * @return A random variant name from the list, or the default variant if the list is empty. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ default String getRandomVariant(List pVariantNamesList, String pDefaultVariant) { if (pVariantNamesList.isEmpty()) { - BaseLogger.log(BaseLogLevel.INFO,"Variant names list is empty. Returning default variant: " + pDefaultVariant); + BaseLogger.log(BaseLogLevel.INFO, "Variant names list is empty. Returning default variant: " + pDefaultVariant); return pDefaultVariant; } int index = random.nextInt(pVariantNamesList.size()); String selectedVariant = pVariantNamesList.get(index); - BaseLogger.log(BaseLogLevel.SUCCESS,"Selected random variant: " + selectedVariant + " from list of size: " + pVariantNamesList.size()); + BaseLogger.log(BaseLogLevel.SUCCESS, "Selected random variant: " + selectedVariant + " from list of size: " + pVariantNamesList.size()); return selectedVariant; } } diff --git a/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index 2e18ee26..d8c3f2e3 100644 --- a/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -23,8 +23,8 @@ *
        • {@link #getEntityVariants(String)} - Retrieves a {@link List} of variant names for a specified entity.
        • * *

          + * * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public interface IVariantEntityBase { @@ -36,10 +36,9 @@ public interface IVariantEntityBase { *

          * * @param pModId {@link String} - The mod ID used to locate the texture. - * @param pPath {@link String} - The path to the texture within the mod. + * @param pPath {@link String} - The path to the texture within the mod. * @return A {@link ResourceLocation} pointing to the specified texture. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ default ResourceLocation getTextureLocation(String pModId, String pPath) { @@ -55,7 +54,6 @@ default ResourceLocation getTextureLocation(String pModId, String pPath) { * @param pEntityName {@link String} - The name of the entity whose variant names are to be retrieved. * @return A {@link List} containing the names of variants associated with the specified entity. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ default List getEntityVariants(String pEntityName) { @@ -63,7 +61,7 @@ default List getEntityVariants(String pEntityName) { List variantNames = variants.stream() .map(VariantParameter::getVariantName) .collect(Collectors.toList()); - BaseLogger.log(BaseLogLevel.SUCCESS,"Retrieved " + variantNames.size() + " variants for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.SUCCESS, "Retrieved " + variantNames.size() + " variants for entity: " + pEntityName); return variantNames; } } diff --git a/common/src/main/java/software/bluelib/json/JSONLoader.java b/common/src/main/java/software/bluelib/json/JSONLoader.java index f44a4c05..10b887ab 100644 --- a/common/src/main/java/software/bluelib/json/JSONLoader.java +++ b/common/src/main/java/software/bluelib/json/JSONLoader.java @@ -25,14 +25,15 @@ *
            *
          • {@link #loadJson(ResourceLocation, ResourceManager)} - Loads a JSON resource from the specified location.
          • *
          + * * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public class JSONLoader { /** * A {@code private static} {@link Gson} instance for parsing JSON data. + * * @co-author MeAlam, Dan */ private static final Gson gson = new Gson(); @@ -42,22 +43,22 @@ public class JSONLoader { * This method is typically used to load configuration files or other JSON-based resources * in a Minecraft mod environment. *

          + * * @param pResourceLocation {@link ResourceLocation} - The {@link ResourceLocation} of the JSON resource. - * @param pResourceManager {@link ResourceManager} - The {@link ResourceManager} used to load the resource. + * @param pResourceManager {@link ResourceManager} - The {@link ResourceManager} used to load the resource. * @return The loaded {@link JsonObject}. Returns an empty {@link JsonObject} if the resource is not found. * @throws RuntimeException if there is an error reading the resource. * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager pResourceManager) { - BaseLogger.log(BaseLogLevel.INFO,"Attempting to load JSON resource: " + pResourceLocation); + BaseLogger.log(BaseLogLevel.INFO, "Attempting to load JSON resource: " + pResourceLocation); try { Optional resource = pResourceManager.getResource(pResourceLocation); if (resource.isEmpty()) { - BaseLogger.log(BaseLogLevel.ERROR,"Resource not found: " + pResourceLocation); + BaseLogger.log(BaseLogLevel.ERROR, "Resource not found: " + pResourceLocation); return new JsonObject(); } @@ -65,12 +66,12 @@ public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager p InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { JsonObject jsonObject = gson.fromJson(reader, JsonObject.class); - BaseLogger.log(BaseLogLevel.SUCCESS,"Successfully loaded JSON resource: " + pResourceLocation); + BaseLogger.log(BaseLogLevel.SUCCESS, "Successfully loaded JSON resource: " + pResourceLocation); return jsonObject; } } catch (IOException pException) { RuntimeException exception = new RuntimeException("Failed to load JSON resource: " + pResourceLocation, pException); - BaseLogger.log(BaseLogLevel.ERROR,"Failed to load JSON resource: " + pResourceLocation, exception); + BaseLogger.log(BaseLogLevel.ERROR, "Failed to load JSON resource: " + pResourceLocation, exception); throw exception; } } diff --git a/common/src/main/java/software/bluelib/json/JSONMerger.java b/common/src/main/java/software/bluelib/json/JSONMerger.java index 5cde178c..d2adefde 100644 --- a/common/src/main/java/software/bluelib/json/JSONMerger.java +++ b/common/src/main/java/software/bluelib/json/JSONMerger.java @@ -23,8 +23,8 @@ *

        • {@link #mergeJsonObjects(JsonObject, JsonObject)} - Merges the data from the source JSON object into the target JSON object.
        • * *

          + * * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public class JSONMerger { @@ -40,7 +40,7 @@ public class JSONMerger { * @param pSource {@link JsonObject} - The source {@link JsonObject} to merge data from. This object is not modified by the operation. */ public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { - BaseLogger.log(BaseLogLevel.INFO,"Starting JSON merge operation."); + BaseLogger.log(BaseLogLevel.INFO, "Starting JSON merge operation."); for (Map.Entry entry : pSource.entrySet()) { String key = entry.getKey(); @@ -57,17 +57,17 @@ public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { targetArray.add(element); } - BaseLogger.log(BaseLogLevel.ERROR,"Merged array for key: " + key); + BaseLogger.log(BaseLogLevel.ERROR, "Merged array for key: " + key); } else { pTarget.add(key, sourceElement); - BaseLogger.log(BaseLogLevel.WARNING,"Overwriting value for key: " + key); + BaseLogger.log(BaseLogLevel.WARNING, "Overwriting value for key: " + key); } } else { pTarget.add(key, sourceElement); - BaseLogger.log(BaseLogLevel.SUCCESS,"Added new key: " + key); + BaseLogger.log(BaseLogLevel.SUCCESS, "Added new key: " + key); } } - BaseLogger.log(BaseLogLevel.SUCCESS,"JSON merge operation completed."); + BaseLogger.log(BaseLogLevel.SUCCESS, "JSON merge operation completed."); } } diff --git a/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java b/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java index 5298977c..7f6a67a4 100644 --- a/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java +++ b/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java @@ -39,6 +39,7 @@ public class LivingEntityMixin implements IVariantAccessor { /** * A {@link EntityDataAccessor} to hold the entity's variant name, which is synchronized * across clients and servers using {@link SynchedEntityData}. + * * @co-author MeAlam * @since 1.0.0 */ @@ -51,7 +52,7 @@ public class LivingEntityMixin implements IVariantAccessor { * the synchronized data that will hold the entity's variant information. * * @param pBuilder {@link SynchedEntityData.Builder} - The builder to define entity data. - * @param pCi {@link CallbackInfo} - Callback information for the injection process. + * @param pCi {@link CallbackInfo} - Callback information for the injection process. * @author MeAlam * @since 1.0.0 */ @@ -65,7 +66,7 @@ protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder, Ca * the entity's variant in NBT data when saving the entity. * * @param pCompound {@link CompoundTag} - The NBT tag to save the entity's variant information. - * @param pCi {@link CallbackInfo} - Callback information for the injection process. + * @param pCi {@link CallbackInfo} - Callback information for the injection process. * @author MeAlam * @since 1.0.0 */ @@ -79,7 +80,7 @@ public void addAdditionalSaveData(@NotNull CompoundTag pCompound, CallbackInfo p * the entity's variant from NBT data when loading the entity. * * @param pCompound {@link CompoundTag} - The NBT tag containing the entity's variant information. - * @param pCi {@link CallbackInfo} - Callback information for the injection process. + * @param pCi {@link CallbackInfo} - Callback information for the injection process. * @author MeAlam * @since 1.0.0 */ diff --git a/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java b/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java index 0d6f3707..7e98dd7c 100644 --- a/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java +++ b/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java @@ -23,6 +23,7 @@ *
        • {@link #stringToDate(String, String)} - Converts a string to a {@link Date} object.
        • *
        • {@link #dateToString(Date, String)} - Converts a {@link Date} object to a string.
        • * + * * @author MeAlam * @since 1.0.0 */ @@ -101,7 +102,7 @@ public static double milesToKilometers(double pMiles) { * A {@link Date} that converts a string to a {@link Date} object. * * @param pDateStr {@link String} - The date in string format (e.g., "yyyy-MM-dd"). - * @param pFormat {@link String} - The format of the input date string. + * @param pFormat {@link String} - The format of the input date string. * @return The corresponding {@code Date} object. * @throws ParseException if the string cannot be parsed. * @author MeAlam @@ -112,7 +113,7 @@ public static Date stringToDate(String pDateStr, String pFormat) throws ParseExc SimpleDateFormat formatter = new SimpleDateFormat(pFormat); return formatter.parse(pDateStr); } catch (ParseException pException) { - BaseLogger.log(BaseLogLevel.ERROR,"Error parsing date string: " + pDateStr + " with format: " + pFormat, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error parsing date string: " + pDateStr + " with format: " + pFormat, pException); throw pException; } } @@ -120,7 +121,7 @@ public static Date stringToDate(String pDateStr, String pFormat) throws ParseExc /** * A {@link String} that converts a {@link Date} object to a string in a specified format. * - * @param pDate {@link Date} - The date to be converted. + * @param pDate {@link Date} - The date to be converted. * @param pFormat {@link String} - The desired date format (e.g., "yyyy-MM-dd"). * @return The date as a string in the specified format. * @author MeAlam @@ -131,7 +132,7 @@ public static String dateToString(Date pDate, String pFormat) { SimpleDateFormat formatter = new SimpleDateFormat(pFormat); return formatter.format(pDate); } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR,"Error formatting date: " + pDate.toString() + " with format: " + pFormat, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error formatting date: " + pDate.toString() + " with format: " + pFormat, pException); return pException.getMessage(); } } diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java index de34f76b..8fb96380 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java @@ -16,40 +16,51 @@ *
        • {@link #SUCCESS} - Custom log level for indicating successful operations.
        • *
        • {@link #BLUELIB} - Custom log level specific to BlueLib.
        • * + * * @author MeAlam * @since 1.0.0 */ public class BaseLogLevel { /** * Standard informational log level. + * * @co-author MeAlam * @since 1.0.0 */ - public static final Level INFO = new Level("INFO", Level.INFO.intValue()) {}; + public static final Level INFO = new Level("INFO", Level.INFO.intValue()) { + }; /** * Log level for error messages. + * * @co-author MeAlam * @since 1.0.0 */ - public static final Level ERROR = new Level("ERROR", Level.SEVERE.intValue()) {}; + public static final Level ERROR = new Level("ERROR", Level.SEVERE.intValue()) { + }; /** * Log level for warning messages. + * * @co-author MeAlam * @since 1.0.0 */ - public static final Level WARNING = new Level("WARNING", Level.WARNING.intValue()) {}; + public static final Level WARNING = new Level("WARNING", Level.WARNING.intValue()) { + }; /** * Custom log level for indicating successful operations. + * * @co-author MeAlam * @since 1.0.0 */ - public static final Level SUCCESS = new Level("SUCCESS", Level.INFO.intValue() + 50) {}; + public static final Level SUCCESS = new Level("SUCCESS", Level.INFO.intValue() + 50) { + }; /** * Custom log level specific to BlueLib. + * * @co-author MeAlam * @since 1.0.0 */ - public static final Level BLUELIB = new Level("BlueLib Developer", Level.INFO.intValue() + 50) {}; + public static final Level BLUELIB = new Level("BlueLib Developer", Level.INFO.intValue() + 50) { + }; } diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java index 4b2d3bc5..bc3cb296 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -23,13 +23,13 @@ * * * @author MeAlam - * @co-author Dan * @since 1.0.0 */ public class BaseLogger { /** * A {@link Logger} instance for logging messages. + * * @co-author MeAlam * @since 1.0.0 */ @@ -38,6 +38,7 @@ public class BaseLogger { //FIXME: Set to false before release /** * A {@link Boolean} to enable or disable BlueLib specific logging. + * * @co-author MeAlam * @since 1.0.0 */ @@ -45,6 +46,7 @@ public class BaseLogger { /** * A {@link Boolean} to enable or disable general logging. + * * @co-author MeAlam * @since 1.0.0 */ @@ -101,8 +103,8 @@ public static void setLoggingEnabled(boolean pEnabled) { /** * A {@code void} that logs a message with an associated {@link Throwable} if {@code BlueLib} logging is enabled. * - * @param pLogLevel {@link Level} - The logging level to use. - * @param pMessage {@link String} - The message to log. + * @param pLogLevel {@link Level} - The logging level to use. + * @param pMessage {@link String} - The message to log. * @param pThrowable {@link Throwable} - The throwable to log with the message. * @param pIsBlueLib {@link boolean} - Indicates if the message is {@code BlueLib} specific. * @co-author MeAlam @@ -117,8 +119,8 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, b /** * A {@code void} that logs a message if BlueLib logging is enabled. * - * @param pLogLevel {@link Level} - The logging level to use. - * @param pMessage {@link String} - The message to log. + * @param pLogLevel {@link Level} - The logging level to use. + * @param pMessage {@link String} - The message to log. * @param pIsBlueLib {@link boolean} - Indicates if the message is {@code BlueLib} specific. * @co-author MeAlam * @since 1.0.0 @@ -132,8 +134,8 @@ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { /** * A {@code void} that logs a message with an associated {@link Throwable} if general logging is enabled. * - * @param pLogLevel {@link Level} - The logging level to use. - * @param pMessage {@link String} - The message to log. + * @param pLogLevel {@link Level} - The logging level to use. + * @param pMessage {@link String} - The message to log. * @param pThrowable {@link Throwable} - The throwable to log with the message. * @co-author MeAlam * @since 1.0.0 @@ -148,7 +150,7 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { * A {@code void} that logs a message if general logging is enabled. * * @param pLogLevel {@link Level} - The logging level to use. - * @param pMessage {@link String} - The message to log. + * @param pMessage {@link String} - The message to log. * @co-author MeAlam * @since 1.0.0 */ diff --git a/common/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java b/common/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java index 81d5f0a0..ede066e1 100644 --- a/common/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java +++ b/common/src/main/java/software/bluelib/utils/logging/DefaultLogColorProvider.java @@ -18,6 +18,7 @@ *
        • {@link BaseLogLevel#SUCCESS} - Green color.
        • *
        • {@link BaseLogLevel#BLUELIB} - Green color.
        • * + * * @author MeAlam * @since 1.0.0 */ diff --git a/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java b/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java index 0c794f21..c9b679f3 100644 --- a/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java +++ b/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java @@ -28,6 +28,7 @@ public abstract class LoggerConfig { /** * ANSI color codes for console output. + * * @co-author MeAlam * @since 1.0.0 */ @@ -35,6 +36,7 @@ public abstract class LoggerConfig { /** * ANSI color codes for console output. + * * @co-author MeAlam * @since 1.0.0 */ @@ -42,6 +44,7 @@ public abstract class LoggerConfig { /** * ANSI color codes for console output. + * * @co-author MeAlam * @since 1.0.0 */ @@ -49,6 +52,7 @@ public abstract class LoggerConfig { /** * ANSI color codes for console output. + * * @co-author MeAlam * @since 1.0.0 */ @@ -56,6 +60,7 @@ public abstract class LoggerConfig { /** * ANSI color codes for console output. + * * @co-author MeAlam * @since 1.0.0 */ @@ -65,7 +70,7 @@ public abstract class LoggerConfig { * A {@link Logger} configuration method that sets up a {@link ConsoleHandler} * with custom color formatting based on log level using the provided {@link ILogColorProvider}. * - * @param pLogger {@link Logger} - The logger instance to be configured. + * @param pLogger {@link Logger} - The logger instance to be configured. * @param pColorProvider {@link ILogColorProvider} - Provides color codes for different log levels. * @author MeAlam * @since 1.0.0 diff --git a/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java b/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java index 2ed8a4e6..b4156484 100644 --- a/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java @@ -20,6 +20,7 @@ *
        • {@link #calculateGCD(int, int)} - Calculates the greatest common divisor of two integers.
        • *
        • {@link #generatePowerSet(Set)} - Generates the power set of a given set.
        • * + * * @author MeAlam * @since 1.0.0 */ @@ -40,7 +41,7 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { double discriminant = pB * pB - 4 * pA * pC; if (discriminant < 0) { - BaseLogger.log(BaseLogLevel.WARNING,"No real roots found for the quadratic equation."); + BaseLogger.log(BaseLogLevel.WARNING, "No real roots found for the quadratic equation."); return new double[0]; } @@ -48,8 +49,8 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { double root1 = (-pB + sqrtDiscriminant) / (2 * pA); double root2 = (-pB - sqrtDiscriminant) / (2 * pA); - BaseLogger.log(BaseLogLevel.INFO,"Roots found: root1=" + root1 + ", root2=" + root2); - return new double[] { root1, root2 }; + BaseLogger.log(BaseLogLevel.INFO, "Roots found: root1=" + root1 + ", root2=" + root2); + return new double[]{root1, root2}; } /** @@ -64,7 +65,7 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { public static long factorial(int pNumber) { if (pNumber < 0) { IllegalArgumentException exception = new IllegalArgumentException("Number must be non-negative."); - BaseLogger.log(BaseLogLevel.INFO,"Attempted to calculate factorial of a negative number: " + pNumber, exception); + BaseLogger.log(BaseLogLevel.INFO, "Attempted to calculate factorial of a negative number: " + pNumber, exception); throw exception; } @@ -73,7 +74,7 @@ public static long factorial(int pNumber) { result *= i; } - BaseLogger.log(BaseLogLevel.SUCCESS,"Factorial of " + pNumber + " is " + result); + BaseLogger.log(BaseLogLevel.SUCCESS, "Factorial of " + pNumber + " is " + result); return result; } @@ -94,7 +95,7 @@ public static int calculateGCD(int pA, int pB) { pA = temp; } - BaseLogger.log(BaseLogLevel.SUCCESS,"GCD found: " + pA); + BaseLogger.log(BaseLogLevel.SUCCESS, "GCD found: " + pA); return pA; } @@ -102,7 +103,7 @@ public static int calculateGCD(int pA, int pB) { * A {@link List} that generates the power set (all subsets) of a given set. * * @param pSet {@link Set} - The input set. - * @param The type of elements in the set. + * @param The type of elements in the set. * @return A list of all subsets of the input set. * @author MeAlam * @since 1.0.0 @@ -121,7 +122,7 @@ public static List> generatePowerSet(Set pSet) { powerSet.addAll(newSubsets); } - BaseLogger.log(BaseLogLevel.SUCCESS,"Power set generated with " + powerSet.size() + " subsets."); + BaseLogger.log(BaseLogLevel.SUCCESS, "Power set generated with " + powerSet.size() + " subsets."); return powerSet; } } diff --git a/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java b/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java index a1bca98f..e71ba71e 100644 --- a/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java @@ -23,6 +23,7 @@ *
        • {@link #calculateCylinderVolume(double, double)} - Calculates the volume of a cylinder given its radius and height.
        • *
        • {@link #calculateConeSurfaceArea(double, double)} - Calculates the surface area of a cone given its radius and slant height.
        • * + * * @author MeAlam * @since 1.0.0 */ @@ -76,7 +77,7 @@ public static double calculateDistance3D(double pX1, double pY1, double pZ1, dou public static double calculateCircleArea(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR,"Error calculating circle area", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating circle area", throwable); return Double.NaN; } return Math.PI * pRadius * pRadius; @@ -93,7 +94,7 @@ public static double calculateCircleArea(double pRadius) { public static double calculateCircleCircumference(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR,"Error calculating circle circumference", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating circle circumference", throwable); return Double.NaN; } return 2 * Math.PI * pRadius; @@ -102,7 +103,7 @@ public static double calculateCircleCircumference(double pRadius) { /** * A {@link Double} that calculates the area of a rectangle given its width and height. * - * @param pWidth {@link Double} - The width of the rectangle. + * @param pWidth {@link Double} - The width of the rectangle. * @param pHeight {@link Double} - The height of the rectangle. * @return The area of the rectangle. * @author MeAlam @@ -111,7 +112,7 @@ public static double calculateCircleCircumference(double pRadius) { public static double calculateRectangleArea(double pWidth, double pHeight) { if (pWidth < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Width and height must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR,"Error calculating rectangle area", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating rectangle area", throwable); return Double.NaN; } return pWidth * pHeight; @@ -120,7 +121,7 @@ public static double calculateRectangleArea(double pWidth, double pHeight) { /** * A {@link Double} that calculates the perimeter of a rectangle given its width and height. * - * @param pWidth {@link Double} - The width of the rectangle. + * @param pWidth {@link Double} - The width of the rectangle. * @param pHeight {@link Double} - The height of the rectangle. * @return The perimeter of the rectangle. * @author MeAlam @@ -129,7 +130,7 @@ public static double calculateRectangleArea(double pWidth, double pHeight) { public static double calculateRectanglePerimeter(double pWidth, double pHeight) { if (pWidth < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Width and height must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR,"Error calculating rectangle perimeter", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating rectangle perimeter", throwable); return Double.NaN; } return 2 * (pWidth + pHeight); @@ -138,7 +139,7 @@ public static double calculateRectanglePerimeter(double pWidth, double pHeight) /** * A {@link Double} that calculates the area of a triangle given its base and height. * - * @param pBase {@link Double} - The base of the triangle. + * @param pBase {@link Double} - The base of the triangle. * @param pHeight {@link Double} - The height of the triangle. * @return The area of the triangle. * @since 1.0.0 @@ -146,7 +147,7 @@ public static double calculateRectanglePerimeter(double pWidth, double pHeight) public static double calculateTriangleArea(double pBase, double pHeight) { if (pBase < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Base and height must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR,"Error calculating triangle area", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating triangle area", throwable); return Double.NaN; } return 0.5 * pBase * pHeight; @@ -164,7 +165,7 @@ public static double calculateTriangleArea(double pBase, double pHeight) { public static double calculateTrianglePerimeter(double pSide1, double pSide2, double pSide3) { if (pSide1 < 0 || pSide2 < 0 || pSide3 < 0) { Throwable throwable = new IllegalArgumentException("Sides must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR,"Error calculating triangle perimeter", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating triangle perimeter", throwable); return Double.NaN; } return pSide1 + pSide2 + pSide3; @@ -181,7 +182,7 @@ public static double calculateTrianglePerimeter(double pSide1, double pSide2, do public static double calculateSphereVolume(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR,"Error calculating sphere volume", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating sphere volume", throwable); return Double.NaN; } return (4.0 / 3.0) * Math.PI * Math.pow(pRadius, 3); @@ -198,7 +199,7 @@ public static double calculateSphereVolume(double pRadius) { public static double calculateCubeSurfaceArea(double pSideLength) { if (pSideLength < 0) { Throwable throwable = new IllegalArgumentException("Side length must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR,"Error calculating cube surface area", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating cube surface area", throwable); return Double.NaN; } return 6 * Math.pow(pSideLength, 2); @@ -216,7 +217,7 @@ public static double calculateCubeSurfaceArea(double pSideLength) { public static double calculateCylinderVolume(double pRadius, double pHeight) { if (pRadius < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Radius and height must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR,"Error calculating cylinder volume", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating cylinder volume", throwable); return Double.NaN; } return Math.PI * Math.pow(pRadius, 2) * pHeight; @@ -225,7 +226,7 @@ public static double calculateCylinderVolume(double pRadius, double pHeight) { /** * A {@link Double} that calculates the surface area of a cone given its radius and slant height. * - * @param pRadius {@link Double} - The radius of the base of the cone. + * @param pRadius {@link Double} - The radius of the base of the cone. * @param pSlantHeight {@link Double} - The slant height of the cone. * @return The surface area of the cone. * @author MeAlam @@ -234,7 +235,7 @@ public static double calculateCylinderVolume(double pRadius, double pHeight) { public static double calculateConeSurfaceArea(double pRadius, double pSlantHeight) { if (pRadius < 0 || pSlantHeight < 0) { Throwable throwable = new IllegalArgumentException("Radius and slant height must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR,"Error calculating cone surface area", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating cone surface area", throwable); return Double.NaN; } return Math.PI * pRadius * (pRadius + pSlantHeight); diff --git a/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java b/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java index 6f98d358..cde59e87 100644 --- a/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java @@ -15,6 +15,7 @@ *
        • {@link #calculate2x2MatrixDeterminant(double[][])} - Calculates the determinant of a 2x2 matrix.
        • *
        • {@link #invert2x2Matrix(double[][])} - Calculates the inverse of a 2x2 matrix.
        • * + * * @author MeAlam * @since 1.0.0 */ @@ -36,7 +37,7 @@ public static double[][] multiplyMatrices(double[][] pMatrixA, double[][] pMatri int colsB = pMatrixB[0].length; if (colsA != pMatrixB.length) { Throwable throwable = new IllegalArgumentException("Number of columns in the first matrix must be equal to the number of rows in the second matrix."); - BaseLogger.log(BaseLogLevel.ERROR,"Error performing matrix multiplication", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error performing matrix multiplication", throwable); return new double[0][0]; } double[][] result = new double[rowsA][colsB]; @@ -82,7 +83,7 @@ public static double[][] transposeMatrix(double[][] pMatrix) { public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { if (pMatrix.length != 2 || pMatrix[0].length != 2) { Throwable throwable = new IllegalArgumentException("Matrix must be 2x2."); - BaseLogger.log(BaseLogLevel.ERROR,"Error calculating 2x2 matrix determinant", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating 2x2 matrix determinant", throwable); return Double.NaN; } return pMatrix[0][0] * pMatrix[1][1] - pMatrix[0][1] * pMatrix[1][0]; @@ -100,13 +101,13 @@ public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { public static double[][] invert2x2Matrix(double[][] pMatrix) { if (pMatrix.length != 2 || pMatrix[0].length != 2) { Throwable throwable = new IllegalArgumentException("Matrix must be 2x2."); - BaseLogger.log(BaseLogLevel.ERROR,"Error inverting 2x2 matrix", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error inverting 2x2 matrix", throwable); return new double[0][0]; } double determinant = calculate2x2MatrixDeterminant(pMatrix); if (determinant == 0) { Throwable throwable = new IllegalArgumentException("Matrix is not invertible."); - BaseLogger.log(BaseLogLevel.ERROR,"Error inverting 2x2 matrix", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error inverting 2x2 matrix", throwable); return new double[0][0]; } double[][] inverse = new double[2][2]; diff --git a/common/src/main/java/software/bluelib/utils/math/MiscUtils.java b/common/src/main/java/software/bluelib/utils/math/MiscUtils.java index b1bbd8ad..8f576256 100644 --- a/common/src/main/java/software/bluelib/utils/math/MiscUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/MiscUtils.java @@ -15,6 +15,7 @@ *
        • {@link #calculateLevenshteinDistance(String, String)} - Calculates the Levenshtein distance between two strings.
        • *
        • {@link #hexToRGB(String)} - Converts a hexadecimal color code to an RGB array.
        • * + * * @author MeAlam * @since 1.0.0 */ @@ -36,7 +37,7 @@ public static boolean isValidEmail(String pEmail) { /** * A {@link Integer} that converts a string to an integer, returning a default value if the string is not a valid integer. * - * @param pString {@link String} - The string to be converted. + * @param pString {@link String} - The string to be converted. * @param pDefaultValue {@link Integer} - The default value to return if the string is not a valid integer. * @return The integer value of the string, or {@code pDefaultValue} if the string is not a valid integer. * @author MeAlam @@ -46,7 +47,7 @@ public static int stringToIntWithDefault(String pString, int pDefaultValue) { try { return Integer.parseInt(pString); } catch (NumberFormatException pException) { - BaseLogger.log(BaseLogLevel.ERROR,"Error converting string to integer", pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error converting string to integer", pException); return pDefaultValue; } } @@ -92,7 +93,7 @@ public static int calculateLevenshteinDistance(String pStr1, String pStr2) { public static int[] hexToRGB(String pHex) { if (pHex == null || pHex.isEmpty()) { Throwable throwable = new IllegalArgumentException("Hex color code cannot be null or empty."); - BaseLogger.log(BaseLogLevel.ERROR,"Error converting hex to RGB", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error converting hex to RGB", throwable); return new int[]{0, 0, 0}; } if (pHex.charAt(0) == '#') { @@ -100,7 +101,7 @@ public static int[] hexToRGB(String pHex) { } if (pHex.length() != 6) { Throwable throwable = new IllegalArgumentException("Invalid hex color code."); - BaseLogger.log(BaseLogLevel.ERROR,"Error converting hex to RGB", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error converting hex to RGB", throwable); return new int[]{0, 0, 0}; } try { @@ -109,7 +110,7 @@ public static int[] hexToRGB(String pHex) { int b = Integer.parseInt(pHex.substring(4, 6), 16); return new int[]{r, g, b}; } catch (NumberFormatException pException) { - BaseLogger.log(BaseLogLevel.ERROR,"Error parsing hex color code to RGB", pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error parsing hex color code to RGB", pException); return new int[]{0, 0, 0}; } } diff --git a/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java index 1d0ebf7a..6fd69180 100644 --- a/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java @@ -27,6 +27,7 @@ * or minimum values greater than maximum values) and returns default values (e.g., `0` for integers and `"unknown"` for strings) * in such cases. *

          + * * @author MeAlam * @since 1.0.0 */ @@ -44,10 +45,10 @@ public class RandomGenUtils { public static int generateRandomInt(int pMin, int pMax) { if (pMin > pMax) { Throwable throwable = new IllegalArgumentException("Minimum value must not be greater than maximum value."); - BaseLogger.log(BaseLogLevel.WARNING,"Error generating random integer", throwable); + BaseLogger.log(BaseLogLevel.WARNING, "Error generating random integer", throwable); return 0; } - return pMin + (int)(Math.random() * (pMax - pMin + 1)); + return pMin + (int) (Math.random() * (pMax - pMin + 1)); } /** @@ -62,7 +63,7 @@ public static int generateRandomInt(int pMin, int pMax) { public static double generateRandomDouble(double pMin, double pMax) { if (pMin > pMax) { Throwable throwable = new IllegalArgumentException("Minimum value must not be greater than maximum value."); - BaseLogger.log(BaseLogLevel.WARNING,"Error generating random double", throwable); + BaseLogger.log(BaseLogLevel.WARNING, "Error generating random double", throwable); return 0; } return pMin + Math.random() * (pMax - pMin); @@ -91,7 +92,7 @@ public static boolean generateRandomBoolean() { public static String generateRandomString(int pLength) { if (pLength < 0) { Throwable throwable = new IllegalArgumentException("Length must be non-negative."); - BaseLogger.log(BaseLogLevel.WARNING,"Error generating random string", throwable); + BaseLogger.log(BaseLogLevel.WARNING, "Error generating random string", throwable); return "unknown"; } String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -115,7 +116,7 @@ public static String generateRandomString(int pLength) { public static String generateRandomStringWithPrefix(String pPrefix, int pLength) { if (pLength < 0) { Throwable throwable = new IllegalArgumentException("Length must be non-negative."); - BaseLogger.log(BaseLogLevel.WARNING,"Error generating random string with prefix", throwable); + BaseLogger.log(BaseLogLevel.WARNING, "Error generating random string with prefix", throwable); return "unknown"; } return pPrefix + generateRandomString(pLength - pPrefix.length()); diff --git a/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java index e8690b26..144ba773 100644 --- a/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java @@ -32,6 +32,7 @@ * Each method logs a success message with the computed value or a warning if the input array is empty. * The logging is done via {@link BaseLogger}, ensuring that any issues or results are recorded appropriately. *

          + * * @author MeAlam * @since 1.0.0 */ @@ -50,7 +51,7 @@ public class StatisticalUtils { */ public static double calculateMean(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, mean calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, mean calculation might fail."); return 0; } @@ -59,7 +60,7 @@ public static double calculateMean(double[] pValues) { sum += value; } double mean = sum / pValues.length; - BaseLogger.log(BaseLogLevel.SUCCESS,"Mean successfully calculated: " + mean); + BaseLogger.log(BaseLogLevel.SUCCESS, "Mean successfully calculated: " + mean); return mean; } @@ -76,7 +77,7 @@ public static double calculateMean(double[] pValues) { */ public static double calculateMedian(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, median calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, median calculation might fail."); return 0; } @@ -87,7 +88,7 @@ public static double calculateMedian(double[] pValues) { (sorted[middle - 1] + sorted[middle]) / 2.0 : sorted[middle]; - BaseLogger.log(BaseLogLevel.SUCCESS,"Median successfully calculated: " + median); + BaseLogger.log(BaseLogLevel.SUCCESS, "Median successfully calculated: " + median); return median; } @@ -104,7 +105,7 @@ public static double calculateMedian(double[] pValues) { */ public static double calculateMode(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, mode calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, mode calculation might fail."); return 0; } @@ -122,7 +123,7 @@ public static double calculateMode(double[] pValues) { } } - BaseLogger.log(BaseLogLevel.SUCCESS,"Mode successfully calculated: " + mode); + BaseLogger.log(BaseLogLevel.SUCCESS, "Mode successfully calculated: " + mode); return mode; } @@ -139,7 +140,7 @@ public static double calculateMode(double[] pValues) { */ public static double calculateStandardDeviation(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, standard deviation calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, standard deviation calculation might fail."); return 0; } @@ -149,7 +150,7 @@ public static double calculateStandardDeviation(double[] pValues) { sumSquaredDifferences += Math.pow(value - mean, 2); } double stdDev = Math.sqrt(sumSquaredDifferences / pValues.length); - BaseLogger.log(BaseLogLevel.SUCCESS,"Standard deviation successfully calculated: " + stdDev); + BaseLogger.log(BaseLogLevel.SUCCESS, "Standard deviation successfully calculated: " + stdDev); return stdDev; } @@ -166,7 +167,7 @@ public static double calculateStandardDeviation(double[] pValues) { */ public static double calculateVariance(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, variance calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, variance calculation might fail."); return 0; } @@ -176,7 +177,7 @@ public static double calculateVariance(double[] pValues) { sumSquaredDifferences += Math.pow(value - mean, 2); } double variance = sumSquaredDifferences / pValues.length; - BaseLogger.log(BaseLogLevel.SUCCESS,"Variance successfully calculated: " + variance); + BaseLogger.log(BaseLogLevel.SUCCESS, "Variance successfully calculated: " + variance); return variance; } @@ -193,14 +194,14 @@ public static double calculateVariance(double[] pValues) { */ public static double calculateRange(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, range calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, range calculation might fail."); return 0; } double max = Arrays.stream(pValues).max().orElseThrow(); double min = Arrays.stream(pValues).min().orElseThrow(); double range = max - min; - BaseLogger.log(BaseLogLevel.SUCCESS,"Range successfully calculated: " + range); + BaseLogger.log(BaseLogLevel.SUCCESS, "Range successfully calculated: " + range); return range; } @@ -217,14 +218,14 @@ public static double calculateRange(double[] pValues) { */ public static double calculateCoefficientOfVariation(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING,"Array is empty, coefficient of variation calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, coefficient of variation calculation might fail."); return 0; } double mean = calculateMean(pValues); double stdDev = calculateStandardDeviation(pValues); double coefficient = (stdDev / mean) * 100; - BaseLogger.log(BaseLogLevel.SUCCESS,"Coefficient of variation successfully calculated: " + coefficient); + BaseLogger.log(BaseLogLevel.SUCCESS, "Coefficient of variation successfully calculated: " + coefficient); return coefficient; } } diff --git a/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java b/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java index f98a62b4..5d6f7efb 100644 --- a/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java +++ b/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java @@ -32,8 +32,9 @@ *
        • {@link #getChunkBlockCount(Level, ChunkPos)} - Counts the number of non-air blocks in the specified chunk.
        • * *

          - * @since 1.0.0 + * * @author MeAlam + * @since 1.0.0 */ public class ChunkUtils { @@ -44,7 +45,7 @@ public class ChunkUtils { * and an error message if an exception occurs. *

          * - * @param pLevel {@link Level} - The game world level. + * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return The {@link Biome} associated with the specified chunk. * @throws RuntimeException if there is an error retrieving the biome. @@ -52,10 +53,10 @@ public class ChunkUtils { public static Biome getBiomeOfChunk(Level pLevel, ChunkPos pChunkPos) { try { Biome biome = pLevel.getBiome(pChunkPos.getWorldPosition()).value(); - BaseLogger.log(BaseLogLevel.INFO,"Retrieved biome for chunk at position " + pChunkPos + ": " + biome); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved biome for chunk at position " + pChunkPos + ": " + biome); return biome; } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR,"Error retrieving biome for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving biome for chunk at position " + pChunkPos, pException); throw pException; } } @@ -67,7 +68,7 @@ public static Biome getBiomeOfChunk(Level pLevel, ChunkPos pChunkPos) { * Example: "minecraft:plains", "minecraft:desert" *

          * - * @param pLevel {@link Level} - The game world level. + * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return The registry name of the chunk's biome as a {@link String}. * @throws RuntimeException if there is an error retrieving the biome registry name. @@ -79,11 +80,11 @@ public static String getBiomeRegistryNameOfChunk(Level pLevel, ChunkPos pChunkPo if (biomeKey == null) { NullPointerException exception = new NullPointerException("Biome at chunk position " + pChunkPos + " is null"); - BaseLogger.log(BaseLogLevel.ERROR,"Error retrieving biome registry name of chunk at " + pChunkPos, exception); + BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving biome registry name of chunk at " + pChunkPos, exception); return exception.getMessage(); } - BaseLogger.log(BaseLogLevel.SUCCESS,"Retrieved biome registry name for chunk at position " + pChunkPos + ": " + biomeKey); + BaseLogger.log(BaseLogLevel.SUCCESS, "Retrieved biome registry name for chunk at position " + pChunkPos + ": " + biomeKey); return biomeKey.toString(); } @@ -94,7 +95,7 @@ public static String getBiomeRegistryNameOfChunk(Level pLevel, ChunkPos pChunkPo * Example: "plains", "desert" *

          * - * @param pLevel {@link Level} - The game world level. + * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return The simple name of the chunk's biome. */ @@ -110,7 +111,7 @@ public static String getBiomeSimpleNameOfChunk(Level pLevel, ChunkPos pChunkPos) * and an error message if an exception occurs. *

          * - * @param pLevel {@link Level} - The game world level. + * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return A collection of tile entities present in the specified chunk. * @throws RuntimeException if there is an error retrieving tile entities. @@ -119,10 +120,10 @@ public static Collection getChunkTileEntities(Level pLevel, ChunkPo try { LevelChunk chunk = pLevel.getChunk(pChunkPos.x, pChunkPos.z); Collection tileEntities = chunk.getBlockEntities().values(); - BaseLogger.log(BaseLogLevel.INFO,"Retrieved " + tileEntities.size() + " tile entities for chunk at position " + pChunkPos); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved " + tileEntities.size() + " tile entities for chunk at position " + pChunkPos); return tileEntities; } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR,"Error retrieving tile entities for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving tile entities for chunk at position " + pChunkPos, pException); throw pException; } } @@ -134,7 +135,7 @@ public static Collection getChunkTileEntities(Level pLevel, ChunkPo * Example: "minecraft:chest, minecraft:furnace" *

          * - * @param pLevel {@link Level} - The game world level. + * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return A comma-separated string of tile entity registry names in the chunk. * @throws RuntimeException if there is an error retrieving tile entity registry names. @@ -152,10 +153,10 @@ public static String getChunkTileEntitiesRegistryNames(Level pLevel, ChunkPos pC }) .collect(Collectors.joining(", ")); - BaseLogger.log(BaseLogLevel.INFO,"Tile entities for chunk at position " + pChunkPos + ": " + registryNames); + BaseLogger.log(BaseLogLevel.INFO, "Tile entities for chunk at position " + pChunkPos + ": " + registryNames); return registryNames; } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR,"Error retrieving tile entity registry names for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving tile entity registry names for chunk at position " + pChunkPos, pException); throw pException; } } @@ -166,7 +167,7 @@ public static String getChunkTileEntitiesRegistryNames(Level pLevel, ChunkPos pC * Example: "chest, furnace" *

          * - * @param pLevel {@link Level} - The game world level. + * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return A comma-separated string of tile entity simple names in the chunk. */ @@ -185,7 +186,7 @@ public static String getChunkTileEntitiesSimpleNames(Level pLevel, ChunkPos pChu * and an error message if an exception occurs. *

          * - * @param pLevel {@link Level} - The game world level. + * @param pLevel {@link Level} - The game world level. * @param pChunkPos {@link ChunkPos} - The position of the chunk. * @return The number of non-air blocks in the specified chunk. * @throws RuntimeException if there is an error counting blocks. @@ -206,25 +207,25 @@ public static int getChunkBlockCount(Level pLevel, ChunkPos pChunkPos) { } } - BaseLogger.log(BaseLogLevel.INFO,"Non-air block count for chunk at position " + pChunkPos + ": " + blockCount); + BaseLogger.log(BaseLogLevel.INFO, "Non-air block count for chunk at position " + pChunkPos + ": " + blockCount); return blockCount; } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR,"Error counting blocks for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error counting blocks for chunk at position " + pChunkPos, pException); throw pException; } } /** FIXME: This method is not working as expected. It is not returning correctly. - public static boolean isChunkLoaded(final LevelAccessor pWorld, final int pX, final int pZ) { - try { - boolean isLoaded = pWorld.getChunk(pX, pZ, ChunkStatus.FULL, false) != null; - BaseLogger.bluelibLogSuccess("Chunk at (" + pX + ", " + pZ + ") is loaded: " + isLoaded); - return isLoaded; - } catch (Exception e) { - BaseLogger.logError("Error checking if chunk at (" + pX + ", " + pZ + ") is loaded", e); - return false; - } - } + public static boolean isChunkLoaded(final LevelAccessor pWorld, final int pX, final int pZ) { + try { + boolean isLoaded = pWorld.getChunk(pX, pZ, ChunkStatus.FULL, false) != null; + BaseLogger.bluelibLogSuccess("Chunk at (" + pX + ", " + pZ + ") is loaded: " + isLoaded); + return isLoaded; + } catch (Exception e) { + BaseLogger.logError("Error checking if chunk at (" + pX + ", " + pZ + ") is loaded", e); + return false; + } + } */ diff --git a/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java index 020bd929..495a71bd 100644 --- a/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java +++ b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java @@ -30,11 +30,10 @@ * *

          * - * @since 1.0.0 * @author MeAlam - * @co-author Dan * @version 1.0.0 - * @see software.bluelib.entity.variant.VariantParameter + * @see VariantParameter + * @since 1.0.0 */ public class ParameterUtils { @@ -45,8 +44,8 @@ public class ParameterUtils { * representing custom parameters for that variant. *

          * - * @since 1.0.0 * @co-author MeAlam, Dan + * @since 1.0.0 */ private static final Map> variantParametersMap = new HashMap<>(); @@ -56,12 +55,11 @@ public class ParameterUtils { * If the parameter is not found, {@code null} is returned. *

          * - * @param pVariantName {@link String} The name of the variant. + * @param pVariantName {@link String} The name of the variant. * @param pParameterKey {@link String} The key of the parameter to retrieve. * @return {@link String} The value of the custom parameter for the specified variant or {@code null} if not found. - * @since 1.0.0 * @author MeAlam - * @co-author Dan + * @since 1.0.0 */ public static String getParameter(String pVariantName, String pParameterKey) { return variantParametersMap.getOrDefault(pVariantName, new HashMap<>()).getOrDefault(pParameterKey, "null"); @@ -81,44 +79,42 @@ public static String getParameter(String pVariantName, String pParameterKey) { * *

          * - * @since 1.0.0 * @author MeAlam - * @co-author Dan + * @since 1.0.0 */ public static class ParameterBuilder { /** * The name of the variant being associated with custom parameters. * - * @since 1.0.0 * @co-author MeAlam, Dan + * @since 1.0.0 */ private final String variantName; /** * The name of the entity being associated with custom parameters. * - * @since 1.0.0 * @co-author MeAlam, Dan + * @since 1.0.0 */ private final String entityName; /** * Stores custom parameters being built for the variant. * - * @since 1.0.0 * @co-author MeAlam, Dan + * @since 1.0.0 */ private final Map parameters = new HashMap<>(); /** * Constructor to initialize the builder for a specific entity and variant. * - * @param pEntityName {@link String} The name of the entity. + * @param pEntityName {@link String} The name of the entity. * @param pVariantName {@link String} The name of the variant. - * @since 1.0.0 * @author MeAlam - * @co-author Dan + * @since 1.0.0 */ private ParameterBuilder(String pEntityName, String pVariantName) { this.variantName = pVariantName; @@ -128,12 +124,11 @@ private ParameterBuilder(String pEntityName, String pVariantName) { /** * A {@link ParameterBuilder} that creates a new instance of {@link ParameterBuilder} for the specified entity and variant. * - * @param pEntityName {@link String} The name of the entity. + * @param pEntityName {@link String} The name of the entity. * @param pVariantName {@link String} The name of the variant. * @return {@link ParameterBuilder} A new instance for chaining. - * @since 1.0.0 * @author MeAlam - * @co-author Dan + * @since 1.0.0 */ public static ParameterBuilder forVariant(String pEntityName, String pVariantName) { return new ParameterBuilder(pEntityName, pVariantName); @@ -147,9 +142,8 @@ public static ParameterBuilder forVariant(String pEntityName, String pVariantNam * * @param pParameter {@link String} The parameter key. * @return {@link ParameterBuilder} The builder instance for chaining. - * @since 1.0.0 * @author MeAlam - * @co-author Dan + * @since 1.0.0 */ public ParameterBuilder withParameter(String pParameter) { parameters.put(pParameter, "null"); @@ -164,9 +158,8 @@ public ParameterBuilder withParameter(String pParameter) { * * @return {@link ParameterBuilder} The builder instance for chaining. * @throws NoSuchElementException if the variant or entity is not found in the database. - * @since 1.0.0 * @author MeAlam - * @co-author Dan + * @since 1.0.0 */ public ParameterBuilder connect() { VariantParameter variant = VariantLoader.getVariantByName(entityName, variantName); From b53b3e3db242198d9317b29ff20658ec57e26622 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 12:19:02 +0200 Subject: [PATCH 39/62] Removed co-author/ fixed some close comments --- NeoForge/src/main/java/software/bluelib/BlueLib.java | 1 + .../main/java/software/bluelib/BlueLibConstants.java | 3 --- .../bluelib/entity/variant/VariantLoader.java | 3 --- .../bluelib/entity/variant/VariantParameter.java | 1 - .../bluelib/entity/variant/base/ParameterBase.java | 1 - .../software/bluelib/event/ReloadEventHandler.java | 2 -- .../bluelib/interfaces/variant/IVariantEntity.java | 1 - .../main/java/software/bluelib/json/JSONLoader.java | 2 -- .../main/java/software/bluelib/json/JSONMerger.java | 1 - .../bluelib/mixin/variant/LivingEntityMixin.java | 1 - .../software/bluelib/utils/logging/BaseLogLevel.java | 5 ----- .../software/bluelib/utils/logging/BaseLogger.java | 12 ------------ .../software/bluelib/utils/logging/LoggerConfig.java | 5 ----- .../software/bluelib/utils/math/RandomGenUtils.java | 1 - .../bluelib/utils/math/StatisticalUtils.java | 1 - .../software/bluelib/utils/minecraft/ChunkUtils.java | 1 - .../bluelib/utils/variant/ParameterUtils.java | 7 ------- .../bluelib/platform/FabricPlatformHelper.java | 6 ++---- .../bluelib/platform/ForgePlatformHelper.java | 7 ++----- .../bluelib/platform/NeoForgePlatformHelper.java | 6 ++---- 20 files changed, 7 insertions(+), 60 deletions(-) diff --git a/NeoForge/src/main/java/software/bluelib/BlueLib.java b/NeoForge/src/main/java/software/bluelib/BlueLib.java index ad53369f..7735e9b2 100644 --- a/NeoForge/src/main/java/software/bluelib/BlueLib.java +++ b/NeoForge/src/main/java/software/bluelib/BlueLib.java @@ -15,6 +15,7 @@ * This class serves as the entry point for the {@code BlueLib} mod, handling initialization by registering event handlers * and setting up necessary configurations. For more details, refer to the BlueLib Wiki. *

          + * *

          * Key Methods: *

            diff --git a/common/src/main/java/software/bluelib/BlueLibConstants.java b/common/src/main/java/software/bluelib/BlueLibConstants.java index c5934a6b..dc95e738 100644 --- a/common/src/main/java/software/bluelib/BlueLibConstants.java +++ b/common/src/main/java/software/bluelib/BlueLibConstants.java @@ -11,7 +11,6 @@ public class BlueLibConstants { * This executor runs tasks on a single thread to ensure delayed tasks run in a separate thread from the main thread. *

            * - * @co-author MeAlam, Dan * @since 1.0.0 */ public static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1); @@ -20,7 +19,6 @@ public class BlueLibConstants { * A {@code public static final} {@link String} representing the Mod ID for the {@code BlueLib} mod. *

            This serves as a unique identifier for the mod.

            * - * @co-author MeAlam, Dan * @since 1.0.0 */ public static final String MOD_ID = "bluelib"; @@ -28,7 +26,6 @@ public class BlueLibConstants { /** * A {@code public static final} {@link String} representing the Mod Name for the {@code BlueLib} mod. * - * @co-author MeAlam, Dan * @since 1.0.0 */ public static final String MOD_NAME = "BlueLib"; diff --git a/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java index af8e039e..e8f87d72 100644 --- a/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -41,7 +41,6 @@ public class VariantLoader implements IVariantEntityBase { * This {@link Map} holds entity names and their corresponding list of {@link VariantParameter} instances. *

            * - * @co-author MeAlam, Dan * @since 1.0.0 */ private static final Map> entityVariantsMap = new HashMap<>(); @@ -49,7 +48,6 @@ public class VariantLoader implements IVariantEntityBase { /** * A {@code private static final} {@link JSONLoader} to load JSON data from resources. * - * @co-author MeAlam, Dan * @since 1.0.0 */ private static final JSONLoader jsonLoader = new JSONLoader(); @@ -60,7 +58,6 @@ public class VariantLoader implements IVariantEntityBase { * This {@link JSONMerger} instance is used to merge JSON data into a single {@link JsonObject}. *

            * - * @co-author MeAlam, Dan * @since 1.0.0 */ private static final JSONMerger jsonMerger = new JSONMerger(); diff --git a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java index c5b4b01b..6347af1d 100644 --- a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java +++ b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java @@ -36,7 +36,6 @@ public class VariantParameter extends ParameterBase { * This key is used to map the entity to its corresponding parameters within a {@link JsonObject}. *

            * - * @co-author MeAlam, Dan * @since 1.0.0 */ private final String jsonKey; diff --git a/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java index 9769ac9f..600c761e 100644 --- a/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java +++ b/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java @@ -41,7 +41,6 @@ public abstract class ParameterBase { * This {@link Map} holds parameter keys and their corresponding values. *

            * - * @co-author MeAlam, Dan * @since 1.0.0 */ private final Map parameters = new HashMap<>(); diff --git a/common/src/main/java/software/bluelib/event/ReloadEventHandler.java b/common/src/main/java/software/bluelib/event/ReloadEventHandler.java index c9e3e8ce..9920a94f 100644 --- a/common/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/common/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -19,7 +19,6 @@ *
              *
            • {@link #registerEntityVariants(String, MinecraftServer, String, String)} - Registers entity variants from specified locations.
            • *
            - *

            * * @author MeAlam * @see VariantLoader @@ -43,7 +42,6 @@ public class ReloadEventHandler { *
          • {@code pModID} {@link String} - The mod ID used to locate the entity variant resources. (Use your Mod's ID)
          • *
          • {@code pEntityName} {@link String} - The entity name to load.
          • *
          - *

          *

          * Exception Handling: *

            diff --git a/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java b/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java index 8abb3471..9f117a41 100644 --- a/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java +++ b/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java @@ -30,7 +30,6 @@ public interface IVariantEntity extends IVariantEntityBase { /** * A {@link RandomSource} instance used for generating random variants. * - * @co-author MeAlam, Dan * @since 1.0.0 */ RandomSource random = RandomSource.create(); diff --git a/common/src/main/java/software/bluelib/json/JSONLoader.java b/common/src/main/java/software/bluelib/json/JSONLoader.java index 10b887ab..ed3ea2d2 100644 --- a/common/src/main/java/software/bluelib/json/JSONLoader.java +++ b/common/src/main/java/software/bluelib/json/JSONLoader.java @@ -33,8 +33,6 @@ public class JSONLoader { /** * A {@code private static} {@link Gson} instance for parsing JSON data. - * - * @co-author MeAlam, Dan */ private static final Gson gson = new Gson(); diff --git a/common/src/main/java/software/bluelib/json/JSONMerger.java b/common/src/main/java/software/bluelib/json/JSONMerger.java index d2adefde..a69d3c3f 100644 --- a/common/src/main/java/software/bluelib/json/JSONMerger.java +++ b/common/src/main/java/software/bluelib/json/JSONMerger.java @@ -22,7 +22,6 @@ *
              *
            • {@link #mergeJsonObjects(JsonObject, JsonObject)} - Merges the data from the source JSON object into the target JSON object.
            • *
            - *

            * * @author MeAlam * @since 1.0.0 diff --git a/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java b/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java index 7f6a67a4..dfdfdba0 100644 --- a/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java +++ b/common/src/main/java/software/bluelib/mixin/variant/LivingEntityMixin.java @@ -40,7 +40,6 @@ public class LivingEntityMixin implements IVariantAccessor { * A {@link EntityDataAccessor} to hold the entity's variant name, which is synchronized * across clients and servers using {@link SynchedEntityData}. * - * @co-author MeAlam * @since 1.0.0 */ @Unique diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java index 8fb96380..56bb022a 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java @@ -24,7 +24,6 @@ public class BaseLogLevel { /** * Standard informational log level. * - * @co-author MeAlam * @since 1.0.0 */ public static final Level INFO = new Level("INFO", Level.INFO.intValue()) { @@ -32,7 +31,6 @@ public class BaseLogLevel { /** * Log level for error messages. * - * @co-author MeAlam * @since 1.0.0 */ public static final Level ERROR = new Level("ERROR", Level.SEVERE.intValue()) { @@ -40,7 +38,6 @@ public class BaseLogLevel { /** * Log level for warning messages. * - * @co-author MeAlam * @since 1.0.0 */ public static final Level WARNING = new Level("WARNING", Level.WARNING.intValue()) { @@ -49,7 +46,6 @@ public class BaseLogLevel { /** * Custom log level for indicating successful operations. * - * @co-author MeAlam * @since 1.0.0 */ public static final Level SUCCESS = new Level("SUCCESS", Level.INFO.intValue() + 50) { @@ -58,7 +54,6 @@ public class BaseLogLevel { /** * Custom log level specific to BlueLib. * - * @co-author MeAlam * @since 1.0.0 */ public static final Level BLUELIB = new Level("BlueLib Developer", Level.INFO.intValue() + 50) { diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java index bc3cb296..569cdab1 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -30,7 +30,6 @@ public class BaseLogger { /** * A {@link Logger} instance for logging messages. * - * @co-author MeAlam * @since 1.0.0 */ private static final Logger logger = Logger.getLogger(BlueLibConstants.MOD_NAME); @@ -39,7 +38,6 @@ public class BaseLogger { /** * A {@link Boolean} to enable or disable BlueLib specific logging. * - * @co-author MeAlam * @since 1.0.0 */ private static boolean bluelibLogging = true; @@ -47,7 +45,6 @@ public class BaseLogger { /** * A {@link Boolean} to enable or disable general logging. * - * @co-author MeAlam * @since 1.0.0 */ private static boolean isLoggingEnabled = true; @@ -56,7 +53,6 @@ public class BaseLogger { * A {@code void} to enable or disable {@code BlueLib} specific logging. * * @param pEnabled {@link boolean} - Indicates whether to enable or disable BlueLib logging. - * @co-author MeAlam * @since 1.0.0 */ public static void setBlueLibLoggingEnabled(boolean pEnabled) { @@ -67,7 +63,6 @@ public static void setBlueLibLoggingEnabled(boolean pEnabled) { * A {@link Boolean} method that checks if BlueLib logging is enabled. * * @return {@code true} if BlueLib logging is enabled, {@code false} otherwise. - * @co-author MeAlam * @since 1.0.0 */ public static boolean isBlueLibLoggingEnabled() { @@ -78,7 +73,6 @@ public static boolean isBlueLibLoggingEnabled() { * A {@link Boolean} method that checks if logging is enabled. * * @return {@code true} if general logging is enabled, {@code false} otherwise. - * @co-author MeAlam * @since 1.0.0 */ public static boolean isLoggingEnabled() { @@ -89,7 +83,6 @@ public static boolean isLoggingEnabled() { * A {@code void} to enable or disable general logging. * * @param pEnabled {@link boolean} - Indicates whether to enable or disable general logging. - * @co-author MeAlam * @since 1.0.0 */ public static void setLoggingEnabled(boolean pEnabled) { @@ -107,7 +100,6 @@ public static void setLoggingEnabled(boolean pEnabled) { * @param pMessage {@link String} - The message to log. * @param pThrowable {@link Throwable} - The throwable to log with the message. * @param pIsBlueLib {@link boolean} - Indicates if the message is {@code BlueLib} specific. - * @co-author MeAlam * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, boolean pIsBlueLib) { @@ -122,7 +114,6 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, b * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. * @param pIsBlueLib {@link boolean} - Indicates if the message is {@code BlueLib} specific. - * @co-author MeAlam * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { @@ -137,7 +128,6 @@ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. * @param pThrowable {@link Throwable} - The throwable to log with the message. - * @co-author MeAlam * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { @@ -151,7 +141,6 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { * * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. - * @co-author MeAlam * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage) { @@ -164,7 +153,6 @@ public static void log(Level pLogLevel, String pMessage) { * A {@code void} that logs a {@code BlueLib} specific message at the {@code BlueLib} log level. * * @param pMessage {@link String} - The {@code BlueLib} message to log. - * @co-author MeAlam * @since 1.0.0 */ public static void logBlueLib(String pMessage) { diff --git a/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java b/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java index c9b679f3..e4b58c03 100644 --- a/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java +++ b/common/src/main/java/software/bluelib/utils/logging/LoggerConfig.java @@ -29,7 +29,6 @@ public abstract class LoggerConfig { /** * ANSI color codes for console output. * - * @co-author MeAlam * @since 1.0.0 */ protected static final String RESET = "\u001B[0m"; @@ -37,7 +36,6 @@ public abstract class LoggerConfig { /** * ANSI color codes for console output. * - * @co-author MeAlam * @since 1.0.0 */ protected static final String RED = "\u001B[31m"; @@ -45,7 +43,6 @@ public abstract class LoggerConfig { /** * ANSI color codes for console output. * - * @co-author MeAlam * @since 1.0.0 */ protected static final String ORANGE = "\u001B[38;5;214m"; @@ -53,7 +50,6 @@ public abstract class LoggerConfig { /** * ANSI color codes for console output. * - * @co-author MeAlam * @since 1.0.0 */ protected static final String BLUE = "\u001B[34m"; @@ -61,7 +57,6 @@ public abstract class LoggerConfig { /** * ANSI color codes for console output. * - * @co-author MeAlam * @since 1.0.0 */ protected static final String GREEN = "\u001B[38;5;10m"; diff --git a/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java index 6fd69180..868a777d 100644 --- a/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java @@ -21,7 +21,6 @@ *
          • {@link #generateRandomString(int)} - Generates a random alphanumeric string of a specified length.
          • *
          • {@link #generateRandomStringWithPrefix(String, int)} - Generates a random alphanumeric string with a specified prefix and length.
          • *
          - *

          *

          * Each method logs errors using {@link BaseLogger} when invalid parameters are provided (e.g., negative lengths * or minimum values greater than maximum values) and returns default values (e.g., `0` for integers and `"unknown"` for strings) diff --git a/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java index 144ba773..04aa9303 100644 --- a/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java @@ -27,7 +27,6 @@ *

        • {@link #calculateRange(double[])} - Determines the range (difference between maximum and minimum) of an array of values.
        • *
        • {@link #calculateCoefficientOfVariation(double[])} - Calculates the coefficient of variation (CV) of an array of values.
        • * - *

          *

          * Each method logs a success message with the computed value or a warning if the input array is empty. * The logging is done via {@link BaseLogger}, ensuring that any issues or results are recorded appropriately. diff --git a/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java b/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java index 5d6f7efb..c327045f 100644 --- a/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java +++ b/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java @@ -31,7 +31,6 @@ *

        • {@link #getChunkTileEntitiesSimpleNames(Level, ChunkPos)} - Retrieves the simple names of tile entities in the specified chunk.
        • *
        • {@link #getChunkBlockCount(Level, ChunkPos)} - Counts the number of non-air blocks in the specified chunk.
        • * - *

          * * @author MeAlam * @since 1.0.0 diff --git a/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java index 495a71bd..bdba99b8 100644 --- a/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java +++ b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java @@ -22,13 +22,11 @@ *
            *
          • {@link #getParameter(String, String)} - Retrieves the value of a custom parameter for a specific variant.
          • *
          - *

          *

          * Nested Classes: *

            *
          • {@link ParameterBuilder} - Builder class for creating and associating custom parameters with variants.
          • *
          - *

          * * @author MeAlam * @version 1.0.0 @@ -44,7 +42,6 @@ public class ParameterUtils { * representing custom parameters for that variant. *

          * - * @co-author MeAlam, Dan * @since 1.0.0 */ private static final Map> variantParametersMap = new HashMap<>(); @@ -77,7 +74,6 @@ public static String getParameter(String pVariantName, String pParameterKey) { *
        • {@link #withParameter(String)} - Adds a parameter with a default value of {@code null} .
        • *
        • {@link #connect()} - Connects the parameters to the variant and updates {@link VariantParameter} with the parameters.
        • * - *

          * * @author MeAlam * @since 1.0.0 @@ -87,7 +83,6 @@ public static class ParameterBuilder { /** * The name of the variant being associated with custom parameters. * - * @co-author MeAlam, Dan * @since 1.0.0 */ private final String variantName; @@ -95,7 +90,6 @@ public static class ParameterBuilder { /** * The name of the entity being associated with custom parameters. * - * @co-author MeAlam, Dan * @since 1.0.0 */ private final String entityName; @@ -103,7 +97,6 @@ public static class ParameterBuilder { /** * Stores custom parameters being built for the variant. * - * @co-author MeAlam, Dan * @since 1.0.0 */ private final Map parameters = new HashMap<>(); diff --git a/fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java b/fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java index ec55e2bc..ad0aa9de 100644 --- a/fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java +++ b/fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java @@ -11,14 +11,12 @@ public String getPlatformName() { } @Override - public boolean isModLoaded(String modId) { - - return FabricLoader.getInstance().isModLoaded(modId); + public boolean isModLoaded(String pModId) { + return FabricLoader.getInstance().isModLoaded(pModId); } @Override public boolean isDevelopmentEnvironment() { - return FabricLoader.getInstance().isDevelopmentEnvironment(); } } \ No newline at end of file diff --git a/forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java b/forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java index 0905e124..44329bc5 100644 --- a/forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java +++ b/forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java @@ -8,19 +8,16 @@ public class ForgePlatformHelper implements IPlatformHelper { @Override public String getPlatformName() { - return "Forge"; } @Override - public boolean isModLoaded(String modId) { - - return ModList.get().isLoaded(modId); + public boolean isModLoaded(String pModId) { + return ModList.get().isLoaded(pModId); } @Override public boolean isDevelopmentEnvironment() { - return !FMLLoader.isProduction(); } } \ No newline at end of file diff --git a/neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java b/neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java index 35be15f5..606e1252 100644 --- a/neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java +++ b/neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java @@ -8,14 +8,12 @@ public class NeoForgePlatformHelper implements IPlatformHelper { @Override public String getPlatformName() { - return "NeoForge"; } @Override - public boolean isModLoaded(String modId) { - - return ModList.get().isLoaded(modId); + public boolean isModLoaded(String pModId) { + return ModList.get().isLoaded(pModId); } @Override From 718deafd396dc79f7e29c2ce4d320b9336873bb2 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 12:44:20 +0200 Subject: [PATCH 40/62] Fixed all Comments --- .../main/java/software/bluelib/BlueLib.java | 15 +++-- .../main/java/software/bluelib/BlueLib.java | 1 - .../java/software/bluelib/BlueLibCommon.java | 57 ++++++++++++++++--- .../software/bluelib/BlueLibConstants.java | 19 +++++++ .../entity/variant/VariantParameter.java | 1 - .../entity/variant/base/ParameterBase.java | 10 ++-- .../bluelib/event/ReloadEventHandler.java | 3 +- .../interfaces/logging/ILogColorProvider.java | 1 - .../interfaces/platform/IPlatformHelper.java | 53 +++++++++++++---- .../interfaces/variant/IVariantEntity.java | 1 - .../variant/base/IVariantEntityBase.java | 1 - .../main/java/software/bluelib/BlueLib.java | 35 ++++++++++++ .../platform/FabricPlatformHelper.java | 45 ++++++++++++++- .../bluelib/platform/ForgePlatformHelper.java | 45 ++++++++++++++- .../platform/NeoForgePlatformHelper.java | 45 ++++++++++++++- 15 files changed, 292 insertions(+), 40 deletions(-) diff --git a/Forge/src/main/java/software/bluelib/BlueLib.java b/Forge/src/main/java/software/bluelib/BlueLib.java index c58de55b..4f8fc622 100644 --- a/Forge/src/main/java/software/bluelib/BlueLib.java +++ b/Forge/src/main/java/software/bluelib/BlueLib.java @@ -14,16 +14,14 @@ * This class serves as the entry point for the {@link BlueLib} mod, handling initialization by registering event handlers * and setting up necessary configurations. For more details, refer to the BlueLib Wiki. *

          - * *

          * Key Methods: *

            *
          • {@link #BlueLib()} - Constructs the {@link BlueLib} instance and registers the mod event bus.
          • *
          • {@link #onLoadComplete(FMLLoadCompleteEvent)} - Handles the event when the mod loading is complete.
          • *
          - *

          * - * @author MeAlam, Dan and All Contributors of BlueLib! + * @author MeAlam * @see BlueLib Wiki * @since 1.0.0 */ @@ -32,6 +30,10 @@ public class BlueLib { /** * Constructs a new {@link BlueLib} instance and registers the mod event bus. + *

          + * This constructor sets up the mod's event handling by registering the current instance + * with the Forge mod event bus. + *

          * * @author MeAlam * @since 1.0.0 @@ -42,7 +44,12 @@ public BlueLib() { } /** - * A {@code public void} that handles the {@link FMLLoadCompleteEvent}, which occurs when the mod finishes loading. + * A {@code public void} method that handles the {@link FMLLoadCompleteEvent}, which is triggered once + * the mod loading process is complete. + *

          + * This method calls {@link BlueLibCommon#init()} to perform additional initialization after all mod-related + * loading steps are finished. + *

          * * @param pEvent {@link FMLLoadCompleteEvent} - The event fired after the mod loading process completes. * @author MeAlam diff --git a/NeoForge/src/main/java/software/bluelib/BlueLib.java b/NeoForge/src/main/java/software/bluelib/BlueLib.java index 7735e9b2..d2d0dc21 100644 --- a/NeoForge/src/main/java/software/bluelib/BlueLib.java +++ b/NeoForge/src/main/java/software/bluelib/BlueLib.java @@ -22,7 +22,6 @@ *
        • {@link #BlueLib(IEventBus, ModContainer)} - Constructs the {@code BlueLib} instance and registers the mod event bus.
        • *
        • {@link #onLoadComplete(FMLLoadCompleteEvent)} - Handles the event when the mod loading is complete.
        • * - *

          * * @author MeAlam, Dan and All Contributors of BlueLib! * @see BlueLib Wiki diff --git a/common/src/main/java/software/bluelib/BlueLibCommon.java b/common/src/main/java/software/bluelib/BlueLibCommon.java index fdc1d205..c5a56796 100644 --- a/common/src/main/java/software/bluelib/BlueLibCommon.java +++ b/common/src/main/java/software/bluelib/BlueLibCommon.java @@ -1,5 +1,6 @@ -package software.bluelib; +// Copyright (c) BlueLib. Licensed under the MIT License. +package software.bluelib; import software.bluelib.interfaces.platform.IPlatformHelper; import software.bluelib.utils.logging.BaseLogLevel; @@ -10,17 +11,55 @@ import static software.bluelib.BlueLibConstants.SCHEDULER; +/** + * A {@code public class} responsible for common initialization logic and platform detection. + *

          + * This class contains utility methods to load services, initialize the mod in developer mode, + * and determine if the current environment is a development environment. + *

          + *

          + * Key Methods: + *

            + *
          • {@link #init()} - Initializes BlueLib and logs welcome messages if in developer mode.
          • + *
          • {@link #isDeveloperMode()} - Checks if the mod is running in developer mode.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ public class BlueLibCommon { + /** + * A {@code public static final} {@link IPlatformHelper} instance that represents the current platform helper loaded for the mod. + * This is used to identify platform-specific functionalities. + * + * @since 1.0.0 + */ public static final IPlatformHelper PLATFORM = load(IPlatformHelper.class); - public static T load(Class clazz) { - - return ServiceLoader.load(clazz) + /** + * A {@code public static} {@link T} that loads a service using {@link ServiceLoader}. + * + * @param pClazz {@link Class} - The class type of the service to load. + * @param The type of the service class to be loaded. + * @return The loaded service instance of type {@code T}. + * @throws NullPointerException if the service cannot be found. + * @author MeAlam + * @since 1.0.0 + */ + public static T load(Class pClazz) { + return ServiceLoader.load(pClazz) .findFirst() - .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); + .orElseThrow(() -> new NullPointerException("Failed to load service for " + pClazz.getName())); } + /** + * A {@code public static void} that initializes BlueLib and logs a thank-you message if in developer mode.
          + * The message is scheduled to appear after 5 seconds and then the scheduler shuts down. + * + * @author MeAlam + * @since 1.0.0 + */ public static void init() { if (isDeveloperMode()) { SCHEDULER.schedule(() -> { @@ -36,16 +75,16 @@ public static void init() { } /** - * A {@code static} {@link Boolean} that checks if the mod is running in developer mode. + * A {@code public static} {@link Boolean} that checks if the mod is running in developer mode. *

          * Developer mode is active when the mod is not running in a production environment. *

          * - * @return {@code true} if running in developer mode, {@code false} otherwise. + * @return {@code true} if running in developer mode, {@code false} if it isn't. * @author MeAlam * @since 1.0.0 */ - static boolean isDeveloperMode() { + public static boolean isDeveloperMode() { boolean isDevMode = PLATFORM.isDevelopmentEnvironment(); if (isDevMode) { BaseLogger.log(BaseLogLevel.INFO, "Running in Developer mode.", true); @@ -55,4 +94,4 @@ static boolean isDeveloperMode() { return isDevMode; } -} \ No newline at end of file +} diff --git a/common/src/main/java/software/bluelib/BlueLibConstants.java b/common/src/main/java/software/bluelib/BlueLibConstants.java index dc95e738..36c33540 100644 --- a/common/src/main/java/software/bluelib/BlueLibConstants.java +++ b/common/src/main/java/software/bluelib/BlueLibConstants.java @@ -1,8 +1,27 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +/** + * A {@code public class} that defines common constants used across the BlueLib mod. + *

          + * This class contains constants such as the mod's {@link #MOD_ID}, {@link #MOD_NAME}, and a + * {@link ScheduledExecutorService} for scheduling tasks. + *

          + *

          + * Key Fields: + *

            + *
          • {@link #SCHEDULER} - Executor for scheduling delayed tasks.
          • + *
          • {@link #MOD_ID} - Unique identifier for the mod.
          • + *
          • {@link #MOD_NAME} - Display name of the mod.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ public class BlueLibConstants { /** diff --git a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java index 6347af1d..c1a23dfa 100644 --- a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java +++ b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java @@ -50,7 +50,6 @@ public class VariantParameter extends ParameterBase { *
        • {@link JsonObject}: Converts the nested JSON object to a string representation.
        • *
        • {@code Other Types}: Stores "null" for unhandled JSON types.
        • * - *

          * * @param pJsonKey {@link String} - The key that identifies this entity within the {@link JsonObject}. * @param pJsonObject {@link JsonObject} - The {@link JsonObject} containing the variant parameters. diff --git a/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java index 600c761e..ae0a3db7 100644 --- a/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java +++ b/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java @@ -36,9 +36,9 @@ public abstract class ParameterBase { /** - * A {@code private final} {@link Map} to store parameters as key-value pairs. + * A {@code private final} {@link Map} to store parameters as key-value pairs. *

          - * This {@link Map} holds parameter keys and their corresponding values. + * This {@link Map} holds parameter keys and their corresponding values. *

          * * @since 1.0.0 @@ -97,12 +97,12 @@ protected void removeParameter(String pKey) { } /** - * A {@code protected} {@link Map} that returns all parameters in {@link #parameters}. + * A {@code protected} {@link Map} that returns all parameters in {@link #parameters}. *

          - * This method returns a new {@link Map} containing all parameters stored in {@link #parameters}. + * This method returns a new {@link Map} containing all parameters stored in {@link #parameters}. *

          * - * @return {@link Map} - A {@link Map} containing all parameters. + * @return {@link Map} - A {@link Map} containing all parameters. * @author MeAlam * @since 1.0.0 */ diff --git a/common/src/main/java/software/bluelib/event/ReloadEventHandler.java b/common/src/main/java/software/bluelib/event/ReloadEventHandler.java index 9920a94f..12d2bf2d 100644 --- a/common/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/common/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -42,13 +42,12 @@ public class ReloadEventHandler { *
        • {@code pModID} {@link String} - The mod ID used to locate the entity variant resources. (Use your Mod's ID)
        • *
        • {@code pEntityName} {@link String} - The entity name to load.
        • * - *

          + * * Exception Handling: *

            *
          • {@link JsonParseException} - Thrown when there is an error parsing the JSON files.
          • *
          • {@link RuntimeException} - Thrown for unexpected errors during the registration process.
          • *
          - *

          * * @param pFolderPath {@link String} - The folder path location within the mod or datapack where variants are stored. * @param pServer {@link MinecraftServer} - The server instance of the current world. diff --git a/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java b/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java index 58dfb234..b029f0cc 100644 --- a/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java +++ b/common/src/main/java/software/bluelib/interfaces/logging/ILogColorProvider.java @@ -15,7 +15,6 @@ *
            *
          • {@link #getColor(Level)} - Retrieves the color code associated with a specific {@link Level} of logging.
          • *
          - *

          * * @author MeAlam * @since 1.0.0 diff --git a/common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java b/common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java index be1187e7..6938a537 100644 --- a/common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java +++ b/common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java @@ -1,36 +1,65 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.interfaces.platform; +/** + * A {@code public interface} that defines platform-specific functionality for the BlueLib mod. + *

          + * This interface provides methods to retrieve the platform name, check for loaded mods, and determine + * if the game is running in a development environment. + *

          + *

          + * Key Methods: + *

            + *
          • {@link #getPlatformName()} - Retrieves the name of the current platform.
          • + *
          • {@link #isModLoaded(String)} - Checks if a mod is loaded based on its ID.
          • + *
          • {@link #isDevelopmentEnvironment()} - Determines if the environment is for development.
          • + *
          • {@link #getEnvironmentName()} - Retrieves the name of the environment type.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ public interface IPlatformHelper { /** - * Gets the name of the current platform + * A {@link String} method that retrieves the name of the current platform. * - * @return The name of the current platform. + * @return The name of the current platform as a {@link String}. + * @since 1.0.0 */ String getPlatformName(); /** - * Checks if a mod with the given id is loaded. + * A {@link Boolean} method that checks if a mod with the given ID is loaded. * - * @param modId The mod to check if it is loaded. - * @return True if the mod is loaded, false otherwise. + * @param pModId {@link String} - The ID of the mod to check. + * @return {@code true} if the mod is loaded, {@code false} if it isn't. + * @since 1.0.0 */ - boolean isModLoaded(String modId); + boolean isModLoaded(String pModId); /** - * Check if the game is currently in a development environment. + * A {@link Boolean} method that checks if the game is currently running in a development environment. * - * @return True if in a development environment, false otherwise. + * @return {@code true} if running in a development environment, {@code false} if it isn't. + * @author MeAlam + * @since 1.0.0 */ boolean isDevelopmentEnvironment(); /** - * Gets the name of the environment type as a string. + * A {@link String} method that retrieves the name of the current environment type. + *

          + * The environment type is either "development" or "production" based on whether the game is running + * in a development environment. + *

          * - * @return The name of the environment type. + * @return {@link String} - The name of the environment type. + * @author MeAlam + * @since 1.0.0 */ default String getEnvironmentName() { - return isDevelopmentEnvironment() ? "development" : "production"; } -} \ No newline at end of file +} diff --git a/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java b/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java index 9f117a41..90336c54 100644 --- a/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java +++ b/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java @@ -20,7 +20,6 @@ *
            *
          • {@link #getRandomVariant(List, String)} - Retrieves a random variant name from a provided list or defaults if the list is empty.
          • *
          - *

          * * @author MeAlam * @since 1.0.0 diff --git a/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index d8c3f2e3..6c7a6d72 100644 --- a/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -22,7 +22,6 @@ *
        • {@link #getTextureLocation(String, String)} - Retrieves the {@link ResourceLocation} for the entity texture.
        • *
        • {@link #getEntityVariants(String)} - Retrieves a {@link List} of variant names for a specified entity.
        • * - *

          * * @author MeAlam * @since 1.0.0 diff --git a/fabric/src/main/java/software/bluelib/BlueLib.java b/fabric/src/main/java/software/bluelib/BlueLib.java index 876f8311..846da7c5 100644 --- a/fabric/src/main/java/software/bluelib/BlueLib.java +++ b/fabric/src/main/java/software/bluelib/BlueLib.java @@ -1,12 +1,47 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +/** + * A {@code public class} that implements {@link ModInitializer} to initialize the BlueLib mod on the Fabric platform. + *

          + * This class handles the initialization of BlueLib by registering a client tick event that ensures + * the mod is initialized only once during the game runtime. + *

          + *

          + * Key Methods: + *

            + *
          • {@link #onInitialize()} - Registers the client tick event to initialize BlueLib.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ public class BlueLib implements ModInitializer { + /** + * A {@code private} {@link Boolean} flag indicating whether the mod has been initialized. + *

          + * This ensures that the {@link BlueLibCommon#init()} method is called only once during the game's lifecycle. + *

          + * + * @since 1.0.0 + */ private boolean hasInitialized = false; + /** + * A {@code public void} that registers a client tick event to initialize the BlueLib mod. + *

          + * This method uses {@link ClientTickEvents#END_CLIENT_TICK} to register a callback that checks + * whether the mod has already been initialized and calls {@link BlueLibCommon#init()} if necessary. + *

          + * + * @author MeAlam + * @since 1.0.0 + */ @Override public void onInitialize() { ClientTickEvents.END_CLIENT_TICK.register(client -> { diff --git a/fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java b/fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java index ad0aa9de..a15e3a42 100644 --- a/fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java +++ b/fabric/src/main/java/software/bluelib/platform/FabricPlatformHelper.java @@ -1,22 +1,65 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.platform; import net.fabricmc.loader.api.FabricLoader; import software.bluelib.interfaces.platform.IPlatformHelper; +/** + * A {@code public class} that provides platform-specific implementation for Fabric. + *

          + * This class implements {@link IPlatformHelper} to provide Fabric-specific functionality such as + * retrieving the platform name, checking if a mod is loaded, and determining if the game is running + * in a development environment. + *

          + *

          + * Key Methods: + *

            + *
          • {@link #getPlatformName()} - Returns the platform name for Fabric.
          • + *
          • {@link #isModLoaded(String)} - Checks if a mod is loaded using Fabric's mod loader.
          • + *
          • {@link #isDevelopmentEnvironment()} - Checks if Fabric is running in a development environment.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ public class FabricPlatformHelper implements IPlatformHelper { + /** + * A {@code public} {@link String} method that returns the name of the current platform, which is "Fabric" for this implementation. + * + * @return {@link String} - The platform name, "Fabric". + * @author MeAlam + * @since 1.0.0 + */ @Override public String getPlatformName() { return "Fabric"; } + /** + * A {@code public} {@link Boolean} method that checks if a mod with the given ID is loaded using Fabric's mod loader. + * + * @param pModId {@link String} - The mod ID to check if it's loaded. + * @return {@code true} if the mod is loaded, {@code false} otherwise. + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isModLoaded(String pModId) { return FabricLoader.getInstance().isModLoaded(pModId); } + /** + * A {@code public} {@link Boolean} method that checks if the game is currently running in a development environment + * using Fabric's environment detection. + * + * @return {@code true} if running in a development environment, {@code false} if it isn't. + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isDevelopmentEnvironment() { return FabricLoader.getInstance().isDevelopmentEnvironment(); } -} \ No newline at end of file +} diff --git a/forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java b/forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java index 44329bc5..d941bb87 100644 --- a/forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java +++ b/forge/src/main/java/software/bluelib/platform/ForgePlatformHelper.java @@ -1,23 +1,66 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.platform; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.loading.FMLLoader; import software.bluelib.interfaces.platform.IPlatformHelper; +/** + * A {@code public class} that provides platform-specific implementation for Forge. + *

          + * This class implements {@link IPlatformHelper} to provide Forge-specific functionality such as + * retrieving the platform name, checking if a mod is loaded, and determining if the game is running + * in a development environment. + *

          + * + * Key Methods: + *
            + *
          • {@link #getPlatformName()} - Returns the platform name for Forge.
          • + *
          • {@link #isModLoaded(String)} - Checks if a mod is loaded using Forge's {@link ModList}.
          • + *
          • {@link #isDevelopmentEnvironment()} - Checks if Forge is running in a development environment.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ public class ForgePlatformHelper implements IPlatformHelper { + /** + * A {@code public} {@link String} method that returns the name of the current platform, which is "Forge" for this implementation. + * + * @return {@link String} - The platform name, "Forge". + * @author MeAlam + * @since 1.0.0 + */ @Override public String getPlatformName() { return "Forge"; } + /** + * A {@code public} {@link Boolean} method that checks if a mod with the given ID is loaded using Forge's {@link ModList}. + * + * @param pModId {@link String} - The mod ID to check if it's loaded. + * @return {@code true} if the mod is loaded, {@code false} if it isn't. + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isModLoaded(String pModId) { return ModList.get().isLoaded(pModId); } + /** + * A {@code public} {@link Boolean} method that checks if the game is currently running in a development environment + * using Forge's {@link FMLLoader}. + * + * @return {@code true} if running in a development environment, {@code false} if it isn't. + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isDevelopmentEnvironment() { return !FMLLoader.isProduction(); } -} \ No newline at end of file +} diff --git a/neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java b/neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java index 606e1252..5cb1f2c2 100644 --- a/neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java +++ b/neoforge/src/main/java/software/bluelib/platform/NeoForgePlatformHelper.java @@ -1,23 +1,66 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.platform; import net.neoforged.fml.ModList; import net.neoforged.fml.loading.FMLLoader; import software.bluelib.interfaces.platform.IPlatformHelper; +/** + * A {@link NeoForgePlatformHelper} class that provides platform-specific implementation for NeoForge. + *

          + * This class implements {@link IPlatformHelper} to provide NeoForge-specific functionality such as + * retrieving the platform name, checking if a mod is loaded, and determining if the game is running + * in a development environment. + *

          + * + * Key Methods: + *
            + *
          • {@link #getPlatformName()} - Returns the platform name for NeoForge.
          • + *
          • {@link #isModLoaded(String)} - Checks if a mod is loaded using NeoForge's {@link ModList}.
          • + *
          • {@link #isDevelopmentEnvironment()} - Checks if NeoForge is running in a development environment.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ public class NeoForgePlatformHelper implements IPlatformHelper { + /** + * A {@code public} {@link String} method that returns the name of the current platform, which is "NeoForge" for this implementation. + * + * @return {@link String} - The platform name, "NeoForge". + * @author MeAlam + * @since 1.0.0 + */ @Override public String getPlatformName() { return "NeoForge"; } + /** + * A {@code public} {@link Boolean} method that checks if a mod with the given ID is loaded using NeoForge's {@link ModList}. + * + * @param pModId {@link String} - The mod ID to check if it's loaded. + * @return {@code true} if the mod is loaded, {@code false} otherwise. + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isModLoaded(String pModId) { return ModList.get().isLoaded(pModId); } + /** + * A {@code public} {@link Boolean} method that checks if the game is currently running in a development environment + * using NeoForge's {@link FMLLoader}. + * + * @return {@code true} if running in a development environment, {@code false} if it isn't. + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isDevelopmentEnvironment() { return !FMLLoader.isProduction(); } -} \ No newline at end of file +} From 3eb4429acb50712aa14e5bbf2690bd1ac05b3b79 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 12:58:16 +0200 Subject: [PATCH 41/62] removed github workflow error --- .github/workflows/ci.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 293b32e9..e77880a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,9 @@ jobs: build: runs-on: ubuntu-latest + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE20: true + steps: - name: Checkout code uses: actions/checkout@v3 @@ -22,6 +25,11 @@ jobs: distribution: 'temurin' java-version: '21' + - name: Set up Node.js 20 + uses: actions/setup-node@v3 + with: + node-version: '20' + - name: Cache Gradle packages uses: actions/cache@v3 with: @@ -32,7 +40,6 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - # Set up a single Gradle wrapper in a common directory - name: Generate Gradle wrapper if not present run: | if [ ! -f "./gradlew" ]; then From 051b33100261f84e95ab17d809ade6280e9e3ca2 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 16:45:50 +0200 Subject: [PATCH 42/62] Updated Gradle --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138..df97d72b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 6d6fd4300e45e6ec2a021fdf2b85fcdf5c1f0551 Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 20:53:35 +0200 Subject: [PATCH 43/62] Added setVariantParameter * Added Functionality to set the parameter name for which the code will look in the parameters/JSON files when its looking for the Variants --- .../bluelib/entity/variant/VariantLoader.java | 2 +- .../entity/variant/VariantParameter.java | 40 +++++++++++++++---- .../variant/base/IVariantEntityBase.java | 2 +- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java index e8f87d72..e3f9041d 100644 --- a/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -183,7 +183,7 @@ public static VariantParameter getVariantByName(String pEntityName, String pVari BaseLogger.log(BaseLogLevel.INFO, "Retrieving variant by name: " + pVariantName + " for entity: " + pEntityName); List variants = getVariantsFromEntity(pEntityName); for (VariantParameter variant : variants) { - if (variant.getVariantName().equals(pVariantName)) { + if (variant.getVariantParameter().equals(pVariantName)) { return variant; } } diff --git a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java index c1a23dfa..753625ed 100644 --- a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java +++ b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java @@ -21,7 +21,7 @@ * Key Methods: *
            *
          • {@link #getJsonKey()} - Retrieves the key of the JSON object that identifies this entity.
          • - *
          • {@link #getVariantName()} - Retrieves the name of the variant.
          • + *
          • {@link #getVariantParameter()} - Retrieves the name of the variant.
          • *
          • {@link #getParameter(String)} - Retrieves the value of a specific parameter by its key.
          • *
          * @@ -31,7 +31,7 @@ public class VariantParameter extends ParameterBase { /** - * A {@link String} that represents the key of the JSON object that identifies this entity. + * A {@code private final} {@link String} that represents the key of the JSON object that identifies this entity. *

          * This key is used to map the entity to its corresponding parameters within a {@link JsonObject}. *

          @@ -40,6 +40,16 @@ public class VariantParameter extends ParameterBase { */ private final String jsonKey; + /** + * A {@code private static} {@link String} that represents the name of the Variant parameter. + *

          + * This key is used to locate the variant name within the parameters/JSON files. + *

          + * + * @since 1.0.0 + */ + private static String variantParameterName = "variantName"; + /** * Constructs a new {@code VariantParameter} instance by extracting parameters from a given {@link JsonObject}. *

          @@ -114,21 +124,37 @@ public String getJsonKey() { } /** - * A {@link String} method that retrieves the name of the variant. + * A {@link String} method that retrieves the name of the variant parameter. *

          - * The variant name is expected to be stored under the key {@code "variantName"} in the parameters/JSON files. + * The variant name is, by default, stored under the key {@code "variantName"} in the parameters/JSON files. + * Otherwise, the key is stored in the {@link #variantParameterName} field. *

          * * @return The name of the variant, or {@code null} if the variant name is not found. * @author MeAlam * @since 1.0.0 */ - public String getVariantName() { - String variantName = getParameter("variantName"); - BaseLogger.log(BaseLogLevel.INFO, "Retrieved variant name: " + variantName); + public String getVariantParameter() { + String variantName = getParameter(variantParameterName); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter name: " + variantName); return variantName; } + /** + * A {@link String} method that sets the name of the variant parameter. + *

          + * This method allows the user to customize the key used to locate the variant name within the parameters/JSON files. + *

          + * + * @param pCustomVariantName {@link String} - The custom name of the variant parameter. + * @author MeAlam + * @since 1.0.0 + */ + public void setVariantParameter(String pCustomVariantName) { + variantParameterName = pCustomVariantName; + BaseLogger.log(BaseLogLevel.INFO, "Setting parameter name: " + variantParameterName); + } + /** * A {@link String} method that retrieves the value of a specific parameter by its key. *

          diff --git a/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index 6c7a6d72..a6c969a5 100644 --- a/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -58,7 +58,7 @@ default ResourceLocation getTextureLocation(String pModId, String pPath) { default List getEntityVariants(String pEntityName) { List variants = VariantLoader.getVariantsFromEntity(pEntityName); List variantNames = variants.stream() - .map(VariantParameter::getVariantName) + .map(VariantParameter::getVariantParameter) .collect(Collectors.toList()); BaseLogger.log(BaseLogLevel.SUCCESS, "Retrieved " + variantNames.size() + " variants for entity: " + pEntityName); return variantNames; From fe801ca76eb7813d2922707e8992a7ffcd78453e Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 22:18:02 +0200 Subject: [PATCH 44/62] Created an EnableLogging Annotation --- .../java/software/bluelib/BlueLibCommon.java | 6 +- .../bluelib/annotations/EnableLogging.java | 21 +++++ .../bluelib/utils/logging/BaseLogger.java | 82 +++++++++++++++---- 3 files changed, 91 insertions(+), 18 deletions(-) create mode 100644 common/src/main/java/software/bluelib/annotations/EnableLogging.java diff --git a/common/src/main/java/software/bluelib/BlueLibCommon.java b/common/src/main/java/software/bluelib/BlueLibCommon.java index c5a56796..ba821114 100644 --- a/common/src/main/java/software/bluelib/BlueLibCommon.java +++ b/common/src/main/java/software/bluelib/BlueLibCommon.java @@ -2,6 +2,7 @@ package software.bluelib; +import software.bluelib.annotations.EnableLogging; import software.bluelib.interfaces.platform.IPlatformHelper; import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; @@ -87,11 +88,10 @@ public static void init() { public static boolean isDeveloperMode() { boolean isDevMode = PLATFORM.isDevelopmentEnvironment(); if (isDevMode) { - BaseLogger.log(BaseLogLevel.INFO, "Running in Developer mode.", true); + BaseLogger.log(BaseLogLevel.INFO, "Running in Developer mode."); } else { - BaseLogger.log(BaseLogLevel.INFO, "Running in Production mode.", true); + BaseLogger.log(BaseLogLevel.INFO, "Running in Production mode."); } return isDevMode; } - } diff --git a/common/src/main/java/software/bluelib/annotations/EnableLogging.java b/common/src/main/java/software/bluelib/annotations/EnableLogging.java new file mode 100644 index 00000000..cfe342a7 --- /dev/null +++ b/common/src/main/java/software/bluelib/annotations/EnableLogging.java @@ -0,0 +1,21 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * A custom annotation that acts as a boolean flag. + * If this annotation is present on a class or method, it is considered 'true'. + * Otherwise, it defaults to 'false'. + * + * @author MeAlam + * @version 1.0.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD}) +public @interface EnableLogging { +} diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java index 569cdab1..8823bcf9 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -3,7 +3,9 @@ package software.bluelib.utils.logging; import software.bluelib.BlueLibConstants; +import software.bluelib.annotations.EnableLogging; +import java.lang.reflect.Method; import java.util.logging.Level; import java.util.logging.Logger; @@ -40,14 +42,14 @@ public class BaseLogger { * * @since 1.0.0 */ - private static boolean bluelibLogging = true; + private static boolean bluelibLogging = false; /** * A {@link Boolean} to enable or disable general logging. * * @since 1.0.0 */ - private static boolean isLoggingEnabled = true; + private static boolean isLoggingEnabled = false; /** * A {@code void} to enable or disable {@code BlueLib} specific logging. @@ -94,7 +96,8 @@ public static void setLoggingEnabled(boolean pEnabled) { } /** - * A {@code void} that logs a message with an associated {@link Throwable} if {@code BlueLib} logging is enabled. + * A {@code public static void} that logs a message with an associated {@link Throwable} + * if {@code BlueLib} logging is enabled. * * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. @@ -103,13 +106,19 @@ public static void setLoggingEnabled(boolean pEnabled) { * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, boolean pIsBlueLib) { - if (pIsBlueLib && bluelibLogging) { - logger.log(pLogLevel, pMessage, pThrowable); + try { + if (pIsBlueLib && bluelibLogging) { + logger.log(pLogLevel, pMessage, pThrowable); + } else if (!pIsBlueLib && isLoggingEnabled) { + logger.log(pLogLevel, pMessage, pThrowable); + } + } catch (Exception pException) { + logger.log(Level.SEVERE, "Failed to log message.", pException); } } /** - * A {@code void} that logs a message if BlueLib logging is enabled. + * A {@code public static void} that logs a message if {@code BlueLib} logging is enabled. * * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. @@ -117,13 +126,20 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, b * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { - if (pIsBlueLib && bluelibLogging) { - logger.log(pLogLevel, pMessage); + try { + if (pIsBlueLib && bluelibLogging) { + logger.log(pLogLevel, pMessage); + } else if (!pIsBlueLib && isLoggingEnabled) { + logger.log(pLogLevel, pMessage); + } + } catch (Exception pException) { + logger.log(Level.SEVERE, "Failed to log message.", pException); } } /** - * A {@code void} that logs a message with an associated {@link Throwable} if general logging is enabled. + * A {@code public static void} that logs a message with an associated {@link Throwable} + * if general logging is enabled. * * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. @@ -131,26 +147,62 @@ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { - if (isLoggingEnabled) { - logger.log(pLogLevel, pMessage, pThrowable); + try { + if (isLoggingEnabled) { + logger.log(pLogLevel, pMessage, pThrowable); + } else { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + if (stackTrace.length > 3) { + Class callingClass = Class.forName(stackTrace[3].getClassName()); + Method callingMethod = callingClass.getMethod(stackTrace[3].getMethodName()); + + if (callingClass.isAnnotationPresent(EnableLogging.class)) { + logger.log(pLogLevel, pMessage, pThrowable); + } else if (callingMethod.isAnnotationPresent(EnableLogging.class)) { + logger.log(pLogLevel, pMessage, pThrowable); + } else { + logger.log(pLogLevel,"Class: " + callingClass.getName() + ", Method: " + callingMethod.getName()); + } + } + } + } catch (Exception pException) { + logger.log(Level.SEVERE, "Failed to log message.", pException); } } /** - * A {@code void} that logs a message if general logging is enabled. + * A {@code public static void} that logs a message if general logging is enabled. * * @param pLogLevel {@link Level} - The logging level to use. * @param pMessage {@link String} - The message to log. * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage) { - if (isLoggingEnabled) { - logger.log(pLogLevel, pMessage); + try { + if (isLoggingEnabled) { + logger.log(pLogLevel, pMessage); + } else { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + if (stackTrace.length > 3) { + Class callingClass = Class.forName(stackTrace[3].getClassName()); + Method callingMethod = callingClass.getMethod(stackTrace[3].getMethodName()); + + if (callingClass.isAnnotationPresent(EnableLogging.class)) { + logger.log(pLogLevel, pMessage); + } else if (callingMethod.isAnnotationPresent(EnableLogging.class)) { + logger.log(pLogLevel, pMessage); + } else { + logger.log(pLogLevel,"Class: " + callingClass.getName() + ", Method: " + callingMethod.getName()); + } + } + } + } catch (Exception pException) { + logger.log(Level.SEVERE, "Failed to log message.", pException); } } /** - * A {@code void} that logs a {@code BlueLib} specific message at the {@code BlueLib} log level. + * A {@code public static void} that logs a {@code BlueLib} specific message at the {@code BlueLib} log level. * * @param pMessage {@link String} - The {@code BlueLib} message to log. * @since 1.0.0 From 5a693d12066c2598c486f3d64b4bb355a892e7cb Mon Sep 17 00:00:00 2001 From: Aram Date: Mon, 7 Oct 2024 22:23:28 +0200 Subject: [PATCH 45/62] Create EnhancementTemplate.yml --- .../ISSUE_TEMPLATE/EnhancementTemplate.yml | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/EnhancementTemplate.yml diff --git a/.github/ISSUE_TEMPLATE/EnhancementTemplate.yml b/.github/ISSUE_TEMPLATE/EnhancementTemplate.yml new file mode 100644 index 00000000..aa7e66fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/EnhancementTemplate.yml @@ -0,0 +1,33 @@ +name: Enhancement Template +description: Create a Enhancement! +title: "[Enhancement]: " +labels: ["Enhancement"] +body: + - type: markdown + attributes: + value: | + Thank you for making a Suggestion! + - type: textarea + id: what-should-we-add + attributes: + label: What do you want to have added? + description: | + Please tell us as detailed as possible what you want to have added to the mod! + Feel free to also add Examples if they exist! + validations: + required: true + - type: dropdown + id: inspiration + attributes: + label: Inspiration + description: Is this idea used in other Mods/Games? + options: + - "Yes" + - "No" + validations: + required: true + - type: input + id: inspiration-where + attributes: + label: Where did you get the inspiration from? + description: If this idea is used in a different Mod/Game, please provide a list of the Games/Mods \ No newline at end of file From 63e595ec3e9ac16430c3725affcdaa34a8be172a Mon Sep 17 00:00:00 2001 From: Aram Date: Tue, 8 Oct 2024 01:37:28 +0200 Subject: [PATCH 46/62] Removed Debugger --- .../main/java/software/bluelib/utils/logging/BaseLogger.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java index 8823bcf9..a1289715 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -160,8 +160,6 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { logger.log(pLogLevel, pMessage, pThrowable); } else if (callingMethod.isAnnotationPresent(EnableLogging.class)) { logger.log(pLogLevel, pMessage, pThrowable); - } else { - logger.log(pLogLevel,"Class: " + callingClass.getName() + ", Method: " + callingMethod.getName()); } } } @@ -191,8 +189,6 @@ public static void log(Level pLogLevel, String pMessage) { logger.log(pLogLevel, pMessage); } else if (callingMethod.isAnnotationPresent(EnableLogging.class)) { logger.log(pLogLevel, pMessage); - } else { - logger.log(pLogLevel,"Class: " + callingClass.getName() + ", Method: " + callingMethod.getName()); } } } From 919943576dc64df8d87641b65ab23eeb5640f4e5 Mon Sep 17 00:00:00 2001 From: Aram Date: Tue, 8 Oct 2024 16:17:03 +0200 Subject: [PATCH 47/62] Update CONTRIBUTING.md --- CONTRIBUTING.md | 139 ++++++++++++++++++++++++++++++------------------ 1 file changed, 86 insertions(+), 53 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 882c9e7d..54d003ec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,63 +17,96 @@ - **Structure**: - **Class Descriptions**: + - **Start with:** Start the Comment with A(n) {@code privacy/static/final} {@code/link Class/MethodType} [Description of the Class/Method]. - **Key Methods:** List key methods provided by the class, using bullet points for easy readability. - - **Author:** If you have contributed to a Method/Class, put yourself as Co-author, if you have created an Method/Class, put yourself as Author. - - **Since Version:** Use the `@since` tag to indicate the version since which the class has been available. + - **Author:** If you have contributed to a Method/Class, feel free to add yourself to the author tag. + - **Since Version:** Use the `@since` tag to indicate the version since which the Method/Class has been available. + - **Version:** Use the `@version` tag to indicate the version since when the class has last been updated. **Example:** ```java - /** - * A {@code JSONLoader} class responsible for loading and parsing JSON data from resources - * defined by {@link ResourceLocation} within a Minecraft mod environment. - *

          - * Key Methods: - *

            - *
          • {@link #loadJson(ResourceLocation, ResourceManager)} - Loads a JSON resource.
          • - *
          - * @author MeAlam - - * @since 1.0.0 - */ - public class JSONLoader { - } - ``` - - **Method Descriptions**: Begin each comment with a brief description that typically starts with `A ...`, where the `...` represents a link to the relevant class or object using `{@link ClassName}`. If the method is `void`, use `{@code}` to refer to the method name instead. - - **Example for a Method**: - ```java /** - * A {@link String} that retrieves the value of a custom parameter for a specific variant. - * - * @param pVariantName {@link String} - The variant name you want to see the custom parameter of. - * @param pParameterKey {@link String} - The parameter you want to see. - * @return The value of the custom parameter identified by {@code pParameterKey} - * for the variant specified by {@code pVariantName}. - * @author MeAlam + * A {@code public abstract base class} for managing a collection of {@link #parameters}. + *

          + * This {@code class} provides methods to add, retrieve, remove, and manipulate {@link #parameters} stored as key-value pairs. + *

          + * Key Methods: + *
            + *
          • {@link #addParameter(String, Object)} - Adds a parameter to {@link #parameters}.
          • + *
          • {@link #getParameter(String)} - Retrieves a parameter from {@link #parameters}.
          • + *
          • {@link #removeParameter(String)} - Removes a parameter from {@link #parameters}.
          • + *
          • {@link #getAllParameters()} - Returns all parameters in {@link #parameters}.
          • + *
          • {@link #containsParameter(String)} - Checks if a parameter exists by its key from {@link #parameters}.
          • + *
          • {@link #isEmpty()} - Checks if {@link #parameters} is empty.
          • + *
          • {@link #clearParameters()} - Clears all parameters from {@link #parameters}.
          • + *
          • {@link #getParameterCount()} - Returns the number of parameters in {@link #parameters}.
          • + *
          • {@link #getParameterKeys()} - Returns a set of all parameter keys from {@link #parameters}.
          • + *
          • {@link #getParameterValues()} - Returns a collection of all parameter values from {@link #parameters}.
          • + *
          • {@link #updateParameter(String, Object)} - Updates the value of an existing parameter in {@link #parameters}.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + * @version 1.0.0 + */ + ``` + - **Start with:** Start the Comment with A(n) {@code privacy/static/final} {@code/link Class/MethodType} [Description of the Class/Method]. + - **Example for a Method**: + ```java + /** + * A {@code protected static void} that registers entity variants from specified locations. + *

          + * This method attempts to load variants from both mod and datapack locations. It logs status information and + * handles exceptions that occur during the loading process. + *

          + *

          + * Parameters: + *

            + *
          • {@code pFolderPath} {@link String} - The folder path location within the mod or datapack where variants are stored.
          • + *
          • {@code pServer} {@link MinecraftServer} - The server instance of the current world.
          • + *
          • {@code pModID} {@link String} - The mod ID used to locate the entity variant resources. (Use your Mod's ID)
          • + *
          • {@code pEntityName} {@link String} - The entity name to load.
          • + *
          + * + * Exception Handling: + *
            + *
          • {@link JsonParseException} - Thrown when there is an error parsing the JSON files.
          • + *
          • {@link RuntimeException} - Thrown for unexpected errors during the registration process.
          • + *
          + * + * @param pFolderPath {@link String} - The folder path location within the mod or datapack where variants are stored. + * @param pServer {@link MinecraftServer} - The server instance of the current world. + * @param pModID {@link String} - The mod ID used to locate the entity variant resources. (Use your Mod's ID) + * @param pEntityName {@link String} - The entity name to load. + * @throws JsonParseException if there is an error parsing the JSON files. + * @throws RuntimeException if an unexpected error occurs during the registration process. + * @author MeAlam + * @see MinecraftServer + * @see ResourceLocation + * @see VariantLoader + * @since 1.0.0 + */ + protected static void registerEntityVariants(String pFolderPath, MinecraftServer pServer, String pModID, String pEntityName) { + } + ``` + + - **Parameters**: Start each parameter description with `{@link TypeOfParameter} - [Comment]`. If the parameter is referenced within the comment, enclose it in a code block using `{@code}`. + - **Example for Parameters**: + ```java + /** + * A {@link String} that retrieves the value of a custom parameter for a specific variant. + * + * @param pVariantName {@link String} - The variant name you want to see the custom parameter of. + * @param pParameterKey {@link String} - The parameter you want to see. + * @return The value of the custom parameter identified by {@code pParameterKey} + * for the variant specified by {@code pVariantName}. + * @author MeAlam - * @since 1.0.0 + * @since 1.0.0 */ - public String getCustomParameter(String pVariantName, String pParameterKey) { - // Method implementation - } - ``` - - - **Parameters**: Start each parameter description with `{@link TypeOfParameter} - [Comment]`. If the parameter is referenced within the comment, enclose it in a code block using `{@code}`. - - **Example for Parameters**: - ```java - /** - * A {@link String} that retrieves the value of a custom parameter for a specific variant. - * - * @param pVariantName {@link String} - The variant name you want to see the custom parameter of. - * @param pParameterKey {@link String} - The parameter you want to see. - * @return The value of the custom parameter identified by {@code pParameterKey} - * for the variant specified by {@code pVariantName}. - * @author MeAlam - - * @since 1.0.0 - */ - public String getCustomParameter(String pVariantName, String pParameterKey) { - // Method implementation - } - ``` + public String getCustomParameter(String pVariantName, String pParameterKey) { + // Method implementation + } + ``` - **General Guidelines**: - Always ensure that comments are clear, concise, and provide sufficient information to understand the code. @@ -81,9 +114,9 @@ - Use `{@link}` to refer to classes, methods, or any other Java elements where appropriate. - Key Methods: In class-level comments, list out key methods provided by the class, which can help users quickly understand the main functionalities. - Versioning: Include the `@since` tag in both class-level and method-level comments to indicate the version since which the class or method has been available. - - If you update a Class/Method, please add/update the `@version` to indicate it has been changed. + - If you update a Class, please add/update the `@version` to indicate it has been changed. - Copyright: Each file should start with `// Copyright (c) BlueLib. Licensed under the MIT License.` - - Tags: Use `@see` to link to the correct Wiki/Api Documentation page if it exists. + - Tags: Use `@see` to link to the correct Wiki Documentation page if it exists. - Logging: Log every step using `BaseLogger.logError`, `BaseLogger.logWarning`, `BaseLogger.bluelibLogInfo`, or `BaseLogger.bluelibLogSuccess`, depending on the step. - Error Handling: Always ensure that errors and warnings are logged using appropriate logging levels. Critical steps must be logged at least with `BaseLogger.bluelibLogInfo` to keep a trail of execution. From c0cec0dfdfb1e8444953fdff41f9bd59cedfa794 Mon Sep 17 00:00:00 2001 From: Aram Date: Tue, 8 Oct 2024 17:04:54 +0200 Subject: [PATCH 48/62] Fixed some errors in the Contributing, Enhancemements and logger --- .../ISSUE_TEMPLATE/EnhancementTemplate.yml | 2 +- CONTRIBUTING.md | 36 +++++++------------ .../bluelib/utils/logging/BaseLogger.java | 16 ++++++--- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/EnhancementTemplate.yml b/.github/ISSUE_TEMPLATE/EnhancementTemplate.yml index aa7e66fa..7675ff1a 100644 --- a/.github/ISSUE_TEMPLATE/EnhancementTemplate.yml +++ b/.github/ISSUE_TEMPLATE/EnhancementTemplate.yml @@ -12,7 +12,7 @@ body: attributes: label: What do you want to have added? description: | - Please tell us as detailed as possible what you want to have added to the mod! + Please tell us as detailed as possible what you want to have added to the library! Feel free to also add Examples if they exist! validations: required: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 54d003ec..479380b5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -100,7 +100,6 @@ * @return The value of the custom parameter identified by {@code pParameterKey} * for the variant specified by {@code pVariantName}. * @author MeAlam - * @since 1.0.0 */ public String getCustomParameter(String pVariantName, String pParameterKey) { @@ -117,13 +116,12 @@ - If you update a Class, please add/update the `@version` to indicate it has been changed. - Copyright: Each file should start with `// Copyright (c) BlueLib. Licensed under the MIT License.` - Tags: Use `@see` to link to the correct Wiki Documentation page if it exists. - - Logging: Log every step using `BaseLogger.logError`, `BaseLogger.logWarning`, `BaseLogger.bluelibLogInfo`, or `BaseLogger.bluelibLogSuccess`, depending on the step. - - Error Handling: Always ensure that errors and warnings are logged using appropriate logging levels. Critical steps must be logged at least with `BaseLogger.bluelibLogInfo` to keep a trail of execution. + - Logging: Log every step using `BaseLogger.log`, Always remove the `@EnableLogging` annotation/disable the logging before committing. + - Error Handling: Always ensure that errors and warnings are logged using appropriate logging levels. Critical steps must be logged at least with `BaseLogger.log(BaseLogLevel.Error)` to keep a trail of execution. ### Deprecation - If you optimize a method, variable, or class and determine that it is no longer necessary for the library, mark it as `@Deprecated` instead of removing it. This only applies to elements that have been included in previous released versions of the library. - - Include a **strong TODO comment** explaining why it is deprecated and any further action required, such as testing or eventual removal. - Include an **`@see`** that links to the New Method - **Example**: @@ -134,7 +132,6 @@ * TODO: Testing with Multiple Entities and Datapacks required before Deletion/Refactoring.
          * @return A map containing the parameters added to this builder. * @author MeAlam - * @since 1.0.0 * @see #newMethod() */ @@ -172,41 +169,32 @@ - Visual Studio Code (VSC) - Eclipse (Recommended) -5. **Publish to Local Maven Repository** - - Run the following command from the library folder (e.g., `NeoForge`, `Forge`, `Fabric`) to publish the library to your local Maven repository. - - **Example**: - ```bash - ./gradlew publishToMavenLocal - ``` - - This allows you to test the library locally. - -6. **Modify the Library** +5. **Modify the Library** - Make the necessary changes to the respective library folder you are working on. Ensure you adhere to the coding conventions described above. -7. **Test Your Changes** - - Before committing, test your changes by running the game using the appropriate test mod loader folder: - - `TestMods/TestNeoForge` - - `TestMods/TestForge` - - `TestMods/TestFabric` +6. **Test Your Changes** + - Before committing, test your changes by running the game using the appropriate test mod loader folder. + - Use the `example` package to test your changes. + - If no code is available to test, create new test code in the `example` package. - Ensure that your changes do not introduce any issues or regressions. -8. **Commit Your Changes** - - Once you are satisfied with your changes, commit them from the root folder (`BlueLib`). +7. **Commit Your Changes** + - Once you are satisfied with your changes, commit them to your branch. - Write clear and concise commit messages explaining the changes made. - **Example**: ```bash git commit -am "Improved logging functionality and deprecated old log method" ``` -9. **Push to Your Fork** +8. **Push to Your Fork** - Push your branch to your fork on GitHub. - **Example**: ```bash git push origin feature/improve-logging ``` -10. **Create a Pull Request (PR)** - - Navigate to your fork on GitHub and create a Pull Request to the main repository. Provide a detailed description of the changes made and why they are necessary. +9. **Create a Pull Request (PR)** + - Navigate to your fork on GitHub and create a Pull Request to the main repository. Provide a detailed description of the changes made and why they are necessary. ## Contributor License Agreement (CLA) diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java index a1289715..882cd94c 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -107,7 +107,9 @@ public static void setLoggingEnabled(boolean pEnabled) { */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, boolean pIsBlueLib) { try { - if (pIsBlueLib && bluelibLogging) { + if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB) { + logger.log(pLogLevel, pMessage, pThrowable); + } else if (pIsBlueLib && bluelibLogging) { logger.log(pLogLevel, pMessage, pThrowable); } else if (!pIsBlueLib && isLoggingEnabled) { logger.log(pLogLevel, pMessage, pThrowable); @@ -127,7 +129,9 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, b */ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { try { - if (pIsBlueLib && bluelibLogging) { + if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB) { + logger.log(pLogLevel, pMessage); + } else if (pIsBlueLib && bluelibLogging) { logger.log(pLogLevel, pMessage); } else if (!pIsBlueLib && isLoggingEnabled) { logger.log(pLogLevel, pMessage); @@ -148,7 +152,9 @@ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { try { - if (isLoggingEnabled) { + if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB) { + logger.log(pLogLevel, pMessage, pThrowable); + } else if (isLoggingEnabled) { logger.log(pLogLevel, pMessage, pThrowable); } else { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); @@ -177,7 +183,9 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { */ public static void log(Level pLogLevel, String pMessage) { try { - if (isLoggingEnabled) { + if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB) { + logger.log(pLogLevel, pMessage); + } else if (isLoggingEnabled) { logger.log(pLogLevel, pMessage); } else { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); From ca144903c8d0aa67d39e8f407e81171e352fc612 Mon Sep 17 00:00:00 2001 From: Aram Date: Tue, 8 Oct 2024 20:25:39 +0200 Subject: [PATCH 49/62] Added Geckolib as Optional Dependancy for NeoForge --- NeoForge/build.gradle | 5 +++++ buildSrc/src/main/groovy/bluelib-common.gradle | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/NeoForge/build.gradle b/NeoForge/build.gradle index 61fb9f8a..3715ccc8 100644 --- a/NeoForge/build.gradle +++ b/NeoForge/build.gradle @@ -36,4 +36,9 @@ neoForge { } } +dependencies { + compileOnly("curse.maven:geckolib-388172:5605715") + runtimeOnly("curse.maven:geckolib-388172:5605715") +} + sourceSets.main.resources { srcDir 'src/generated/resources' } \ No newline at end of file diff --git a/buildSrc/src/main/groovy/bluelib-common.gradle b/buildSrc/src/main/groovy/bluelib-common.gradle index 0291eb4f..31d6d332 100644 --- a/buildSrc/src/main/groovy/bluelib-common.gradle +++ b/buildSrc/src/main/groovy/bluelib-common.gradle @@ -4,7 +4,7 @@ plugins { } base { - archivesName = "${mod_id}-${minecraft_version}-${version}" + archivesName = "${mod_id}-${minecraft_version}" } java { @@ -38,6 +38,16 @@ repositories { ) filter { includeGroup('org.parchmentmc.data') } } + exclusiveContent { + forRepository { + maven { + url "https://cursemaven.com" + } + } + filter { + includeGroup "curse.maven" + } + } maven { name = 'BlameJared' url = 'https://maven.blamejared.com' From acb2cbb598f84b56e6e59010f633bb24564faf97 Mon Sep 17 00:00:00 2001 From: Aram Date: Tue, 8 Oct 2024 23:29:46 +0200 Subject: [PATCH 50/62] Update Gradle 8.8 to 8.10.2 Succesfully this time --- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43583 bytes gradlew | 5 ++++- gradlew.bat | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 12612 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 HJ4oML2Lo<@i8BwbL^1~GkG`E7C$SEa_ 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 diff --git a/gradlew b/gradlew index b740cf13..f5feea6d 100644 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 25da30db..9d21a218 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## From 117104ad4a433dab95e5e398e42610eccf73e1f3 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 9 Oct 2024 00:07:51 +0200 Subject: [PATCH 51/62] Update BaseLogger.java Fixed the logging to ensure it doesnt return an error when the logging is disabled --- .../bluelib/utils/logging/BaseLogger.java | 76 +++++++++---------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java index 882cd94c..0d552f30 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -107,15 +107,14 @@ public static void setLoggingEnabled(boolean pEnabled) { */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, boolean pIsBlueLib) { try { - if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB) { - logger.log(pLogLevel, pMessage, pThrowable); - } else if (pIsBlueLib && bluelibLogging) { - logger.log(pLogLevel, pMessage, pThrowable); - } else if (!pIsBlueLib && isLoggingEnabled) { + if (pLogLevel == BaseLogLevel.ERROR || + pLogLevel == BaseLogLevel.WARNING || + pLogLevel == BaseLogLevel.BLUELIB || + pIsBlueLib && bluelibLogging || + !pIsBlueLib && isLoggingEnabled) { logger.log(pLogLevel, pMessage, pThrowable); } - } catch (Exception pException) { - logger.log(Level.SEVERE, "Failed to log message.", pException); + } catch (Exception ignored) { } } @@ -129,15 +128,14 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, b */ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { try { - if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB) { - logger.log(pLogLevel, pMessage); - } else if (pIsBlueLib && bluelibLogging) { - logger.log(pLogLevel, pMessage); - } else if (!pIsBlueLib && isLoggingEnabled) { + if (pLogLevel == BaseLogLevel.ERROR || + pLogLevel == BaseLogLevel.WARNING || + pLogLevel == BaseLogLevel.BLUELIB || + pIsBlueLib && bluelibLogging || + !pIsBlueLib && isLoggingEnabled) { logger.log(pLogLevel, pMessage); } - } catch (Exception pException) { - logger.log(Level.SEVERE, "Failed to log message.", pException); + } catch (Exception ignored) { } } @@ -152,25 +150,24 @@ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { try { - if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB) { + if (pLogLevel == BaseLogLevel.ERROR || + pLogLevel == BaseLogLevel.WARNING || + pLogLevel == BaseLogLevel.BLUELIB || + isLoggingEnabled) { logger.log(pLogLevel, pMessage, pThrowable); - } else if (isLoggingEnabled) { - logger.log(pLogLevel, pMessage, pThrowable); - } else { + return; + } StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); if (stackTrace.length > 3) { Class callingClass = Class.forName(stackTrace[3].getClassName()); Method callingMethod = callingClass.getMethod(stackTrace[3].getMethodName()); - if (callingClass.isAnnotationPresent(EnableLogging.class)) { - logger.log(pLogLevel, pMessage, pThrowable); - } else if (callingMethod.isAnnotationPresent(EnableLogging.class)) { + if (callingClass.isAnnotationPresent(EnableLogging.class) || + callingMethod.isAnnotationPresent(EnableLogging.class)) { logger.log(pLogLevel, pMessage, pThrowable); } } - } - } catch (Exception pException) { - logger.log(Level.SEVERE, "Failed to log message.", pException); + } catch (Exception ignored) { } } @@ -183,25 +180,24 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { */ public static void log(Level pLogLevel, String pMessage) { try { - if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB) { + if (pLogLevel == BaseLogLevel.ERROR || + pLogLevel == BaseLogLevel.WARNING || + pLogLevel == BaseLogLevel.BLUELIB || + isLoggingEnabled) { logger.log(pLogLevel, pMessage); - } else if (isLoggingEnabled) { - logger.log(pLogLevel, pMessage); - } else { - StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - if (stackTrace.length > 3) { - Class callingClass = Class.forName(stackTrace[3].getClassName()); - Method callingMethod = callingClass.getMethod(stackTrace[3].getMethodName()); - - if (callingClass.isAnnotationPresent(EnableLogging.class)) { - logger.log(pLogLevel, pMessage); - } else if (callingMethod.isAnnotationPresent(EnableLogging.class)) { - logger.log(pLogLevel, pMessage); - } + return; + } + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + if (stackTrace.length > 3) { + Class callingClass = Class.forName(stackTrace[3].getClassName()); + Method callingMethod = callingClass.getMethod(stackTrace[3].getMethodName()); + + if (callingClass.isAnnotationPresent(EnableLogging.class) || + callingMethod.isAnnotationPresent(EnableLogging.class)) { + logger.log(pLogLevel, pMessage); } } - } catch (Exception pException) { - logger.log(Level.SEVERE, "Failed to log message.", pException); + } catch (Exception ignored) { } } From 71fdba38ca586407711f8847408b1e86c4b0577b Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 9 Oct 2024 02:01:40 +0200 Subject: [PATCH 52/62] Fixed Logging + Added Example Package --- .../example/entity/dragon/DragonEntity.java | 141 +++++++ .../example/entity/dragon/DragonModel.java | 29 ++ .../example/entity/dragon/DragonRender.java | 14 + .../bluelib/example/entity/rex/RexEntity.java | 142 +++++++ .../bluelib/example/entity/rex/RexModel.java | 29 ++ .../bluelib/example/entity/rex/RexRender.java | 14 + .../bluelib/example/event/ClientEvents.java | 24 ++ .../bluelib/example/event/CommonModEvent.java | 21 + .../bluelib/example/event/ReloadHandler.java | 126 ++++++ .../bluelib/example/init/ModEntities.java | 42 ++ .../bluelib/example/proxy/ClientProxy.java | 20 + .../bluelib/example/proxy/CommonProxy.java | 14 + .../bluelib/animations/dragon.animation.json | 63 +++ .../bluelib/animations/rex.animation.json | 51 +++ .../assets/bluelib/geo/dragon.geo.json | 93 +++++ .../resources/assets/bluelib/geo/rex.geo.json | 390 ++++++++++++++++++ .../resources/assets/bluelib/lang/en_us.json | 4 + .../bluelib/textures/entity/dragon/blue.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/dragon/bright.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/dragon/dark.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/dragon/pink.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/rex/brown.png | Bin 0 -> 3454 bytes .../bluelib/textures/entity/rex/green.png | Bin 0 -> 1531 bytes .../bluelib.variant/entity/dragon/blue.json | 14 + .../bluelib.variant/entity/dragon/dragon.json | 24 ++ .../bluelib.variant/entity/dragon/pink.json | 14 + .../data/bluelib.variant/entity/rex/rex.json | 24 ++ .../example/entity/dragon/DragonEntity.java | 141 +++++++ .../example/entity/dragon/DragonModel.java | 30 ++ .../example/entity/dragon/DragonRender.java | 14 + .../bluelib/example/entity/rex/RexEntity.java | 142 +++++++ .../bluelib/example/entity/rex/RexModel.java | 29 ++ .../bluelib/example/entity/rex/RexRender.java | 14 + .../bluelib/example/event/ClientEvents.java | 32 ++ .../bluelib/example/event/ReloadHandler.java | 128 ++++++ .../bluelib/example/init/ModEntities.java | 40 ++ .../bluelib/animations/dragon.animation.json | 63 +++ .../bluelib/animations/rex.animation.json | 51 +++ .../assets/bluelib/geo/dragon.geo.json | 93 +++++ .../resources/assets/bluelib/geo/rex.geo.json | 390 ++++++++++++++++++ .../resources/assets/bluelib/lang/en_us.json | 4 + .../bluelib/textures/entity/dragon/blue.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/dragon/bright.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/dragon/dark.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/dragon/pink.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/rex/brown.png | Bin 0 -> 3454 bytes .../bluelib/textures/entity/rex/green.png | Bin 0 -> 1531 bytes .../bluelib/variant/entity/dragon/blue.json | 14 + .../bluelib/variant/entity/dragon/dragon.json | 24 ++ .../bluelib/variant/entity/dragon/pink.json | 14 + .../data/bluelib/variant/entity/rex/rex.json | 24 ++ .../java/software/bluelib/BlueLibCommon.java | 5 +- .../software/bluelib/BlueLibConstants.java | 8 + .../bluelib/annotations/EnableLogging.java | 21 - .../bluelib/entity/variant/VariantLoader.java | 24 +- .../entity/variant/VariantParameter.java | 22 +- .../entity/variant/base/ParameterBase.java | 21 +- .../bluelib/event/ReloadEventHandler.java | 8 +- .../interfaces/platform/IPlatformHelper.java | 3 + .../interfaces/variant/IVariantEntity.java | 4 +- .../variant/base/IVariantEntityBase.java | 2 +- .../software/bluelib/json/JSONLoader.java | 8 +- .../software/bluelib/json/JSONMerger.java | 9 +- .../utils/conversion/CaseConverterUtils.java | 36 +- .../utils/conversion/MathConverterUtils.java | 4 +- .../bluelib/utils/logging/BaseLogger.java | 56 +-- .../bluelib/utils/math/AlgebraicUtils.java | 9 +- .../bluelib/utils/math/GeometricUtils.java | 20 +- .../bluelib/utils/math/MatrixUtils.java | 8 +- .../bluelib/utils/math/MiscUtils.java | 8 +- .../bluelib/utils/math/RandomGenUtils.java | 8 +- .../bluelib/utils/math/StatisticalUtils.java | 42 +- .../bluelib/utils/minecraft/ChunkUtils.java | 28 +- .../bluelib/utils/variant/ParameterUtils.java | 4 +- fabric/build.gradle | 3 + .../main/java/software/bluelib/BlueLib.java | 11 + .../example/entity/dragon/DragonEntity.java | 141 +++++++ .../example/entity/dragon/DragonModel.java | 29 ++ .../example/entity/dragon/DragonRender.java | 14 + .../bluelib/example/entity/rex/RexEntity.java | 142 +++++++ .../bluelib/example/entity/rex/RexModel.java | 29 ++ .../bluelib/example/entity/rex/RexRender.java | 14 + .../bluelib/example/event/ReloadHandler.java | 133 ++++++ .../bluelib/example/init/ClientInit.java | 14 + .../bluelib/example/init/ModEntities.java | 33 ++ .../bluelib/animations/dragon.animation.json | 63 +++ .../bluelib/animations/rex.animation.json | 51 +++ .../assets/bluelib/geo/dragon.geo.json | 93 +++++ .../resources/assets/bluelib/geo/rex.geo.json | 390 ++++++++++++++++++ .../resources/assets/bluelib/lang/en_us.json | 4 + .../bluelib/textures/entity/dragon/blue.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/dragon/bright.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/dragon/dark.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/dragon/pink.png | Bin 0 -> 676 bytes .../bluelib/textures/entity/rex/brown.png | Bin 0 -> 3454 bytes .../bluelib/textures/entity/rex/green.png | Bin 0 -> 1531 bytes .../bluelib/variant/entity/dragon/blue.json | 14 + .../bluelib/variant/entity/dragon/dragon.json | 24 ++ .../bluelib/variant/entity/dragon/pink.json | 14 + .../data/bluelib/variant/entity/rex/rex.json | 24 ++ fabric/src/main/resources/fabric.mod.json | 8 +- 101 files changed, 3917 insertions(+), 229 deletions(-) create mode 100644 Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java create mode 100644 Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java create mode 100644 Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java create mode 100644 Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java create mode 100644 Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java create mode 100644 Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java create mode 100644 Forge/src/main/java/software/bluelib/example/event/ClientEvents.java create mode 100644 Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java create mode 100644 Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java create mode 100644 Forge/src/main/java/software/bluelib/example/init/ModEntities.java create mode 100644 Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java create mode 100644 Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java create mode 100644 Forge/src/main/resources/assets/bluelib/animations/dragon.animation.json create mode 100644 Forge/src/main/resources/assets/bluelib/animations/rex.animation.json create mode 100644 Forge/src/main/resources/assets/bluelib/geo/dragon.geo.json create mode 100644 Forge/src/main/resources/assets/bluelib/geo/rex.geo.json create mode 100644 Forge/src/main/resources/assets/bluelib/lang/en_us.json create mode 100644 Forge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png create mode 100644 Forge/src/main/resources/assets/bluelib/textures/entity/dragon/bright.png create mode 100644 Forge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png create mode 100644 Forge/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png create mode 100644 Forge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png create mode 100644 Forge/src/main/resources/assets/bluelib/textures/entity/rex/green.png create mode 100644 Forge/src/main/resources/data/bluelib.variant/entity/dragon/blue.json create mode 100644 Forge/src/main/resources/data/bluelib.variant/entity/dragon/dragon.json create mode 100644 Forge/src/main/resources/data/bluelib.variant/entity/dragon/pink.json create mode 100644 Forge/src/main/resources/data/bluelib.variant/entity/rex/rex.json create mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java create mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java create mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java create mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java create mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java create mode 100644 NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java create mode 100644 NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java create mode 100644 NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java create mode 100644 NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java create mode 100644 NeoForge/src/main/resources/assets/bluelib/animations/dragon.animation.json create mode 100644 NeoForge/src/main/resources/assets/bluelib/animations/rex.animation.json create mode 100644 NeoForge/src/main/resources/assets/bluelib/geo/dragon.geo.json create mode 100644 NeoForge/src/main/resources/assets/bluelib/geo/rex.geo.json create mode 100644 NeoForge/src/main/resources/assets/bluelib/lang/en_us.json create mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png create mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/bright.png create mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png create mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png create mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png create mode 100644 NeoForge/src/main/resources/assets/bluelib/textures/entity/rex/green.png create mode 100644 NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/blue.json create mode 100644 NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/dragon.json create mode 100644 NeoForge/src/main/resources/data/bluelib/variant/entity/dragon/pink.json create mode 100644 NeoForge/src/main/resources/data/bluelib/variant/entity/rex/rex.json delete mode 100644 common/src/main/java/software/bluelib/annotations/EnableLogging.java create mode 100644 fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java create mode 100644 fabric/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java create mode 100644 fabric/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java create mode 100644 fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java create mode 100644 fabric/src/main/java/software/bluelib/example/entity/rex/RexModel.java create mode 100644 fabric/src/main/java/software/bluelib/example/entity/rex/RexRender.java create mode 100644 fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java create mode 100644 fabric/src/main/java/software/bluelib/example/init/ClientInit.java create mode 100644 fabric/src/main/java/software/bluelib/example/init/ModEntities.java create mode 100644 fabric/src/main/resources/assets/bluelib/animations/dragon.animation.json create mode 100644 fabric/src/main/resources/assets/bluelib/animations/rex.animation.json create mode 100644 fabric/src/main/resources/assets/bluelib/geo/dragon.geo.json create mode 100644 fabric/src/main/resources/assets/bluelib/geo/rex.geo.json create mode 100644 fabric/src/main/resources/assets/bluelib/lang/en_us.json create mode 100644 fabric/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png create mode 100644 fabric/src/main/resources/assets/bluelib/textures/entity/dragon/bright.png create mode 100644 fabric/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png create mode 100644 fabric/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png create mode 100644 fabric/src/main/resources/assets/bluelib/textures/entity/rex/brown.png create mode 100644 fabric/src/main/resources/assets/bluelib/textures/entity/rex/green.png create mode 100644 fabric/src/main/resources/data/bluelib/variant/entity/dragon/blue.json create mode 100644 fabric/src/main/resources/data/bluelib/variant/entity/dragon/dragon.json create mode 100644 fabric/src/main/resources/data/bluelib/variant/entity/dragon/pink.json create mode 100644 fabric/src/main/resources/data/bluelib/variant/entity/rex/rex.json diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java new file mode 100644 index 00000000..130d2740 --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -0,0 +1,141 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.dragon; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.*; +import net.minecraft.world.entity.ai.attributes.AttributeSupplier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; +import software.bluelib.interfaces.variant.IVariantAccessor; +import software.bluelib.interfaces.variant.IVariantEntity; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; +import software.bluelib.utils.variant.ParameterUtils; + +/** + * A {@code DragonEntity} class representing a dragon entity in the game, which extends {@link TamableAnimal} + * and implements {@link IVariantEntity} and {@link GeoEntity}. + *

          + * This class manages the dragon's variant system, its data synchronization, and integrates with the GeckoLib + * animation system. + *

          + * + *

          + * Key Methods: + *

            + *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
          • + *
          • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
          • + *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • + *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • + *
          + *

          + * + * @author MeAlam + * @since 1.0.0 + */ +public class DragonEntity extends TamableAnimal implements IVariantEntity, GeoEntity { + /** + * The name of the entity. + * + * @since 1.0.0 + */ + protected final String entityName = "dragon"; + + /** + * Constructs a new {@link DragonEntity} instance with the specified entity type and level. + * + * @param pEntityType {@link EntityType} - The type of the entity. + * @param pLevel {@link Level} - The level in which the entity is created. + * @author MeAlam + * @since 1.0.0 + */ + public DragonEntity(EntityType pEntityType, Level pLevel) { + super(pEntityType, pLevel); + } + + public void setVariantName(String pVariantName) { + ((IVariantAccessor) this).setEntityVariantName(pVariantName); + } + + public String getVariantName() { + return ((IVariantAccessor) this).getEntityVariantName(); + } + + /** + * Finalizes the spawning of the dragon entity. + *

          + * This method sets up the variant for the entity and connects parameters if needed. + *

          + * + * @param pLevel {@link ServerLevelAccessor} - The level in which the entity is spawned. + * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. + * @param pReason {@link MobSpawnType} - The reason for spawning the entity. + * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. + * @return {@link SpawnGroupData} - Updated spawn data. + * @author MeAlam + * @since 1.0.0 + */ + @Override + public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { + if (getVariantName() == null || getVariantName().isEmpty()) { + setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); + ParameterUtils.ParameterBuilder.forVariant(entityName, this.getVariantName()) + .withParameter("customParameter") + .withParameter("int") + .withParameter("bool") + .withParameter("array") + .connect(); + } + BaseLogger.log(BaseLogLevel.SUCCESS, "Dragon Spawned with Variant: " + getVariantName(), true); + return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); + } + + + /** + * All Code below this Fragment is not Library Related!!! + */ + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public static AttributeSupplier.Builder createAttributes() { + return Mob.createMobAttributes() + .add(Attributes.MOVEMENT_SPEED, 0.3) + .add(Attributes.MAX_HEALTH, 10) + .add(Attributes.ARMOR, 0) + .add(Attributes.ATTACK_DAMAGE, 3) + .add(Attributes.FOLLOW_RANGE, 16) + .add(Attributes.FLYING_SPEED, 0.3); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return cache; + } + + @Nullable + @Override + public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { + return null; + } + + @Override + public boolean isFood(@NotNull ItemStack pItemStack) { + return false; + } +} diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java new file mode 100644 index 00000000..2979ca65 --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java @@ -0,0 +1,29 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.dragon; + +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; +import software.bluelib.BlueLibConstants; + +public class DragonModel extends GeoModel { + + + // Get the Model Location + @Override + public ResourceLocation getModelResource(DragonEntity pObject) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/dragon.geo.json"); + } + + // Get the Texture Location + @Override + public ResourceLocation getTextureResource(DragonEntity pObject) { + return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); + } + + // Get the Animation Location + @Override + public ResourceLocation getAnimationResource(DragonEntity pAnimatable) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/dragon.animation.json"); + } +} diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java new file mode 100644 index 00000000..c770ac48 --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java @@ -0,0 +1,14 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.dragon; + +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class DragonRender extends GeoEntityRenderer { + + // Render the entity + public DragonRender(EntityRendererProvider.Context pRenderManager) { + super(pRenderManager, new DragonModel()); + } +} diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java new file mode 100644 index 00000000..8c3d1fa7 --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -0,0 +1,142 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.rex; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.*; +import net.minecraft.world.entity.ai.attributes.AttributeSupplier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; +import software.bluelib.interfaces.variant.IVariantAccessor; +import software.bluelib.interfaces.variant.IVariantEntity; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; +import software.bluelib.utils.variant.ParameterUtils; + +/** + * A {@code RexEntity} class representing a Rex entity in the game, which extends {@link TamableAnimal} + * and implements {@link IVariantEntity} and {@link GeoEntity}. + *

          + * This class manages the Rex's variant system, its data synchronization, and integrates with the GeckoLib + * animation system. + *

          + * + *

          + * Key Methods: + *

            + *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
          • + *
          • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
          • + *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • + *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • + *
          • {@link #setVariantName(String)} - Sets the variant name of the Rex.
          • + *
          • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
          • + *
          + *

          + * + * @author MeAlam + * @since 1.0.0 + */ +public class RexEntity extends TamableAnimal implements IVariantEntity, GeoEntity { + /** + * The name of the entity. + * + * @since 1.0.0 + */ + protected final String entityName = "rex"; + + /** + * Constructs a new {@link RexEntity} instance with the specified entity type and level. + * + * @param pEntityType {@link EntityType} - The type of the entity. + * @param pLevel {@link Level} - The level in which the entity is created. + * @author MeAlam + * @since 1.0.0 + */ + public RexEntity(EntityType pEntityType, Level pLevel) { + super(pEntityType, pLevel); + } + + public void setVariantName(String pVariantName) { + ((IVariantAccessor) this).setEntityVariantName(pVariantName); + } + + public String getVariantName() { + return ((IVariantAccessor) this).getEntityVariantName(); + } + + /** + * Finalizes the spawning of the Rex entity. + *

          + * This method sets up the variant for the entity and connects parameters if needed. + *

          + * + * @param pLevel {@link ServerLevelAccessor} - The level in which the entity is spawned. + * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. + * @param pReason {@link MobSpawnType} - The reason for spawning the entity. + * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. + * @return {@link SpawnGroupData} - Updated spawn data. + * @author MeAlam + * @since 1.0.0 + */ + @Override + public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { + if (getVariantName() == null || getVariantName().isEmpty()) { + this.setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); + ParameterUtils.ParameterBuilder.forVariant(entityName, this.getVariantName()) + .withParameter("customParameter") + .withParameter("int") + .withParameter("bool") + .withParameter("array") + .connect(); + } + BaseLogger.log(BaseLogLevel.SUCCESS, "Dragon Spawned with Variant: " + getVariantName(), true); + return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); + } + + /** + * All Code below this Fragment is not Library Related!!! + */ + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public static AttributeSupplier.Builder createAttributes() { + return Mob.createMobAttributes() + .add(Attributes.MOVEMENT_SPEED, 0.3) + .add(Attributes.MAX_HEALTH, 10) + .add(Attributes.ARMOR, 0) + .add(Attributes.ATTACK_DAMAGE, 3) + .add(Attributes.FOLLOW_RANGE, 16) + .add(Attributes.FLYING_SPEED, 0.3); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return cache; + } + + @Nullable + @Override + public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { + return null; + } + + @Override + public boolean isFood(@NotNull ItemStack pItemStack) { + return false; + } +} diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java new file mode 100644 index 00000000..a5f87895 --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java @@ -0,0 +1,29 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.rex; + +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; +import software.bluelib.BlueLibConstants; + +public class RexModel extends GeoModel { + + + // Get the Model Location + @Override + public ResourceLocation getModelResource(RexEntity pObject) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/rex.geo.json"); + } + + // Get the Texture Location + @Override + public ResourceLocation getTextureResource(RexEntity pObject) { + return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); + } + + // Get the Animation Location + @Override + public ResourceLocation getAnimationResource(RexEntity pAnimatable) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/rex.animation.json"); + } +} diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java new file mode 100644 index 00000000..776c5920 --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java @@ -0,0 +1,14 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.rex; + +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class RexRender extends GeoEntityRenderer { + + // Render the entity + public RexRender(EntityRendererProvider.Context pRenderManager) { + super(pRenderManager, new RexModel()); + } +} diff --git a/Forge/src/main/java/software/bluelib/example/event/ClientEvents.java b/Forge/src/main/java/software/bluelib/example/event/ClientEvents.java new file mode 100644 index 00000000..03e70c8e --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/event/ClientEvents.java @@ -0,0 +1,24 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.event; + +import net.minecraft.client.renderer.entity.EntityRenderers; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.common.Mod; +import software.bluelib.BlueLibConstants; +import software.bluelib.example.entity.dragon.DragonRender; +import software.bluelib.example.entity.rex.RexRender; +import software.bluelib.example.init.ModEntities; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; + +@Mod.EventBusSubscriber(modid = BlueLibConstants.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class ClientEvents { + + public static void registerRenderers() { + // Register the renderer for all the Entities + EntityRenderers.register(ModEntities.DRAGON.get(), DragonRender::new); + EntityRenderers.register(ModEntities.REX.get(), RexRender::new); + BaseLogger.log(BaseLogLevel.INFO, "Registered Renderers for Entities", true); + } +} diff --git a/Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java b/Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java new file mode 100644 index 00000000..2a760459 --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java @@ -0,0 +1,21 @@ +package software.bluelib.example.event; + +import net.minecraftforge.event.entity.EntityAttributeCreationEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import software.bluelib.BlueLibConstants; +import software.bluelib.example.entity.dragon.DragonEntity; +import software.bluelib.example.entity.rex.RexEntity; +import software.bluelib.example.init.ModEntities; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; + +@Mod.EventBusSubscriber(modid = BlueLibConstants.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +public class CommonModEvent { + @SubscribeEvent + public static void onAttributeCreate(EntityAttributeCreationEvent pEvent) { + pEvent.put(ModEntities.DRAGON.get(), DragonEntity.createAttributes().build()); + pEvent.put(ModEntities.REX.get(), RexEntity.createAttributes().build()); + BaseLogger.log(BaseLogLevel.INFO, "Registered Attributes for Entities", true); + } +} diff --git a/Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java b/Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java new file mode 100644 index 00000000..e6c5a509 --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java @@ -0,0 +1,126 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.event; + +import net.minecraft.server.MinecraftServer; +import net.minecraftforge.event.AddReloadListenerEvent; +import net.minecraftforge.event.server.ServerStartingEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import software.bluelib.BlueLibConstants; +import software.bluelib.event.ReloadEventHandler; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * A {@code ReloadHandler} class that handles server start and reload events related to entity variants. + *

          + * This class extends {@link ReloadEventHandler} and implements event handling for server starting and reloading, + * ensuring that entity variant data is properly loaded and refreshed. + *

          + * + *

          + * Key Methods: + *

            + *
          • {@link #onServerStart(ServerStartingEvent)} - Handles server starting events to initialize entity variants.
          • + *
          • {@link #onReload(AddReloadListenerEvent)} - Handles reload events to refresh entity variants.
          • + *
          • {@link #LoadEntityVariants(MinecraftServer)} - Loads entity variants from JSON files into the server.
          • + *
          + *

          + * + * @author MeAlam + * @since 1.0.0 + */ +public class ReloadHandler extends ReloadEventHandler { + + /** + * The {@link MinecraftServer} instance for the server handling the events. + *

          + * This is initialized when the server starts and used to load entity variants. + *

          + * + * @since 1.0.0 + */ + private static MinecraftServer server; + + /** + * Handles the server starting event to initialize the {@link MinecraftServer} instance + * and load entity variants. + * + * @param pEvent {@link ServerStartingEvent} - The event triggered when the server starts. + * @author MeAlam + * @since 1.0.0 + */ + @SubscribeEvent + public static void onServerStart(ServerStartingEvent pEvent) { + server = pEvent.getServer(); + ReloadHandler.LoadEntityVariants(server); + BaseLogger.log(BaseLogLevel.INFO, "Entity variants loaded.", true); + } + + /** + * Handles the reload event by scheduling a task to reload entity variants. + *

          + * This method schedules the {@code LoadEntityVariants} method to run after a short delay. + *

          + * + * @param pEvent {@link AddReloadListenerEvent} - The event triggered when a reload occurs. + * @author MeAlam + * @since 1.0.0 + */ + @SubscribeEvent + public static void onReload(AddReloadListenerEvent pEvent) { + if (server != null) { + BlueLibConstants.SCHEDULER.schedule(() -> { + server.execute(() -> { + ReloadHandler.LoadEntityVariants(server); + BaseLogger.log(BaseLogLevel.INFO, "Entity variants reloaded.", true); + }); + }, 1, TimeUnit.SECONDS); + } + } + + /** + * The base path for entity variant JSON files. + *

          + * This path is used to locate the files that contain variant data for entities. + *

          + * + * @since 1.0.0 + */ + private static final String basePath = "variant/entity/"; + + /** + * A {@link List} of entity names for which variants will be loaded. + *

          + * This list defines which entities will have their variants loaded from JSON files. + *

          + * + * @since 1.0.0 + */ + private static final List entityNames = Arrays.asList("dragon", "rex"); + + /** + * Loads entity variants from JSON files into the {@link MinecraftServer}. + *

          + * This method iterates through the list of entity names, constructs file paths, and registers + * entity variants using the {@link ReloadEventHandler}. + *

          + * + * @param pServer {@link MinecraftServer} - The server on which the entity variants will be loaded. + * @author MeAlam + * @since 1.0.0 + */ + public static void LoadEntityVariants(MinecraftServer pServer) { + for (String entityName : entityNames) { + String folderPath = basePath + entityName; + ReloadEventHandler.registerEntityVariants(folderPath, pServer, BlueLibConstants.MOD_ID, entityName); + BaseLogger.log(BaseLogLevel.INFO, "Entity variants loaded for " + entityName + ".", true); + } + } +} diff --git a/Forge/src/main/java/software/bluelib/example/init/ModEntities.java b/Forge/src/main/java/software/bluelib/example/init/ModEntities.java new file mode 100644 index 00000000..c7c5c3e0 --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/init/ModEntities.java @@ -0,0 +1,42 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.init; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobCategory; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import software.bluelib.BlueLibConstants; +import software.bluelib.example.entity.dragon.DragonEntity; +import software.bluelib.example.entity.rex.RexEntity; + +public class ModEntities { + public static final DeferredRegister> REGISTER = + DeferredRegister.create(ForgeRegistries.ENTITY_TYPES, BlueLibConstants.MOD_ID); + + // List of Entities + public static final RegistryObject> DRAGON = + REGISTER.register("example_one", () -> EntityType.Builder.of(DragonEntity::new, MobCategory.AMBIENT) + .setShouldReceiveVelocityUpdates(true) + .setTrackingRange(64) + .setUpdateInterval(3) + .fireImmune() + .sized(0.6f, 1.8f) + .build(ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "dragon").toString())); + + public static final RegistryObject> REX = + REGISTER.register("example_two", () -> EntityType.Builder.of(RexEntity::new, MobCategory.AMBIENT) + .setShouldReceiveVelocityUpdates(true) + .setTrackingRange(64) + .setUpdateInterval(3) + .fireImmune() + .sized(0.6f, 1.8f) + .build(ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "rex").toString())); + + public static void register(IEventBus eventBus) { + REGISTER.register(eventBus); + } +} diff --git a/Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java b/Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java new file mode 100644 index 00000000..eb894483 --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java @@ -0,0 +1,20 @@ +package software.bluelib.example.proxy; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.common.Mod; +import software.bluelib.BlueLibConstants; +import software.bluelib.example.event.ClientEvents; + +@Mod.EventBusSubscriber(modid = BlueLibConstants.MOD_ID, value = Dist.CLIENT) +public class ClientProxy extends CommonProxy { + + @Override + public void postInit() { + } + + @Override + public void clientInit() { + super.clientInit(); + ClientEvents.registerRenderers(); + } +} diff --git a/Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java b/Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java new file mode 100644 index 00000000..33ae075c --- /dev/null +++ b/Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java @@ -0,0 +1,14 @@ +package software.bluelib.example.proxy; + +import net.minecraftforge.fml.common.Mod; +import software.bluelib.BlueLibConstants; + +@Mod.EventBusSubscriber(modid = BlueLibConstants.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +public class CommonProxy { + + public void postInit() { + } + + public void clientInit() { + } +} diff --git a/Forge/src/main/resources/assets/bluelib/animations/dragon.animation.json b/Forge/src/main/resources/assets/bluelib/animations/dragon.animation.json new file mode 100644 index 00000000..0b02f765 --- /dev/null +++ b/Forge/src/main/resources/assets/bluelib/animations/dragon.animation.json @@ -0,0 +1,63 @@ +{ + "format_version": "1.8.0", + "animations": { + "test": { + "loop": true, + "bones": { + "Body": { + "rotation": { + "vector": [-20.44582, 11.73507, -4.3361], + "easing": "linear" + }, + "position": { + "vector": [0, -1, 0], + "easing": "linear" + } + }, + "leftleg": { + "rotation": { + "vector": [0, 22.5, 0], + "easing": "linear" + } + }, + "rightleg": { + "rotation": { + "vector": [0, -22.5, 0], + "easing": "linear" + } + }, + "rightwing1": { + "rotation": { + "vector": [0, 0, -20], + "easing": "linear" + } + }, + "leftwing": { + "rotation": { + "vector": [0, 0, -10], + "easing": "linear" + } + }, + "leftwing1": { + "rotation": { + "vector": [0, 0, 30], + "easing": "linear" + } + }, + "neck": { + "rotation": { + "vector": [-40, 0, 0], + "easing": "linear" + } + }, + "Head": { + "rotation": { + "vector": [72.5, 0, 0], + "easing": "linear" + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/Forge/src/main/resources/assets/bluelib/animations/rex.animation.json b/Forge/src/main/resources/assets/bluelib/animations/rex.animation.json new file mode 100644 index 00000000..5d8891b4 --- /dev/null +++ b/Forge/src/main/resources/assets/bluelib/animations/rex.animation.json @@ -0,0 +1,51 @@ +{ + "format_version": "1.8.0", + "animations": { + "animation2": { + "loop": true, + "bones": { + "body": { + "rotation": { + "vector": [0, -15, 0] + } + }, + "tail2": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail3": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail4": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail5": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail6": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "neck": { + "rotation": { + "vector": [0, -2.5, 0] + } + }, + "head": { + "rotation": { + "vector": [0, -20, 0] + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/Forge/src/main/resources/assets/bluelib/geo/dragon.geo.json b/Forge/src/main/resources/assets/bluelib/geo/dragon.geo.json new file mode 100644 index 00000000..8f038886 --- /dev/null +++ b/Forge/src/main/resources/assets/bluelib/geo/dragon.geo.json @@ -0,0 +1,93 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 64, + "texture_height": 64, + "visible_bounds_width": 4, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [0, 0.75, 0] + }, + "bones": [ + { + "name": "Body", + "pivot": [-0.16667, 5, -1], + "cubes": [ + {"origin": [-2, 4, 1], "size": [4, 2, 4], "uv": [17, 10]}, + {"origin": [-3, 4, -4], "size": [6, 2, 5], "uv": [0, 14]} + ] + }, + { + "name": "leftleg", + "parent": "Body", + "pivot": [1.5, 5, 5], + "cubes": [ + {"origin": [1.5, 3, 4.5], "size": [0, 4, 3], "pivot": [1.5, 5, 6], "rotation": [90, 0, 90], "uv": [0, 0]} + ] + }, + { + "name": "rightleg", + "parent": "Body", + "pivot": [-1.5, 5, 5], + "cubes": [ + {"origin": [-1.5, 3, 4.5], "size": [0, 4, 3], "pivot": [-1.5, 5, 6], "rotation": [90, 0, -90], "uv": [0, 0], "mirror": true} + ] + }, + { + "name": "rightwing", + "parent": "Body", + "pivot": [-2.5, 5, -3.5], + "cubes": [ + {"origin": [-10, 5, -5], "size": [7, 0, 7], "uv": [-7, 28], "mirror": true} + ] + }, + { + "name": "rightwing1", + "parent": "rightwing", + "pivot": [-9.5, 5, -1.5], + "cubes": [ + {"origin": [-17, 5, -5], "size": [7, 0, 7], "uv": [43, 0], "mirror": true} + ] + }, + { + "name": "leftwing", + "parent": "Body", + "pivot": [2.5, 5, -3.5], + "cubes": [ + {"origin": [3, 5, -5], "size": [7, 0, 7], "uv": [-7, 28]} + ] + }, + { + "name": "leftwing1", + "parent": "leftwing", + "pivot": [9.5, 5, -1.5], + "cubes": [ + {"origin": [10, 5, -5], "size": [7, 0, 7], "uv": [43, 0]} + ] + }, + { + "name": "neck", + "parent": "Body", + "pivot": [0, 5, -4], + "cubes": [ + {"origin": [-1, 4, -8], "size": [2, 2, 4], "uv": [10, 21]} + ] + }, + { + "name": "Head", + "parent": "neck", + "pivot": [0, 4.8, -7.5], + "cubes": [ + {"origin": [-1.5, 4, -12], "size": [3, 3, 4], "uv": [18, 17]}, + {"origin": [0, 6, -15], "size": [0, 3, 7], "uv": [0, 14]}, + {"origin": [-1, 4, -16], "size": [2, 2, 4], "uv": [21, 0]}, + {"origin": [-1, 3, -16], "size": [2, 1, 1], "uv": [29, 0]}, + {"origin": [0, 7, -8], "size": [0, 1, 3], "uv": [0, 23]} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/Forge/src/main/resources/assets/bluelib/geo/rex.geo.json b/Forge/src/main/resources/assets/bluelib/geo/rex.geo.json new file mode 100644 index 00000000..3d18bac7 --- /dev/null +++ b/Forge/src/main/resources/assets/bluelib/geo/rex.geo.json @@ -0,0 +1,390 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 512, + "texture_height": 512, + "visible_bounds_width": 29, + "visible_bounds_height": 7.5, + "visible_bounds_offset": [0, 3.25, 0] + }, + "bones": [ + { + "name": "Tyrannosaurus", + "pivot": [0, 0, 0] + }, + { + "name": "body", + "parent": "Tyrannosaurus", + "pivot": [0, 72, 0], + "cubes": [ + {"origin": [-19, 47, -8], "size": [38, 45, 34], "uv": [124, 51]}, + {"origin": [-15.475, 51.23327, -14.01496], "size": [31, 45, 35], "pivot": [0.025, 74.40827, 4.38504], "rotation": [-12.75, 0, 0], "uv": [130, 50]}, + {"origin": [-16, 40, -22.525], "size": [32, 16, 40], "inflate": -0.05, "pivot": [0, 72, 0.275], "rotation": [17.5, 0, 0], "uv": [0, 160]}, + {"origin": [-16, 54, -54], "size": [32, 37, 46], "uv": [1, 1]}, + {"origin": [-16, 71.46448, -54.53145], "size": [32, 30, 48], "inflate": -0.25, "pivot": [0, 89.46448, 3.46855], "rotation": [8.75, 0, 0], "uv": [-1, -1]}, + {"origin": [-16, 28.37894, -42.36923], "size": [32, 21, 49], "inflate": -0.025, "pivot": [0, 73.37894, 12.63077], "rotation": [-24, 0, 0], "uv": [0, 85]} + ] + }, + { + "name": "arm2", + "parent": "body", + "pivot": [13.56731, 58.46159, -45.9607], + "rotation": [29.07337, 19.05681, -20.20848], + "cubes": [ + {"origin": [12.56731, 47.46159, -47.9607], "size": [3, 11, 5], "uv": [111, 0]} + ] + }, + { + "name": "bone2", + "parent": "arm2", + "pivot": [15.06274, 49.29312, -45.32771], + "rotation": [-27.154, -2.96386, 4.54476], + "cubes": [ + {"origin": [13.13695, 39.306, -44.80271], "size": [2, 6, 2], "inflate": -0.075, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [0, 0]}, + {"origin": [14.86195, 37.306, -44.75271], "size": [0, 3, 2], "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [36, 26]}, + {"origin": [12.13695, 44.306, -47.52771], "size": [3, 5, 5], "inflate": -0.125, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [165, 257]} + ] + }, + { + "name": "bone3", + "parent": "bone2", + "pivot": [13.25685, 45.11756, -46.37771], + "rotation": [-14.50257, -2.95519, -2.10666], + "cubes": [ + {"origin": [13.13695, 41.306, -47.37771], "size": [2, 4, 2], "inflate": -0.075, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [0, 28]}, + {"origin": [14.86195, 39.306, -47.37771], "size": [0, 3, 2], "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [36, 29]} + ] + }, + { + "name": "arm3", + "parent": "body", + "pivot": [-13.56731, 58.46159, -45.9607], + "rotation": [29.07337, -19.05681, 20.20848], + "cubes": [ + {"origin": [-15.56731, 47.46159, -47.9607], "size": [3, 11, 5], "uv": [111, 0], "mirror": true} + ] + }, + { + "name": "bone4", + "parent": "arm3", + "pivot": [-15.06274, 49.29312, -45.32771], + "rotation": [-27.154, 2.96386, -4.54476], + "cubes": [ + {"origin": [-15.13695, 39.306, -44.80271], "size": [2, 6, 2], "inflate": -0.075, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [0, 0], "mirror": true}, + {"origin": [-14.86195, 37.306, -44.75271], "size": [0, 3, 2], "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [36, 26], "mirror": true}, + {"origin": [-15.13695, 44.306, -47.52771], "size": [3, 5, 5], "inflate": -0.125, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [165, 257], "mirror": true} + ] + }, + { + "name": "bone5", + "parent": "bone4", + "pivot": [-13.25685, 45.11756, -46.37771], + "rotation": [-14.50257, 2.95519, 2.10666], + "cubes": [ + {"origin": [-15.13695, 41.306, -47.37771], "size": [2, 4, 2], "inflate": -0.075, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [0, 28], "mirror": true}, + {"origin": [-14.86195, 39.306, -47.37771], "size": [0, 3, 2], "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [36, 29], "mirror": true} + ] + }, + { + "name": "tail1", + "parent": "body", + "pivot": [0, 82.97049, 21.3522], + "cubes": [ + {"origin": [-15, 55.74549, 21.0272], "size": [30, 30, 39], "uv": [123, 128]}, + {"origin": [-15, 71.63781, 17.37365], "size": [30, 28, 35], "inflate": -0.2, "pivot": [0, 60.21281, -16.55135], "rotation": [-10.75, 0, 0], "uv": [127, 132]}, + {"origin": [-15, 39.02049, 26.7772], "size": [30, 13, 37], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [16, 0, 0], "uv": [159, 1]} + ] + }, + { + "name": "tail2", + "parent": "tail1", + "pivot": [0, 82.97049, 56.3522], + "cubes": [ + {"origin": [-10, 62.97049, 56.3522], "size": [20, 21, 38], "uv": [106, 199]}, + {"origin": [-9, 41.02049, 63.3522], "size": [18, 14, 35], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [13, 0, 0], "uv": [173, 3]} + ] + }, + { + "name": "tail3", + "parent": "tail2", + "pivot": [0, 82.97049, 93.3522], + "cubes": [ + {"origin": [-7, 66.97049, 93.3522], "size": [14, 14, 37], "uv": [0, 216]}, + {"origin": [-7, 54.52049, 94.3522], "size": [14, 7, 38], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [5.5, 0, 0], "uv": [174, 0]} + ] + }, + { + "name": "tail4", + "parent": "tail3", + "pivot": [0, 82.97049, 129.3522], + "cubes": [ + {"origin": [-5, 69.97049, 129.3522], "size": [10, 9, 37], "uv": [255, 14]}, + {"origin": [-5, 64.82049, 132.6022], "size": [10, 4, 37], "inflate": -0.025, "pivot": [0, 30.97049, 109.3522], "rotation": [4.75, 0, 0], "uv": [255, 14]} + ] + }, + { + "name": "tail5", + "parent": "tail4", + "pivot": [0, 82.97049, 158.3522], + "cubes": [ + {"origin": [-3, 70.97049, 158.3522], "size": [6, 6, 37], "uv": [149, 257]}, + {"origin": [-3, 69.22961, 165.59014], "size": [6, 3, 30], "inflate": -0.1, "pivot": [0, 70.15461, 147.99014], "rotation": [0.5, 0, 0], "uv": [266, 21]} + ] + }, + { + "name": "tail6", + "parent": "tail5", + "pivot": [0, 82.97049, 182.3522], + "cubes": [ + {"origin": [-2, 71.97049, 182.3522], "size": [4, 4, 37], "uv": [0, 285]}, + {"origin": [-2, 66.99549, 197.7022], "size": [4, 4, 25], "inflate": -0.175, "pivot": [0, 30.97049, 162.3522], "rotation": [4.75, 0, 0], "uv": [12, 297]} + ] + }, + { + "name": "neck", + "parent": "body", + "pivot": [0, 74.22605, -48.50511], + "cubes": [ + {"origin": [-15, 55, -67], "size": [30, 31, 17], "uv": [251, 113]}, + {"origin": [-14.25, 80.39311, -64.98257], "size": [30, 11, 17], "inflate": -1, "pivot": [0.75, 82.39311, -53.98257], "rotation": [24.25, 0, 0], "uv": [251, 113]}, + {"origin": [-10, 66.05, -70.125], "size": [20, 34, 25], "inflate": -0.225, "pivot": [0, 87.575, -69.125], "rotation": [-39.25, 0, 0], "uv": [221, 200]}, + {"origin": [-10, 59.575, -78.125], "size": [20, 13, 25], "inflate": -1.325, "pivot": [0, 87.575, -69.125], "rotation": [-14.25, 0, 0], "uv": [235, 259]}, + {"origin": [-9, 71.2, -85.125], "size": [18, 19, 24], "inflate": -0.325, "pivot": [0, 85.2, -69.125], "rotation": [7.5, 0, 0], "uv": [268, 61]}, + {"origin": [-8, 83.89159, -88.09601], "size": [16, 12, 13], "inflate": -0.275, "pivot": [0, 89.89159, -79.09601], "rotation": [42.5, 0, 0], "uv": [198, 259]}, + {"origin": [-8, 86.39159, -80.39601], "size": [16, 11, 19], "inflate": -0.25, "pivot": [0, 89.89159, -68.09601], "rotation": [2.5, 0, 0], "uv": [111, 0]} + ] + }, + { + "name": "head", + "parent": "neck", + "pivot": [0, 83.05369, -83.57238], + "cubes": [ + {"origin": [-8.725, 71, -101], "size": [17, 19, 19], "uv": [286, 165]}, + {"origin": [-8.775, 84, -101], "size": [17, 2, 7], "inflate": 0.225, "uv": [104, 155]}, + {"origin": [-7, 93.5819, -99.5906], "size": [14, 5, 10], "inflate": -0.05, "pivot": [0, 90.5819, -77.5906], "rotation": [21.5, 0, 0], "uv": [0, 111]}, + {"origin": [-7, 81.46532, -93.49693], "size": [14, 5, 9], "inflate": -0.075, "pivot": [0, 78.46532, -74.49693], "rotation": [-25, 0, 0], "uv": [111, 30]}, + {"origin": [-7, 88.64032, -92.02193], "size": [14, 5, 4], "inflate": -0.125, "uv": [0, 191]}, + {"origin": [9, 86, -102], "size": [4, 3, 13], "inflate": -0.025, "pivot": [7, 80.5, -90.5], "rotation": [0, 0, -17.5], "uv": [149, 277]}, + {"origin": [4.59053, 84.6097, -93.1055], "size": [4, 3, 9], "inflate": -0.05, "pivot": [2.59053, 79.1097, -81.6055], "rotation": [0, -27.5, -17.5], "uv": [255, 23]}, + {"origin": [-8.59053, 84.6097, -93.1055], "size": [4, 3, 9], "inflate": -0.05, "pivot": [-2.59053, 79.1097, -81.6055], "rotation": [0, 27.5, 17.5], "uv": [184, 225]}, + {"origin": [12.62776, 90.52364, -107.52067], "size": [4, 3, 11], "inflate": -0.1, "pivot": [10.62776, 85.02364, -91.02067], "rotation": [27.87149, 36.42355, -5.95346], "uv": [0, 239]}, + {"origin": [-16.62776, 90.52364, -107.52067], "size": [4, 3, 11], "inflate": -0.1, "pivot": [-10.62776, 85.02364, -91.02067], "rotation": [27.87149, -36.42355, 5.95346], "uv": [162, 0]}, + {"origin": [-13, 86, -102], "size": [4, 3, 13], "inflate": -0.025, "pivot": [-7, 80.5, -90.5], "rotation": [0, 0, 17.5], "uv": [109, 216]}, + {"origin": [-7, 78.725, -121], "size": [14, 10, 16], "inflate": -0.05, "pivot": [0, 81.725, -99], "rotation": [27.5, 0, 0], "uv": [300, 243]}, + {"origin": [-7, 78.35, -106], "size": [14, 11, 11], "pivot": [0, 81.35, -99], "rotation": [33.5, 0, 0], "uv": [286, 203]}, + {"origin": [-7, 69.519, -125.21974], "size": [14, 11, 7.85], "inflate": -0.075, "pivot": [0, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [259, 165]}, + {"origin": [-6, 78.519, -128.21974], "size": [11, 0, 7.85], "pivot": [0, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [141, 30]}, + {"origin": [5, 61.519, -128.21974], "size": [0, 17, 6.85], "pivot": [-2, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [234, 45]}, + {"origin": [-5, 61.519, -128.21974], "size": [0, 17, 6.85], "pivot": [2, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [28, 154]}, + {"origin": [-7, 73.394, -115.21974], "size": [14, 10, 6.85], "inflate": -0.1, "pivot": [0, 74.394, -109.21974], "rotation": [110.5, 0, 0], "uv": [65, 237]}, + {"origin": [-7, 84.31148, -108.92962], "size": [14, 4, 6.85], "inflate": -0.15, "pivot": [0, 79.31148, -102.92962], "rotation": [128, 0, 0], "uv": [272, 0]}, + {"origin": [-7, 74.31148, -110.92962], "size": [14, 9, 8.85], "inflate": -0.175, "pivot": [0, 79.31148, -102.92962], "rotation": [88, 0, 0], "uv": [0, 28]}, + {"origin": [-7, 69.019, -122.66974], "size": [14, 10, 7], "inflate": -0.125, "pivot": [0, 72.019, -117.66974], "rotation": [47.5, 0, 0], "uv": [0, 267]} + ] + }, + { + "name": "jaw", + "parent": "head", + "pivot": [0, 73.374, -85.20224], + "cubes": [ + {"origin": [-9.125, 61.47673, -99.81697], "size": [18, 13, 12], "inflate": 0.025, "uv": [184, 200]}, + {"origin": [-9.15, 64.14383, -89.12484], "size": [18, 12, 7], "inflate": 0.075, "pivot": [-3, 73.14383, -68.12484], "rotation": [7.5, 0, 0], "uv": [312, 0]}, + {"origin": [7.8, 70.81044, -97.91351], "size": [1, 6, 9], "uv": [104, 179]}, + {"origin": [7.85, 63.60089, -93.15375], "size": [1, 6, 7], "pivot": [-2.975, 63.60089, -72.15375], "rotation": [-22.5, 0, 0], "uv": [65, 216]}, + {"origin": [-7.125, 72.47673, -98.81697], "size": [14, 14, 16], "inflate": 0.025, "uv": [219, 297]}, + {"origin": [6.375, 68.47673, -105.81697], "size": [0, 18, 14], "uv": [0, 159]}, + {"origin": [-6.625, 68.47673, -105.81697], "size": [0, 18, 14], "uv": [0, 141]}, + {"origin": [7.875, 65.38327, -112.3007], "size": [1, 8, 15], "inflate": -0.05, "pivot": [0, 73.88327, -104.8007], "rotation": [27.5, 0, 0], "uv": [255, 0]}, + {"origin": [-9.125, 65.38327, -112.3007], "size": [1, 8, 15], "inflate": -0.05, "pivot": [0, 73.88327, -104.8007], "rotation": [27.5, 0, 0], "uv": [0, 216]}, + {"origin": [-9.05, 70.81044, -97.91351], "size": [1, 6, 9], "uv": [104, 164]}, + {"origin": [-9.1, 63.60089, -93.15375], "size": [1, 6, 7], "pivot": [2.975, 63.60089, -72.15375], "rotation": [-22.5, 0, 0], "uv": [17, 216]}, + {"origin": [-9.125, 64.31864, -111.04094], "size": [18, 8, 15], "inflate": -0.025, "pivot": [0, 70.56864, -103.54094], "rotation": [17.5, 0, 0], "uv": [149, 300]}, + {"origin": [-6.125, 66.9078, -126.60427], "size": [12, 5, 15], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [126, 257]}, + {"origin": [-6.125, 71.5078, -125.60427], "size": [12, 5, 0], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [62, 155]}, + {"origin": [5.725, 71.5078, -125.60427], "size": [0, 5, 17], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [28, 138]}, + {"origin": [-5.975, 71.5078, -125.60427], "size": [0, 5, 17], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [0, 109]}, + {"origin": [-6.125, 60.70962, -124.43479], "size": [12, 5, 15], "inflate": -0.05, "pivot": [0, 63.78462, -115.43479], "rotation": [-3.5, 0, 0], "uv": [234, 61]}, + {"origin": [-7.125, 61.71743, -111.29498], "size": [14, 5, 16], "inflate": -0.025, "pivot": [0, 66.69243, -101.79498], "rotation": [9.25, 0, 0], "uv": [65, 216]} + ] + }, + { + "name": "leg_left", + "parent": "Tyrannosaurus", + "pivot": [20.42923, 70.7324, 8.85434], + "rotation": [-15.09173, -1.85092, -0.08398], + "cubes": [ + {"origin": [12.54366, 41.02086, -4.25109], "size": [12.875, 42.825, 23.725], "uv": [79, 257]} + ] + }, + { + "name": "leg_left2", + "parent": "leg_left", + "pivot": [21.99279, 43.52539, 1.69711], + "cubes": [ + {"origin": [12.844, 24.19389, 3.09297], "size": [12.4, 20.375, 15.95], "pivot": [21.944, 35.38139, 0.96797], "rotation": [34, 0, 0], "uv": [279, 297]} + ] + }, + { + "name": "leg_left3", + "parent": "leg_left2", + "pivot": [19.76532, 33.92692, 13.90262], + "rotation": [55, 0, 0], + "cubes": [ + {"origin": [14.22989, 14.97535, 9.92239], "size": [10, 19, 9], "inflate": -0.1, "uv": [0, 0]} + ] + }, + { + "name": "leg_left4", + "parent": "leg_left3", + "pivot": [19.76532, 14.92692, 13.90262], + "rotation": [-60, 0, 0], + "cubes": [ + {"origin": [14.22989, 2.41759, 7.14887], "size": [10, 17, 9], "inflate": 0.375, "uv": [0, 85]} + ] + }, + { + "name": "Claw5", + "parent": "leg_left4", + "pivot": [18.03922, 11.69239, 7.72125], + "rotation": [3.25353, -39.92899, -4.10228], + "cubes": [ + {"origin": [19.68942, 7.60244, 18.32118], "size": [2, 5, 6], "inflate": -0.2, "pivot": [20.68942, 10.90244, 16.32118], "rotation": [4, 5, 0], "uv": [19, 239]}, + {"origin": [15.96316, 8.07744, 15.28926], "size": [2, 3, 4], "inflate": 0.5, "pivot": [20.4918, 5.40696, 3.40745], "rotation": [2.31336, 4.43385, 27.58957], "uv": [29, 0]} + ] + }, + { + "name": "leg_left5", + "parent": "leg_left4", + "pivot": [19.76532, 2.72669, 9.58045], + "rotation": [32.5, 0, 0], + "cubes": [ + {"origin": [14.22989, -4.78265, 7.2517], "size": [10, 8, 8], "inflate": 0.35, "uv": [42, 267]} + ] + }, + { + "name": "Claw3", + "parent": "leg_left5", + "pivot": [14.03922, -1.93376, 9.83799], + "rotation": [-11.28559, 36.03256, -29.0792], + "cubes": [ + {"origin": [15.68942, -5.02371, -6.76194], "size": [2, 4, 9], "inflate": -0.2, "pivot": [16.68942, -2.72371, 1.23806], "rotation": [-4, -5, 0], "uv": [78, 267]}, + {"origin": [11.96316, -5.54871, -1.73002], "size": [2, 3, 12], "inflate": 0.5, "pivot": [16.4918, -8.21919, 14.15179], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [45, 298]}, + {"origin": [13.86316, -1.04871, -0.45502], "size": [2, 3, 12], "inflate": 0.4, "pivot": [18.3918, -3.71919, 15.42679], "rotation": [14.70847, -5.40113, 27.33492], "uv": [263, 297]} + ] + }, + { + "name": "Claw2", + "parent": "leg_left5", + "pivot": [18.00128, -1.52657, 8.77203], + "rotation": [6.46283, 10.46681, -26.49382], + "cubes": [ + {"origin": [19.65148, -4.61652, -7.8279], "size": [2, 4, 9], "inflate": -0.2, "pivot": [20.65148, -2.31652, 0.1721], "rotation": [-8.25367, -3.37646, 28.00254], "uv": [259, 183]}, + {"origin": [15.92522, -5.14152, -2.79598], "size": [2, 3, 12], "inflate": 0.5, "pivot": [20.45386, -7.812, 13.08583], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [0, 284]}, + {"origin": [17.82522, -0.64152, -1.52098], "size": [2, 3, 12], "inflate": 0.4, "pivot": [22.35386, -3.312, 14.36083], "rotation": [14.70847, -5.40113, 27.33492], "uv": [45, 283]} + ] + }, + { + "name": "Claw4", + "parent": "leg_left5", + "pivot": [25.00339, -1.78444, 9.60342], + "rotation": [-6.62428, -31.83686, 25.40349], + "cubes": [ + {"origin": [21.35319, -4.87439, -6.99651], "size": [2, 4, 9], "inflate": -0.2, "pivot": [22.35319, -2.57439, 1.00349], "rotation": [-4, 5, 0], "uv": [172, 21]}, + {"origin": [25.07945, -5.39939, -1.96459], "size": [2, 3, 12], "inflate": 0.5, "pivot": [22.55081, -8.06987, 13.91722], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [222, 145]}, + {"origin": [23.17945, -0.89939, -0.68959], "size": [2, 3, 12], "inflate": 0.4, "pivot": [20.65081, -3.56987, 15.19222], "rotation": [14.70847, 5.40113, -27.33492], "uv": [222, 130]} + ] + }, + { + "name": "leg_right", + "parent": "Tyrannosaurus", + "pivot": [-20.42923, 70.7324, 8.85434], + "rotation": [-15.09173, 1.85092, 0.08398], + "cubes": [ + {"origin": [-25.41866, 41.02086, -4.25109], "size": [12.875, 42.825, 23.725], "uv": [79, 257], "mirror": true} + ] + }, + { + "name": "leg_right2", + "parent": "leg_right", + "pivot": [-21.99279, 43.52539, 1.69711], + "cubes": [ + {"origin": [-25.244, 24.19389, 3.09297], "size": [12.4, 20.375, 15.95], "pivot": [-21.944, 35.38139, 0.96797], "rotation": [34, 0, 0], "uv": [279, 297], "mirror": true} + ] + }, + { + "name": "leg_right3", + "parent": "leg_right2", + "pivot": [-19.76532, 33.92692, 13.90262], + "rotation": [55, 0, 0], + "cubes": [ + {"origin": [-24.22989, 14.97535, 9.92239], "size": [10, 19, 9], "inflate": -0.1, "uv": [0, 0], "mirror": true} + ] + }, + { + "name": "leg_right4", + "parent": "leg_right3", + "pivot": [-19.76532, 14.92692, 13.90262], + "rotation": [-60, 0, 0], + "cubes": [ + {"origin": [-24.22989, 2.41759, 7.14887], "size": [10, 17, 9], "inflate": 0.375, "uv": [0, 85], "mirror": true} + ] + }, + { + "name": "Claw6", + "parent": "leg_right4", + "pivot": [-18.03922, 11.69239, 7.72125], + "rotation": [3.25353, 39.92899, 4.10228], + "cubes": [ + {"origin": [-21.68942, 7.60244, 18.32118], "size": [2, 5, 6], "inflate": -0.2, "pivot": [-20.68942, 10.90244, 16.32118], "rotation": [4, -5, 0], "uv": [19, 239], "mirror": true}, + {"origin": [-17.96316, 8.07744, 15.28926], "size": [2, 3, 4], "inflate": 0.5, "pivot": [-20.4918, 5.40696, 3.40745], "rotation": [2.31336, -4.43385, -27.58957], "uv": [29, 0], "mirror": true} + ] + }, + { + "name": "leg_right5", + "parent": "leg_right4", + "pivot": [-19.76532, 2.72669, 9.58045], + "rotation": [32.5, 0, 0], + "cubes": [ + {"origin": [-24.22989, -4.78265, 7.2517], "size": [10, 8, 8], "inflate": 0.35, "uv": [42, 267], "mirror": true} + ] + }, + { + "name": "Claw7", + "parent": "leg_right5", + "pivot": [-14.03922, -1.93376, 9.83799], + "rotation": [-11.28559, -36.03256, 29.0792], + "cubes": [ + {"origin": [-17.68942, -5.02371, -6.76194], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-16.68942, -2.72371, 1.23806], "rotation": [-4, 5, 0], "uv": [78, 267], "mirror": true}, + {"origin": [-13.96316, -5.54871, -1.73002], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-16.4918, -8.21919, 14.15179], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [45, 298], "mirror": true}, + {"origin": [-15.86316, -1.04871, -0.45502], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-18.3918, -3.71919, 15.42679], "rotation": [14.70847, 5.40113, -27.33492], "uv": [263, 297], "mirror": true} + ] + }, + { + "name": "Claw8", + "parent": "leg_right5", + "pivot": [-18.00128, -1.52657, 8.77203], + "rotation": [6.46283, -10.46681, 26.49382], + "cubes": [ + {"origin": [-21.65148, -4.61652, -7.8279], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-20.65148, -2.31652, 0.1721], "rotation": [-8.25367, 3.37646, -28.00254], "uv": [259, 183], "mirror": true}, + {"origin": [-17.92522, -5.14152, -2.79598], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-20.45386, -7.812, 13.08583], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [0, 284], "mirror": true}, + {"origin": [-19.82522, -0.64152, -1.52098], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-22.35386, -3.312, 14.36083], "rotation": [14.70847, 5.40113, -27.33492], "uv": [45, 283], "mirror": true} + ] + }, + { + "name": "Claw9", + "parent": "leg_right5", + "pivot": [-25.00339, -1.78444, 9.60342], + "rotation": [-6.62428, 31.83686, -25.40349], + "cubes": [ + {"origin": [-23.35319, -4.87439, -6.99651], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-22.35319, -2.57439, 1.00349], "rotation": [-4, -5, 0], "uv": [172, 21], "mirror": true}, + {"origin": [-27.07945, -5.39939, -1.96459], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-22.55081, -8.06987, 13.91722], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [222, 145], "mirror": true}, + {"origin": [-25.17945, -0.89939, -0.68959], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-20.65081, -3.56987, 15.19222], "rotation": [14.70847, -5.40113, 27.33492], "uv": [222, 130], "mirror": true} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/Forge/src/main/resources/assets/bluelib/lang/en_us.json b/Forge/src/main/resources/assets/bluelib/lang/en_us.json new file mode 100644 index 00000000..8371c823 --- /dev/null +++ b/Forge/src/main/resources/assets/bluelib/lang/en_us.json @@ -0,0 +1,4 @@ +{ + "entity.bluelib.example_one": "Example", + "entity.bluelib.example_two": "Example" +} \ No newline at end of file diff --git a/Forge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png b/Forge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png new file mode 100644 index 0000000000000000000000000000000000000000..83be2147b8db3aaab415e12dc3b6e9a11a594ea4 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!7Pn|)P)=iz4q{MmaJHmZ`5KTT zT@vIM%(v z(aRpoCoWyiTgojaD&F|F!PdZVM@UbNjptVBj4jLF?f%O$LFQ-3hJ{yuCnpH{RqTF0 zeUaRrN`{moTZcM{69EVLnQmQO%s%OtOoW(UeeqPr*})2&$=17>Km8Ke@%eU3;;UAl z_dE-lA2QvTo9bV8@y{Lo#EEr$XX6_ew|<>1!7nqtJ8%c@3EiH9*VZm)@~qx!CojNR zaWk9uaEODlE8kU9hhhtcCz6N4bsR43<#29rQagW3>HO}AsXY7mmmhHEtgR04`g-ue zwv#SzoSD}|v`Lv6asM;6d&}sM&)V{9@7_H|f67<|ydtWYcW8+%(7BtgsyBPB&W+HL z{c<<=%Uw8|weJPP@nd2)_peY@i7iud+B+%Zp5z_{-H+UVy3Ca989GZ6MLiBbQ|UWb z(Y^fs4MF?eSt1usd41cW*!(Qw)s%f3B9+u@XC5>Aq_Xz;j^mF{Oz1waD#L%1(lgZ; z3|#E;@8(@%^IqToRn(#6{C~ELFSiAJm_Id{T)EuXZp3k!(UWyjbJC~xst$5b_e=bf q?_)BNT$9h7r)_M&3`GSo`xu+NS2^bO6ubn+JAk44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!&W-dj)XETq4p!hyw%*PB>6gHc&$n9=U$y$Y z=ULGFkm<(URR6k*f9~ifPORfQ8{fFN_3La2ewpdrfjf9l==L1Ewstv_XZ2P)c>&If zo7udFLmZS{`L3Ee6k9MnkvtTx<8Wy&hjW9I+WA{b=XXy`<=Mx-{D3oOZFPXx*MkqX zopgEQ%)BO|P0GxO`=7DhTSkX`)|Ov;_wF(JQ^qRb6;Z{!LrZLd&fRoXz1eGZZiJTX zm%F)N?!wuueJ>b}9}~N|e}$?_Y?+eN-boqvB=;!je&qhsWu|1$&{>iw>T&p)O5eGP z?&bGy2-@$?61i~7>)RH^=4TPFrtI4gsia;z^O)Hum9@`z9DjUbLid4H8UCA;o~gcI z;9{45H}4Xg_xk>?q7EhJ|FdO$xh>$s{He+0%H_s(BaX|Ao~)CalRmvyb&z|yU*ey9 qACrmXntbLwZDRvwC@P5A$Jpe($}z8};3Y8L89ZJ6T-G@yGywpxb1(q_ literal 0 HcmV?d00001 diff --git a/Forge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png b/Forge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png new file mode 100644 index 0000000000000000000000000000000000000000..56c9452f64ef0b1e71cecef3b4d07f56ae847633 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!mKPJ^=Hz5!W#wdNPn^2p^s67*vJwUgQb~?#2X}7uGm#gP zQ06^oDwgx$fq}uR<%$^@8TFMVidv2~UU@d+Y|c^~DgvxPb0$Wc7}!LuS~IT`$dN7y z@(X78j}sipEHVW;@~EeaV@SoEw^wiHEjAEfdvHHFiDPf3^4f2I61s;NV<1;Z1`L*Y6Om-ccvH#n)Czom43_rz45ef-N0ICIuk2Y7uw_+Z;f zmp9JLYa-gD%#67I8QZ;ObjW9I`L%cN9-}{HtO8yURm?lI#1`n>O;^>My;kQ&Xvu!L zoBQQ1oXy(zg5mfvv77r>sH()4DLL((lyOgTkAm(;?mt~-O7;w$C5fUQho7nRovY|x ze*cD`{q8K03#YukZBcA~7V&Dzz73H|>a{bEnSD}O`+Udo$0sIqA6S*)ze(wt>I()g zcKLVnF0py9@Bb?5P;&l1TgI2$0zS;2noO=-ZfrN=xXkFuI;lD7(|c71xu^Rj{>k?- onMkh5XU@|$HeiOLf|z}bP2Q^<^Lh$i0^^;*)78&qol`;+0O_S2&j0`b literal 0 HcmV?d00001 diff --git a/Forge/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png b/Forge/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png new file mode 100644 index 0000000000000000000000000000000000000000..adbd4aba3aedfc3c346c7fcbcd858cbe4dd261e6 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!Zjwt65OA~RHu2!IKd|xH`;UJotCY^rs5}_f`{vw>EiO$N z3LOzw<`r~)`(`)e=Yh7PEk`d-JKbu&a%s|urSjIR6`Z;x41ng`DxW(eV9(;TfP5fF zx+KUinBhN8a3r(H6zIsKo-U3d6?5KRy`8t%K!EMR{p2K$y_w2uzx|D07t}vHbT_ZS zqnACFPh7g3x0G8Pb3e8>o{E6%i-MMq;~$6()ryJQ+f9BFF)YSSz8_8_4VL` zZ6{scI5V$_Xp=HC;{IoB_m!M8-n(`vqUbO^7^(#vH4lVt10_7L@KG*&OB!JNoDQx9mgM^n9zM-Rfhj2rDv)y z7`WKw-_5(k=DoiEtEfZC`TuMgUv3NdFn?+?xpKL&-H78dqbKX6=A=*WRUPD>?w9x{ q-^XMkxh9`EPutjl8Hx&G_AxejuX4=mDR>EtcLq;aKbLh*2~7ZCIW7SJ literal 0 HcmV?d00001 diff --git a/Forge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png b/Forge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png new file mode 100644 index 0000000000000000000000000000000000000000..f2956d0504901ccd33fb2067b7631ba08471c5ce GIT binary patch literal 3454 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 or57IkfgP>p|9}4H3?K* zd$|Vy0Lxt%z&JT@wO!)n0A&PtxcTWHMQ;CCUK+VbR@PgIE_Q-#4VZ+o>m>4&1Ni!+e7d%l_n? zxZ~ZcB#F9yLg{*Zse~b2F@UYst7MK&{iUQ_aG5EvBgvGNXSSOn&)a!Pwl4YxCIRZr zrAF;ib-vH8++2$fyhbC(n*6E`H_m9e5j)dx#4vTTIM(N7SJ&DT!#AwbRgg-JQwN5Q zx5emxTfD z<_{FgIf}z3c0d4#tD#w9mk5BOP9zjaEKzEgPdNzdq+Fv8RiifJ6`& zvx`(knW5m^Q7YzIDsK%yoEEKP*to+aayaWS%U7eh^5KPKEi0l+qpb>Sj3-;5;D+Kv zHlYL-i|VI}v!0##+8Tmz3N3|4)Zp-ePN_qE;D;FvD1ULzXKSxNHqSj&!)yt!U%(h8{>l>X*3G z4Q~FW@*G8)!++>u?i3VOvVR^=a}as+}U{ny5{`LCt;Y zkO{jf(STt?eR~A|C|L*A`=Jo@0c(8qWjZ!ts%wf4*qe=-BnD9I5Y1D}^z#BBF%pE) zl>}R84GSTDkh!q8L5V|p^W~sxAbO7}5@Gd2@dack6VEW$o1FSADwp;WBA#Fqs{UVX zGZnHihI?Q>wI2@j+hNz8O|0QYC41S$o%0jx; z@W29W8|&NuB)_Qaq9M|4Cg#m1olT!j+qyepp4OlgNrC8VrMEU={pUVObBMHjgc1wK zsq{7j52I5RW`nJ7;`ubl1cmNWI+;L9FSj+VU+T^N)LJM6Wp)lVs1y}8XHa_g~ z&Nvc@>7Bm1^WT@q#QUH2gpsl8jp!=!4$+J{6e2PuRC{AZAFtJoti}vQQz9%93)Jv@ zyFFLtJ?~V7jRsa)!wh|m--{awAi{odkjHLIAH4c(g@i>XrbqcZ2>P$-ncZB%-wva( zD?5>%sFYVXnp|OD@5wc&2RgL@X^*t^l|mto*0ZWOJ8mRKs-j|<=sELnkVIrOmN-@@ zLrD-VE0y(+ioeT_yL5E1rnaO3PxCqFpB1&`%C2%X+L$T~1m&1 + * This class manages the dragon's variant system, its data synchronization, and integrates with the GeckoLib + * animation system. + *

          + * + *

          + * Key Methods: + *

            + *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
          • + *
          • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
          • + *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • + *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • + *
          + *

          + * + * @author MeAlam + * @since 1.0.0 + */ +public class DragonEntity extends TamableAnimal implements IVariantEntity, GeoEntity { + /** + * The name of the entity. + * + * @since 1.0.0 + */ + protected final String entityName = "dragon"; + + /** + * Constructs a new {@link DragonEntity} instance with the specified entity type and level. + * + * @param pEntityType {@link EntityType} - The type of the entity. + * @param pLevel {@link Level} - The level in which the entity is created. + * @author MeAlam + * @since 1.0.0 + */ + public DragonEntity(EntityType pEntityType, Level pLevel) { + super(pEntityType, pLevel); + } + + public void setVariantName(String pVariantName) { + ((IVariantAccessor) this).setEntityVariantName(pVariantName); + } + + public String getVariantName() { + return ((IVariantAccessor) this).getEntityVariantName(); + } + + /** + * Finalizes the spawning of the dragon entity. + *

          + * This method sets up the variant for the entity and connects parameters if needed. + *

          + * + * @param pLevel {@link ServerLevelAccessor} - The level in which the entity is spawned. + * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. + * @param pReason {@link MobSpawnType} - The reason for spawning the entity. + * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. + * @return {@link SpawnGroupData} - Updated spawn data. + * @author MeAlam + * @since 1.0.0 + */ + @Override + public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { + if (getVariantName() == null || getVariantName().isEmpty()) { + setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); + ParameterUtils.ParameterBuilder.forVariant(entityName, this.getVariantName()) + .withParameter("customParameter") + .withParameter("int") + .withParameter("bool") + .withParameter("array") + .connect(); + } + BaseLogger.log(BaseLogLevel.SUCCESS, "Dragon Spawned with Variant: " + getVariantName(), true); + return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); + } + + + /** + * All Code below this Fragment is not Library Related!!! + */ + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public static AttributeSupplier.Builder createAttributes() { + return Mob.createMobAttributes() + .add(Attributes.MOVEMENT_SPEED, 0.3) + .add(Attributes.MAX_HEALTH, 10) + .add(Attributes.ARMOR, 0) + .add(Attributes.ATTACK_DAMAGE, 3) + .add(Attributes.FOLLOW_RANGE, 16) + .add(Attributes.FLYING_SPEED, 0.3); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return cache; + } + + @Nullable + @Override + public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { + return null; + } + + @Override + public boolean isFood(@NotNull ItemStack pItemStack) { + return false; + } +} diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java new file mode 100644 index 00000000..58da8fbc --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java @@ -0,0 +1,30 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.dragon; + +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; +import software.bluelib.BlueLibConstants; +import software.bluelib.utils.logging.BaseLogger; + +public class DragonModel extends GeoModel { + + + // Get the Model Location + @Override + public ResourceLocation getModelResource(DragonEntity pObject) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/dragon.geo.json"); + } + + // Get the Texture Location + @Override + public ResourceLocation getTextureResource(DragonEntity pObject) { + return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); + } + + // Get the Animation Location + @Override + public ResourceLocation getAnimationResource(DragonEntity pAnimatable) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/dragon.animation.json"); + } +} diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java new file mode 100644 index 00000000..c770ac48 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java @@ -0,0 +1,14 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.dragon; + +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class DragonRender extends GeoEntityRenderer { + + // Render the entity + public DragonRender(EntityRendererProvider.Context pRenderManager) { + super(pRenderManager, new DragonModel()); + } +} diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java new file mode 100644 index 00000000..8c3d1fa7 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -0,0 +1,142 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.rex; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.*; +import net.minecraft.world.entity.ai.attributes.AttributeSupplier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; +import software.bluelib.interfaces.variant.IVariantAccessor; +import software.bluelib.interfaces.variant.IVariantEntity; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; +import software.bluelib.utils.variant.ParameterUtils; + +/** + * A {@code RexEntity} class representing a Rex entity in the game, which extends {@link TamableAnimal} + * and implements {@link IVariantEntity} and {@link GeoEntity}. + *

          + * This class manages the Rex's variant system, its data synchronization, and integrates with the GeckoLib + * animation system. + *

          + * + *

          + * Key Methods: + *

            + *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
          • + *
          • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
          • + *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • + *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • + *
          • {@link #setVariantName(String)} - Sets the variant name of the Rex.
          • + *
          • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
          • + *
          + *

          + * + * @author MeAlam + * @since 1.0.0 + */ +public class RexEntity extends TamableAnimal implements IVariantEntity, GeoEntity { + /** + * The name of the entity. + * + * @since 1.0.0 + */ + protected final String entityName = "rex"; + + /** + * Constructs a new {@link RexEntity} instance with the specified entity type and level. + * + * @param pEntityType {@link EntityType} - The type of the entity. + * @param pLevel {@link Level} - The level in which the entity is created. + * @author MeAlam + * @since 1.0.0 + */ + public RexEntity(EntityType pEntityType, Level pLevel) { + super(pEntityType, pLevel); + } + + public void setVariantName(String pVariantName) { + ((IVariantAccessor) this).setEntityVariantName(pVariantName); + } + + public String getVariantName() { + return ((IVariantAccessor) this).getEntityVariantName(); + } + + /** + * Finalizes the spawning of the Rex entity. + *

          + * This method sets up the variant for the entity and connects parameters if needed. + *

          + * + * @param pLevel {@link ServerLevelAccessor} - The level in which the entity is spawned. + * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. + * @param pReason {@link MobSpawnType} - The reason for spawning the entity. + * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. + * @return {@link SpawnGroupData} - Updated spawn data. + * @author MeAlam + * @since 1.0.0 + */ + @Override + public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { + if (getVariantName() == null || getVariantName().isEmpty()) { + this.setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); + ParameterUtils.ParameterBuilder.forVariant(entityName, this.getVariantName()) + .withParameter("customParameter") + .withParameter("int") + .withParameter("bool") + .withParameter("array") + .connect(); + } + BaseLogger.log(BaseLogLevel.SUCCESS, "Dragon Spawned with Variant: " + getVariantName(), true); + return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); + } + + /** + * All Code below this Fragment is not Library Related!!! + */ + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public static AttributeSupplier.Builder createAttributes() { + return Mob.createMobAttributes() + .add(Attributes.MOVEMENT_SPEED, 0.3) + .add(Attributes.MAX_HEALTH, 10) + .add(Attributes.ARMOR, 0) + .add(Attributes.ATTACK_DAMAGE, 3) + .add(Attributes.FOLLOW_RANGE, 16) + .add(Attributes.FLYING_SPEED, 0.3); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return cache; + } + + @Nullable + @Override + public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { + return null; + } + + @Override + public boolean isFood(@NotNull ItemStack pItemStack) { + return false; + } +} diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java new file mode 100644 index 00000000..4323f872 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java @@ -0,0 +1,29 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.rex; + +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; +import software.bluelib.BlueLibConstants; + +public class RexModel extends GeoModel { + + + // Get the Model Locations + @Override + public ResourceLocation getModelResource(RexEntity pObject) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/rex.geo.json"); + } + + // Get the Texture Location + @Override + public ResourceLocation getTextureResource(RexEntity pObject) { + return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); + } + + // Get the Animation Location + @Override + public ResourceLocation getAnimationResource(RexEntity pAnimatable) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/rex.animation.json"); + } +} diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java new file mode 100644 index 00000000..776c5920 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java @@ -0,0 +1,14 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.rex; + +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class RexRender extends GeoEntityRenderer { + + // Render the entity + public RexRender(EntityRendererProvider.Context pRenderManager) { + super(pRenderManager, new RexModel()); + } +} diff --git a/NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java b/NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java new file mode 100644 index 00000000..7e6f8cca --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java @@ -0,0 +1,32 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.event; + +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.client.event.EntityRenderersEvent; +import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent; +import software.bluelib.example.entity.dragon.DragonEntity; +import software.bluelib.example.entity.dragon.DragonRender; +import software.bluelib.example.entity.rex.RexEntity; +import software.bluelib.example.entity.rex.RexRender; +import software.bluelib.example.init.ModEntities; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; + +public class ClientEvents { + @SubscribeEvent + public static void registerRenderers(final EntityRenderersEvent.RegisterRenderers pEvent) { + // Register the renderer for all the Entities + pEvent.registerEntityRenderer(ModEntities.DRAGON.get(), DragonRender::new); + pEvent.registerEntityRenderer(ModEntities.REX.get(), RexRender::new); + BaseLogger.log(BaseLogLevel.INFO, "Registered Renderers for Entities", true); + } + + // Register the Attributes + @SubscribeEvent + public static void registerAttributes(EntityAttributeCreationEvent pEvent) { + pEvent.put(ModEntities.DRAGON.get(), DragonEntity.createAttributes().build()); + pEvent.put(ModEntities.REX.get(), RexEntity.createAttributes().build()); + BaseLogger.log(BaseLogLevel.INFO, "Registered Attributes for Entities", true); + } +} diff --git a/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java b/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java new file mode 100644 index 00000000..a8d19c93 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java @@ -0,0 +1,128 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.event; + +import net.minecraft.server.MinecraftServer; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.AddReloadListenerEvent; +import net.neoforged.neoforge.event.server.ServerStartingEvent; +import software.bluelib.BlueLibConstants; +import software.bluelib.event.ReloadEventHandler; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * A {@code ReloadHandler} class that handles server start and reload events related to entity variants. + *

          + * This class extends {@link ReloadEventHandler} and implements event handling for server starting and reloading, + * ensuring that entity variant data is properly loaded and refreshed. + *

          + * + *

          + * Key Methods: + *

            + *
          • {@link #onServerStart(ServerStartingEvent)} - Handles server starting events to initialize entity variants.
          • + *
          • {@link #onReload(AddReloadListenerEvent)} - Handles reload events to refresh entity variants.
          • + *
          • {@link #LoadEntityVariants(MinecraftServer)} - Loads entity variants from JSON files into the server.
          • + *
          + *

          + * + * @author MeAlam + * @since 1.0.0 + */ +@EventBusSubscriber +public class ReloadHandler extends ReloadEventHandler { + + /** + * The {@link MinecraftServer} instance for the server handling the events. + *

          + * This is initialized when the server starts and used to load entity variants. + *

          + * + * @since 1.0.0 + */ + private static MinecraftServer server; + + /** + * Handles the server starting event to initialize the {@link MinecraftServer} instance + * and load entity variants. + * + * @param pEvent {@link ServerStartingEvent} - The event triggered when the server starts. + * @author MeAlam + * @since 1.0.0 + */ + @SubscribeEvent + public static void onServerStart(ServerStartingEvent pEvent) { + server = pEvent.getServer(); + ReloadHandler.LoadEntityVariants(server); + BaseLogger.log(BaseLogLevel.INFO, "Entity variants loaded.", true); + } + + /** + * Handles the reload event by scheduling a task to reload entity variants. + *

          + * This method schedules the {@code LoadEntityVariants} method to run after a short delay. + *

          + * + * @param pEvent {@link AddReloadListenerEvent} - The event triggered when a reload occurs. + * @author MeAlam + * @since 1.0.0 + */ + @SubscribeEvent + public static void onReload(AddReloadListenerEvent pEvent) { + if (server != null) { + BlueLibConstants.SCHEDULER.schedule(() -> { + server.execute(() -> { + ReloadHandler.LoadEntityVariants(server); + BaseLogger.log(BaseLogLevel.INFO, "Entity variants reloaded.", true); + }); + }, 1, TimeUnit.SECONDS); + } + } + + /** + * The base path for entity variant JSON files. + *

          + * This path is used to locate the files that contain variant data for entities. + *

          + * + * @since 1.0.0 + */ + private static final String basePath = "variant/entity/"; + + /** + * A {@link List} of entity names for which variants will be loaded. + *

          + * This list defines which entities will have their variants loaded from JSON files. + *

          + * + * @since 1.0.0 + */ + private static final List entityNames = Arrays.asList("dragon", "rex"); + + /** + * Loads entity variants from JSON files into the {@link MinecraftServer}. + *

          + * This method iterates through the list of entity names, constructs file paths, and registers + * entity variants using the {@link ReloadEventHandler}. + *

          + * + * @param pServer {@link MinecraftServer} - The server on which the entity variants will be loaded. + * @author MeAlam + * @since 1.0.0 + */ + public static void LoadEntityVariants(MinecraftServer pServer) { + for (String entityName : entityNames) { + String folderPath = basePath + entityName; + ReloadEventHandler.registerEntityVariants(folderPath, pServer, BlueLibConstants.MOD_ID, entityName); + BaseLogger.log(BaseLogLevel.INFO, "Entity variants loaded for " + entityName + ".", true); + } + } +} diff --git a/NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java b/NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java new file mode 100644 index 00000000..cd90fea8 --- /dev/null +++ b/NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java @@ -0,0 +1,40 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.init; + +import net.minecraft.core.registries.Registries; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobCategory; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; +import software.bluelib.BlueLibConstants; +import software.bluelib.example.entity.dragon.DragonEntity; +import software.bluelib.example.entity.rex.RexEntity; + +public class ModEntities { + public static final DeferredRegister> REGISTRY = DeferredRegister.create(Registries.ENTITY_TYPE, BlueLibConstants.MOD_ID); + + // List of Entities + public static final DeferredHolder, EntityType> DRAGON = register( + "example_one", + EntityType.Builder.of(DragonEntity::new, MobCategory.AMBIENT) + .setShouldReceiveVelocityUpdates(true) + .setTrackingRange(64) + .setUpdateInterval(3) + .fireImmune() + .sized(0.6f, 1.8f)); + + public static final DeferredHolder, EntityType> REX = register( + "example_two", + EntityType.Builder.of(RexEntity::new, MobCategory.AMBIENT) + .setShouldReceiveVelocityUpdates(true) + .setTrackingRange(64) + .setUpdateInterval(3) + .fireImmune() + .sized(0.6f, 1.8f)); + + private static DeferredHolder, EntityType> register(String pRegistryName, EntityType.Builder pEntityTypeBuilder) { + return REGISTRY.register(pRegistryName, () -> pEntityTypeBuilder.build(pRegistryName)); + } +} diff --git a/NeoForge/src/main/resources/assets/bluelib/animations/dragon.animation.json b/NeoForge/src/main/resources/assets/bluelib/animations/dragon.animation.json new file mode 100644 index 00000000..0b02f765 --- /dev/null +++ b/NeoForge/src/main/resources/assets/bluelib/animations/dragon.animation.json @@ -0,0 +1,63 @@ +{ + "format_version": "1.8.0", + "animations": { + "test": { + "loop": true, + "bones": { + "Body": { + "rotation": { + "vector": [-20.44582, 11.73507, -4.3361], + "easing": "linear" + }, + "position": { + "vector": [0, -1, 0], + "easing": "linear" + } + }, + "leftleg": { + "rotation": { + "vector": [0, 22.5, 0], + "easing": "linear" + } + }, + "rightleg": { + "rotation": { + "vector": [0, -22.5, 0], + "easing": "linear" + } + }, + "rightwing1": { + "rotation": { + "vector": [0, 0, -20], + "easing": "linear" + } + }, + "leftwing": { + "rotation": { + "vector": [0, 0, -10], + "easing": "linear" + } + }, + "leftwing1": { + "rotation": { + "vector": [0, 0, 30], + "easing": "linear" + } + }, + "neck": { + "rotation": { + "vector": [-40, 0, 0], + "easing": "linear" + } + }, + "Head": { + "rotation": { + "vector": [72.5, 0, 0], + "easing": "linear" + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/NeoForge/src/main/resources/assets/bluelib/animations/rex.animation.json b/NeoForge/src/main/resources/assets/bluelib/animations/rex.animation.json new file mode 100644 index 00000000..5d8891b4 --- /dev/null +++ b/NeoForge/src/main/resources/assets/bluelib/animations/rex.animation.json @@ -0,0 +1,51 @@ +{ + "format_version": "1.8.0", + "animations": { + "animation2": { + "loop": true, + "bones": { + "body": { + "rotation": { + "vector": [0, -15, 0] + } + }, + "tail2": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail3": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail4": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail5": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail6": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "neck": { + "rotation": { + "vector": [0, -2.5, 0] + } + }, + "head": { + "rotation": { + "vector": [0, -20, 0] + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/NeoForge/src/main/resources/assets/bluelib/geo/dragon.geo.json b/NeoForge/src/main/resources/assets/bluelib/geo/dragon.geo.json new file mode 100644 index 00000000..8f038886 --- /dev/null +++ b/NeoForge/src/main/resources/assets/bluelib/geo/dragon.geo.json @@ -0,0 +1,93 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 64, + "texture_height": 64, + "visible_bounds_width": 4, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [0, 0.75, 0] + }, + "bones": [ + { + "name": "Body", + "pivot": [-0.16667, 5, -1], + "cubes": [ + {"origin": [-2, 4, 1], "size": [4, 2, 4], "uv": [17, 10]}, + {"origin": [-3, 4, -4], "size": [6, 2, 5], "uv": [0, 14]} + ] + }, + { + "name": "leftleg", + "parent": "Body", + "pivot": [1.5, 5, 5], + "cubes": [ + {"origin": [1.5, 3, 4.5], "size": [0, 4, 3], "pivot": [1.5, 5, 6], "rotation": [90, 0, 90], "uv": [0, 0]} + ] + }, + { + "name": "rightleg", + "parent": "Body", + "pivot": [-1.5, 5, 5], + "cubes": [ + {"origin": [-1.5, 3, 4.5], "size": [0, 4, 3], "pivot": [-1.5, 5, 6], "rotation": [90, 0, -90], "uv": [0, 0], "mirror": true} + ] + }, + { + "name": "rightwing", + "parent": "Body", + "pivot": [-2.5, 5, -3.5], + "cubes": [ + {"origin": [-10, 5, -5], "size": [7, 0, 7], "uv": [-7, 28], "mirror": true} + ] + }, + { + "name": "rightwing1", + "parent": "rightwing", + "pivot": [-9.5, 5, -1.5], + "cubes": [ + {"origin": [-17, 5, -5], "size": [7, 0, 7], "uv": [43, 0], "mirror": true} + ] + }, + { + "name": "leftwing", + "parent": "Body", + "pivot": [2.5, 5, -3.5], + "cubes": [ + {"origin": [3, 5, -5], "size": [7, 0, 7], "uv": [-7, 28]} + ] + }, + { + "name": "leftwing1", + "parent": "leftwing", + "pivot": [9.5, 5, -1.5], + "cubes": [ + {"origin": [10, 5, -5], "size": [7, 0, 7], "uv": [43, 0]} + ] + }, + { + "name": "neck", + "parent": "Body", + "pivot": [0, 5, -4], + "cubes": [ + {"origin": [-1, 4, -8], "size": [2, 2, 4], "uv": [10, 21]} + ] + }, + { + "name": "Head", + "parent": "neck", + "pivot": [0, 4.8, -7.5], + "cubes": [ + {"origin": [-1.5, 4, -12], "size": [3, 3, 4], "uv": [18, 17]}, + {"origin": [0, 6, -15], "size": [0, 3, 7], "uv": [0, 14]}, + {"origin": [-1, 4, -16], "size": [2, 2, 4], "uv": [21, 0]}, + {"origin": [-1, 3, -16], "size": [2, 1, 1], "uv": [29, 0]}, + {"origin": [0, 7, -8], "size": [0, 1, 3], "uv": [0, 23]} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/NeoForge/src/main/resources/assets/bluelib/geo/rex.geo.json b/NeoForge/src/main/resources/assets/bluelib/geo/rex.geo.json new file mode 100644 index 00000000..3d18bac7 --- /dev/null +++ b/NeoForge/src/main/resources/assets/bluelib/geo/rex.geo.json @@ -0,0 +1,390 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 512, + "texture_height": 512, + "visible_bounds_width": 29, + "visible_bounds_height": 7.5, + "visible_bounds_offset": [0, 3.25, 0] + }, + "bones": [ + { + "name": "Tyrannosaurus", + "pivot": [0, 0, 0] + }, + { + "name": "body", + "parent": "Tyrannosaurus", + "pivot": [0, 72, 0], + "cubes": [ + {"origin": [-19, 47, -8], "size": [38, 45, 34], "uv": [124, 51]}, + {"origin": [-15.475, 51.23327, -14.01496], "size": [31, 45, 35], "pivot": [0.025, 74.40827, 4.38504], "rotation": [-12.75, 0, 0], "uv": [130, 50]}, + {"origin": [-16, 40, -22.525], "size": [32, 16, 40], "inflate": -0.05, "pivot": [0, 72, 0.275], "rotation": [17.5, 0, 0], "uv": [0, 160]}, + {"origin": [-16, 54, -54], "size": [32, 37, 46], "uv": [1, 1]}, + {"origin": [-16, 71.46448, -54.53145], "size": [32, 30, 48], "inflate": -0.25, "pivot": [0, 89.46448, 3.46855], "rotation": [8.75, 0, 0], "uv": [-1, -1]}, + {"origin": [-16, 28.37894, -42.36923], "size": [32, 21, 49], "inflate": -0.025, "pivot": [0, 73.37894, 12.63077], "rotation": [-24, 0, 0], "uv": [0, 85]} + ] + }, + { + "name": "arm2", + "parent": "body", + "pivot": [13.56731, 58.46159, -45.9607], + "rotation": [29.07337, 19.05681, -20.20848], + "cubes": [ + {"origin": [12.56731, 47.46159, -47.9607], "size": [3, 11, 5], "uv": [111, 0]} + ] + }, + { + "name": "bone2", + "parent": "arm2", + "pivot": [15.06274, 49.29312, -45.32771], + "rotation": [-27.154, -2.96386, 4.54476], + "cubes": [ + {"origin": [13.13695, 39.306, -44.80271], "size": [2, 6, 2], "inflate": -0.075, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [0, 0]}, + {"origin": [14.86195, 37.306, -44.75271], "size": [0, 3, 2], "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [36, 26]}, + {"origin": [12.13695, 44.306, -47.52771], "size": [3, 5, 5], "inflate": -0.125, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [165, 257]} + ] + }, + { + "name": "bone3", + "parent": "bone2", + "pivot": [13.25685, 45.11756, -46.37771], + "rotation": [-14.50257, -2.95519, -2.10666], + "cubes": [ + {"origin": [13.13695, 41.306, -47.37771], "size": [2, 4, 2], "inflate": -0.075, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [0, 28]}, + {"origin": [14.86195, 39.306, -47.37771], "size": [0, 3, 2], "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [36, 29]} + ] + }, + { + "name": "arm3", + "parent": "body", + "pivot": [-13.56731, 58.46159, -45.9607], + "rotation": [29.07337, -19.05681, 20.20848], + "cubes": [ + {"origin": [-15.56731, 47.46159, -47.9607], "size": [3, 11, 5], "uv": [111, 0], "mirror": true} + ] + }, + { + "name": "bone4", + "parent": "arm3", + "pivot": [-15.06274, 49.29312, -45.32771], + "rotation": [-27.154, 2.96386, -4.54476], + "cubes": [ + {"origin": [-15.13695, 39.306, -44.80271], "size": [2, 6, 2], "inflate": -0.075, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [0, 0], "mirror": true}, + {"origin": [-14.86195, 37.306, -44.75271], "size": [0, 3, 2], "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [36, 26], "mirror": true}, + {"origin": [-15.13695, 44.306, -47.52771], "size": [3, 5, 5], "inflate": -0.125, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [165, 257], "mirror": true} + ] + }, + { + "name": "bone5", + "parent": "bone4", + "pivot": [-13.25685, 45.11756, -46.37771], + "rotation": [-14.50257, 2.95519, 2.10666], + "cubes": [ + {"origin": [-15.13695, 41.306, -47.37771], "size": [2, 4, 2], "inflate": -0.075, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [0, 28], "mirror": true}, + {"origin": [-14.86195, 39.306, -47.37771], "size": [0, 3, 2], "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [36, 29], "mirror": true} + ] + }, + { + "name": "tail1", + "parent": "body", + "pivot": [0, 82.97049, 21.3522], + "cubes": [ + {"origin": [-15, 55.74549, 21.0272], "size": [30, 30, 39], "uv": [123, 128]}, + {"origin": [-15, 71.63781, 17.37365], "size": [30, 28, 35], "inflate": -0.2, "pivot": [0, 60.21281, -16.55135], "rotation": [-10.75, 0, 0], "uv": [127, 132]}, + {"origin": [-15, 39.02049, 26.7772], "size": [30, 13, 37], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [16, 0, 0], "uv": [159, 1]} + ] + }, + { + "name": "tail2", + "parent": "tail1", + "pivot": [0, 82.97049, 56.3522], + "cubes": [ + {"origin": [-10, 62.97049, 56.3522], "size": [20, 21, 38], "uv": [106, 199]}, + {"origin": [-9, 41.02049, 63.3522], "size": [18, 14, 35], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [13, 0, 0], "uv": [173, 3]} + ] + }, + { + "name": "tail3", + "parent": "tail2", + "pivot": [0, 82.97049, 93.3522], + "cubes": [ + {"origin": [-7, 66.97049, 93.3522], "size": [14, 14, 37], "uv": [0, 216]}, + {"origin": [-7, 54.52049, 94.3522], "size": [14, 7, 38], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [5.5, 0, 0], "uv": [174, 0]} + ] + }, + { + "name": "tail4", + "parent": "tail3", + "pivot": [0, 82.97049, 129.3522], + "cubes": [ + {"origin": [-5, 69.97049, 129.3522], "size": [10, 9, 37], "uv": [255, 14]}, + {"origin": [-5, 64.82049, 132.6022], "size": [10, 4, 37], "inflate": -0.025, "pivot": [0, 30.97049, 109.3522], "rotation": [4.75, 0, 0], "uv": [255, 14]} + ] + }, + { + "name": "tail5", + "parent": "tail4", + "pivot": [0, 82.97049, 158.3522], + "cubes": [ + {"origin": [-3, 70.97049, 158.3522], "size": [6, 6, 37], "uv": [149, 257]}, + {"origin": [-3, 69.22961, 165.59014], "size": [6, 3, 30], "inflate": -0.1, "pivot": [0, 70.15461, 147.99014], "rotation": [0.5, 0, 0], "uv": [266, 21]} + ] + }, + { + "name": "tail6", + "parent": "tail5", + "pivot": [0, 82.97049, 182.3522], + "cubes": [ + {"origin": [-2, 71.97049, 182.3522], "size": [4, 4, 37], "uv": [0, 285]}, + {"origin": [-2, 66.99549, 197.7022], "size": [4, 4, 25], "inflate": -0.175, "pivot": [0, 30.97049, 162.3522], "rotation": [4.75, 0, 0], "uv": [12, 297]} + ] + }, + { + "name": "neck", + "parent": "body", + "pivot": [0, 74.22605, -48.50511], + "cubes": [ + {"origin": [-15, 55, -67], "size": [30, 31, 17], "uv": [251, 113]}, + {"origin": [-14.25, 80.39311, -64.98257], "size": [30, 11, 17], "inflate": -1, "pivot": [0.75, 82.39311, -53.98257], "rotation": [24.25, 0, 0], "uv": [251, 113]}, + {"origin": [-10, 66.05, -70.125], "size": [20, 34, 25], "inflate": -0.225, "pivot": [0, 87.575, -69.125], "rotation": [-39.25, 0, 0], "uv": [221, 200]}, + {"origin": [-10, 59.575, -78.125], "size": [20, 13, 25], "inflate": -1.325, "pivot": [0, 87.575, -69.125], "rotation": [-14.25, 0, 0], "uv": [235, 259]}, + {"origin": [-9, 71.2, -85.125], "size": [18, 19, 24], "inflate": -0.325, "pivot": [0, 85.2, -69.125], "rotation": [7.5, 0, 0], "uv": [268, 61]}, + {"origin": [-8, 83.89159, -88.09601], "size": [16, 12, 13], "inflate": -0.275, "pivot": [0, 89.89159, -79.09601], "rotation": [42.5, 0, 0], "uv": [198, 259]}, + {"origin": [-8, 86.39159, -80.39601], "size": [16, 11, 19], "inflate": -0.25, "pivot": [0, 89.89159, -68.09601], "rotation": [2.5, 0, 0], "uv": [111, 0]} + ] + }, + { + "name": "head", + "parent": "neck", + "pivot": [0, 83.05369, -83.57238], + "cubes": [ + {"origin": [-8.725, 71, -101], "size": [17, 19, 19], "uv": [286, 165]}, + {"origin": [-8.775, 84, -101], "size": [17, 2, 7], "inflate": 0.225, "uv": [104, 155]}, + {"origin": [-7, 93.5819, -99.5906], "size": [14, 5, 10], "inflate": -0.05, "pivot": [0, 90.5819, -77.5906], "rotation": [21.5, 0, 0], "uv": [0, 111]}, + {"origin": [-7, 81.46532, -93.49693], "size": [14, 5, 9], "inflate": -0.075, "pivot": [0, 78.46532, -74.49693], "rotation": [-25, 0, 0], "uv": [111, 30]}, + {"origin": [-7, 88.64032, -92.02193], "size": [14, 5, 4], "inflate": -0.125, "uv": [0, 191]}, + {"origin": [9, 86, -102], "size": [4, 3, 13], "inflate": -0.025, "pivot": [7, 80.5, -90.5], "rotation": [0, 0, -17.5], "uv": [149, 277]}, + {"origin": [4.59053, 84.6097, -93.1055], "size": [4, 3, 9], "inflate": -0.05, "pivot": [2.59053, 79.1097, -81.6055], "rotation": [0, -27.5, -17.5], "uv": [255, 23]}, + {"origin": [-8.59053, 84.6097, -93.1055], "size": [4, 3, 9], "inflate": -0.05, "pivot": [-2.59053, 79.1097, -81.6055], "rotation": [0, 27.5, 17.5], "uv": [184, 225]}, + {"origin": [12.62776, 90.52364, -107.52067], "size": [4, 3, 11], "inflate": -0.1, "pivot": [10.62776, 85.02364, -91.02067], "rotation": [27.87149, 36.42355, -5.95346], "uv": [0, 239]}, + {"origin": [-16.62776, 90.52364, -107.52067], "size": [4, 3, 11], "inflate": -0.1, "pivot": [-10.62776, 85.02364, -91.02067], "rotation": [27.87149, -36.42355, 5.95346], "uv": [162, 0]}, + {"origin": [-13, 86, -102], "size": [4, 3, 13], "inflate": -0.025, "pivot": [-7, 80.5, -90.5], "rotation": [0, 0, 17.5], "uv": [109, 216]}, + {"origin": [-7, 78.725, -121], "size": [14, 10, 16], "inflate": -0.05, "pivot": [0, 81.725, -99], "rotation": [27.5, 0, 0], "uv": [300, 243]}, + {"origin": [-7, 78.35, -106], "size": [14, 11, 11], "pivot": [0, 81.35, -99], "rotation": [33.5, 0, 0], "uv": [286, 203]}, + {"origin": [-7, 69.519, -125.21974], "size": [14, 11, 7.85], "inflate": -0.075, "pivot": [0, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [259, 165]}, + {"origin": [-6, 78.519, -128.21974], "size": [11, 0, 7.85], "pivot": [0, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [141, 30]}, + {"origin": [5, 61.519, -128.21974], "size": [0, 17, 6.85], "pivot": [-2, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [234, 45]}, + {"origin": [-5, 61.519, -128.21974], "size": [0, 17, 6.85], "pivot": [2, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [28, 154]}, + {"origin": [-7, 73.394, -115.21974], "size": [14, 10, 6.85], "inflate": -0.1, "pivot": [0, 74.394, -109.21974], "rotation": [110.5, 0, 0], "uv": [65, 237]}, + {"origin": [-7, 84.31148, -108.92962], "size": [14, 4, 6.85], "inflate": -0.15, "pivot": [0, 79.31148, -102.92962], "rotation": [128, 0, 0], "uv": [272, 0]}, + {"origin": [-7, 74.31148, -110.92962], "size": [14, 9, 8.85], "inflate": -0.175, "pivot": [0, 79.31148, -102.92962], "rotation": [88, 0, 0], "uv": [0, 28]}, + {"origin": [-7, 69.019, -122.66974], "size": [14, 10, 7], "inflate": -0.125, "pivot": [0, 72.019, -117.66974], "rotation": [47.5, 0, 0], "uv": [0, 267]} + ] + }, + { + "name": "jaw", + "parent": "head", + "pivot": [0, 73.374, -85.20224], + "cubes": [ + {"origin": [-9.125, 61.47673, -99.81697], "size": [18, 13, 12], "inflate": 0.025, "uv": [184, 200]}, + {"origin": [-9.15, 64.14383, -89.12484], "size": [18, 12, 7], "inflate": 0.075, "pivot": [-3, 73.14383, -68.12484], "rotation": [7.5, 0, 0], "uv": [312, 0]}, + {"origin": [7.8, 70.81044, -97.91351], "size": [1, 6, 9], "uv": [104, 179]}, + {"origin": [7.85, 63.60089, -93.15375], "size": [1, 6, 7], "pivot": [-2.975, 63.60089, -72.15375], "rotation": [-22.5, 0, 0], "uv": [65, 216]}, + {"origin": [-7.125, 72.47673, -98.81697], "size": [14, 14, 16], "inflate": 0.025, "uv": [219, 297]}, + {"origin": [6.375, 68.47673, -105.81697], "size": [0, 18, 14], "uv": [0, 159]}, + {"origin": [-6.625, 68.47673, -105.81697], "size": [0, 18, 14], "uv": [0, 141]}, + {"origin": [7.875, 65.38327, -112.3007], "size": [1, 8, 15], "inflate": -0.05, "pivot": [0, 73.88327, -104.8007], "rotation": [27.5, 0, 0], "uv": [255, 0]}, + {"origin": [-9.125, 65.38327, -112.3007], "size": [1, 8, 15], "inflate": -0.05, "pivot": [0, 73.88327, -104.8007], "rotation": [27.5, 0, 0], "uv": [0, 216]}, + {"origin": [-9.05, 70.81044, -97.91351], "size": [1, 6, 9], "uv": [104, 164]}, + {"origin": [-9.1, 63.60089, -93.15375], "size": [1, 6, 7], "pivot": [2.975, 63.60089, -72.15375], "rotation": [-22.5, 0, 0], "uv": [17, 216]}, + {"origin": [-9.125, 64.31864, -111.04094], "size": [18, 8, 15], "inflate": -0.025, "pivot": [0, 70.56864, -103.54094], "rotation": [17.5, 0, 0], "uv": [149, 300]}, + {"origin": [-6.125, 66.9078, -126.60427], "size": [12, 5, 15], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [126, 257]}, + {"origin": [-6.125, 71.5078, -125.60427], "size": [12, 5, 0], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [62, 155]}, + {"origin": [5.725, 71.5078, -125.60427], "size": [0, 5, 17], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [28, 138]}, + {"origin": [-5.975, 71.5078, -125.60427], "size": [0, 5, 17], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [0, 109]}, + {"origin": [-6.125, 60.70962, -124.43479], "size": [12, 5, 15], "inflate": -0.05, "pivot": [0, 63.78462, -115.43479], "rotation": [-3.5, 0, 0], "uv": [234, 61]}, + {"origin": [-7.125, 61.71743, -111.29498], "size": [14, 5, 16], "inflate": -0.025, "pivot": [0, 66.69243, -101.79498], "rotation": [9.25, 0, 0], "uv": [65, 216]} + ] + }, + { + "name": "leg_left", + "parent": "Tyrannosaurus", + "pivot": [20.42923, 70.7324, 8.85434], + "rotation": [-15.09173, -1.85092, -0.08398], + "cubes": [ + {"origin": [12.54366, 41.02086, -4.25109], "size": [12.875, 42.825, 23.725], "uv": [79, 257]} + ] + }, + { + "name": "leg_left2", + "parent": "leg_left", + "pivot": [21.99279, 43.52539, 1.69711], + "cubes": [ + {"origin": [12.844, 24.19389, 3.09297], "size": [12.4, 20.375, 15.95], "pivot": [21.944, 35.38139, 0.96797], "rotation": [34, 0, 0], "uv": [279, 297]} + ] + }, + { + "name": "leg_left3", + "parent": "leg_left2", + "pivot": [19.76532, 33.92692, 13.90262], + "rotation": [55, 0, 0], + "cubes": [ + {"origin": [14.22989, 14.97535, 9.92239], "size": [10, 19, 9], "inflate": -0.1, "uv": [0, 0]} + ] + }, + { + "name": "leg_left4", + "parent": "leg_left3", + "pivot": [19.76532, 14.92692, 13.90262], + "rotation": [-60, 0, 0], + "cubes": [ + {"origin": [14.22989, 2.41759, 7.14887], "size": [10, 17, 9], "inflate": 0.375, "uv": [0, 85]} + ] + }, + { + "name": "Claw5", + "parent": "leg_left4", + "pivot": [18.03922, 11.69239, 7.72125], + "rotation": [3.25353, -39.92899, -4.10228], + "cubes": [ + {"origin": [19.68942, 7.60244, 18.32118], "size": [2, 5, 6], "inflate": -0.2, "pivot": [20.68942, 10.90244, 16.32118], "rotation": [4, 5, 0], "uv": [19, 239]}, + {"origin": [15.96316, 8.07744, 15.28926], "size": [2, 3, 4], "inflate": 0.5, "pivot": [20.4918, 5.40696, 3.40745], "rotation": [2.31336, 4.43385, 27.58957], "uv": [29, 0]} + ] + }, + { + "name": "leg_left5", + "parent": "leg_left4", + "pivot": [19.76532, 2.72669, 9.58045], + "rotation": [32.5, 0, 0], + "cubes": [ + {"origin": [14.22989, -4.78265, 7.2517], "size": [10, 8, 8], "inflate": 0.35, "uv": [42, 267]} + ] + }, + { + "name": "Claw3", + "parent": "leg_left5", + "pivot": [14.03922, -1.93376, 9.83799], + "rotation": [-11.28559, 36.03256, -29.0792], + "cubes": [ + {"origin": [15.68942, -5.02371, -6.76194], "size": [2, 4, 9], "inflate": -0.2, "pivot": [16.68942, -2.72371, 1.23806], "rotation": [-4, -5, 0], "uv": [78, 267]}, + {"origin": [11.96316, -5.54871, -1.73002], "size": [2, 3, 12], "inflate": 0.5, "pivot": [16.4918, -8.21919, 14.15179], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [45, 298]}, + {"origin": [13.86316, -1.04871, -0.45502], "size": [2, 3, 12], "inflate": 0.4, "pivot": [18.3918, -3.71919, 15.42679], "rotation": [14.70847, -5.40113, 27.33492], "uv": [263, 297]} + ] + }, + { + "name": "Claw2", + "parent": "leg_left5", + "pivot": [18.00128, -1.52657, 8.77203], + "rotation": [6.46283, 10.46681, -26.49382], + "cubes": [ + {"origin": [19.65148, -4.61652, -7.8279], "size": [2, 4, 9], "inflate": -0.2, "pivot": [20.65148, -2.31652, 0.1721], "rotation": [-8.25367, -3.37646, 28.00254], "uv": [259, 183]}, + {"origin": [15.92522, -5.14152, -2.79598], "size": [2, 3, 12], "inflate": 0.5, "pivot": [20.45386, -7.812, 13.08583], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [0, 284]}, + {"origin": [17.82522, -0.64152, -1.52098], "size": [2, 3, 12], "inflate": 0.4, "pivot": [22.35386, -3.312, 14.36083], "rotation": [14.70847, -5.40113, 27.33492], "uv": [45, 283]} + ] + }, + { + "name": "Claw4", + "parent": "leg_left5", + "pivot": [25.00339, -1.78444, 9.60342], + "rotation": [-6.62428, -31.83686, 25.40349], + "cubes": [ + {"origin": [21.35319, -4.87439, -6.99651], "size": [2, 4, 9], "inflate": -0.2, "pivot": [22.35319, -2.57439, 1.00349], "rotation": [-4, 5, 0], "uv": [172, 21]}, + {"origin": [25.07945, -5.39939, -1.96459], "size": [2, 3, 12], "inflate": 0.5, "pivot": [22.55081, -8.06987, 13.91722], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [222, 145]}, + {"origin": [23.17945, -0.89939, -0.68959], "size": [2, 3, 12], "inflate": 0.4, "pivot": [20.65081, -3.56987, 15.19222], "rotation": [14.70847, 5.40113, -27.33492], "uv": [222, 130]} + ] + }, + { + "name": "leg_right", + "parent": "Tyrannosaurus", + "pivot": [-20.42923, 70.7324, 8.85434], + "rotation": [-15.09173, 1.85092, 0.08398], + "cubes": [ + {"origin": [-25.41866, 41.02086, -4.25109], "size": [12.875, 42.825, 23.725], "uv": [79, 257], "mirror": true} + ] + }, + { + "name": "leg_right2", + "parent": "leg_right", + "pivot": [-21.99279, 43.52539, 1.69711], + "cubes": [ + {"origin": [-25.244, 24.19389, 3.09297], "size": [12.4, 20.375, 15.95], "pivot": [-21.944, 35.38139, 0.96797], "rotation": [34, 0, 0], "uv": [279, 297], "mirror": true} + ] + }, + { + "name": "leg_right3", + "parent": "leg_right2", + "pivot": [-19.76532, 33.92692, 13.90262], + "rotation": [55, 0, 0], + "cubes": [ + {"origin": [-24.22989, 14.97535, 9.92239], "size": [10, 19, 9], "inflate": -0.1, "uv": [0, 0], "mirror": true} + ] + }, + { + "name": "leg_right4", + "parent": "leg_right3", + "pivot": [-19.76532, 14.92692, 13.90262], + "rotation": [-60, 0, 0], + "cubes": [ + {"origin": [-24.22989, 2.41759, 7.14887], "size": [10, 17, 9], "inflate": 0.375, "uv": [0, 85], "mirror": true} + ] + }, + { + "name": "Claw6", + "parent": "leg_right4", + "pivot": [-18.03922, 11.69239, 7.72125], + "rotation": [3.25353, 39.92899, 4.10228], + "cubes": [ + {"origin": [-21.68942, 7.60244, 18.32118], "size": [2, 5, 6], "inflate": -0.2, "pivot": [-20.68942, 10.90244, 16.32118], "rotation": [4, -5, 0], "uv": [19, 239], "mirror": true}, + {"origin": [-17.96316, 8.07744, 15.28926], "size": [2, 3, 4], "inflate": 0.5, "pivot": [-20.4918, 5.40696, 3.40745], "rotation": [2.31336, -4.43385, -27.58957], "uv": [29, 0], "mirror": true} + ] + }, + { + "name": "leg_right5", + "parent": "leg_right4", + "pivot": [-19.76532, 2.72669, 9.58045], + "rotation": [32.5, 0, 0], + "cubes": [ + {"origin": [-24.22989, -4.78265, 7.2517], "size": [10, 8, 8], "inflate": 0.35, "uv": [42, 267], "mirror": true} + ] + }, + { + "name": "Claw7", + "parent": "leg_right5", + "pivot": [-14.03922, -1.93376, 9.83799], + "rotation": [-11.28559, -36.03256, 29.0792], + "cubes": [ + {"origin": [-17.68942, -5.02371, -6.76194], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-16.68942, -2.72371, 1.23806], "rotation": [-4, 5, 0], "uv": [78, 267], "mirror": true}, + {"origin": [-13.96316, -5.54871, -1.73002], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-16.4918, -8.21919, 14.15179], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [45, 298], "mirror": true}, + {"origin": [-15.86316, -1.04871, -0.45502], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-18.3918, -3.71919, 15.42679], "rotation": [14.70847, 5.40113, -27.33492], "uv": [263, 297], "mirror": true} + ] + }, + { + "name": "Claw8", + "parent": "leg_right5", + "pivot": [-18.00128, -1.52657, 8.77203], + "rotation": [6.46283, -10.46681, 26.49382], + "cubes": [ + {"origin": [-21.65148, -4.61652, -7.8279], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-20.65148, -2.31652, 0.1721], "rotation": [-8.25367, 3.37646, -28.00254], "uv": [259, 183], "mirror": true}, + {"origin": [-17.92522, -5.14152, -2.79598], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-20.45386, -7.812, 13.08583], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [0, 284], "mirror": true}, + {"origin": [-19.82522, -0.64152, -1.52098], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-22.35386, -3.312, 14.36083], "rotation": [14.70847, 5.40113, -27.33492], "uv": [45, 283], "mirror": true} + ] + }, + { + "name": "Claw9", + "parent": "leg_right5", + "pivot": [-25.00339, -1.78444, 9.60342], + "rotation": [-6.62428, 31.83686, -25.40349], + "cubes": [ + {"origin": [-23.35319, -4.87439, -6.99651], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-22.35319, -2.57439, 1.00349], "rotation": [-4, -5, 0], "uv": [172, 21], "mirror": true}, + {"origin": [-27.07945, -5.39939, -1.96459], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-22.55081, -8.06987, 13.91722], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [222, 145], "mirror": true}, + {"origin": [-25.17945, -0.89939, -0.68959], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-20.65081, -3.56987, 15.19222], "rotation": [14.70847, -5.40113, 27.33492], "uv": [222, 130], "mirror": true} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/NeoForge/src/main/resources/assets/bluelib/lang/en_us.json b/NeoForge/src/main/resources/assets/bluelib/lang/en_us.json new file mode 100644 index 00000000..8371c823 --- /dev/null +++ b/NeoForge/src/main/resources/assets/bluelib/lang/en_us.json @@ -0,0 +1,4 @@ +{ + "entity.bluelib.example_one": "Example", + "entity.bluelib.example_two": "Example" +} \ No newline at end of file diff --git a/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png b/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png new file mode 100644 index 0000000000000000000000000000000000000000..83be2147b8db3aaab415e12dc3b6e9a11a594ea4 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!7Pn|)P)=iz4q{MmaJHmZ`5KTT zT@vIM%(v z(aRpoCoWyiTgojaD&F|F!PdZVM@UbNjptVBj4jLF?f%O$LFQ-3hJ{yuCnpH{RqTF0 zeUaRrN`{moTZcM{69EVLnQmQO%s%OtOoW(UeeqPr*})2&$=17>Km8Ke@%eU3;;UAl z_dE-lA2QvTo9bV8@y{Lo#EEr$XX6_ew|<>1!7nqtJ8%c@3EiH9*VZm)@~qx!CojNR zaWk9uaEODlE8kU9hhhtcCz6N4bsR43<#29rQagW3>HO}AsXY7mmmhHEtgR04`g-ue zwv#SzoSD}|v`Lv6asM;6d&}sM&)V{9@7_H|f67<|ydtWYcW8+%(7BtgsyBPB&W+HL z{c<<=%Uw8|weJPP@nd2)_peY@i7iud+B+%Zp5z_{-H+UVy3Ca989GZ6MLiBbQ|UWb z(Y^fs4MF?eSt1usd41cW*!(Qw)s%f3B9+u@XC5>Aq_Xz;j^mF{Oz1waD#L%1(lgZ; z3|#E;@8(@%^IqToRn(#6{C~ELFSiAJm_Id{T)EuXZp3k!(UWyjbJC~xst$5b_e=bf q?_)BNT$9h7r)_M&3`GSo`xu+NS2^bO6ubn+JAk44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!&W-dj)XETq4p!hyw%*PB>6gHc&$n9=U$y$Y z=ULGFkm<(URR6k*f9~ifPORfQ8{fFN_3La2ewpdrfjf9l==L1Ewstv_XZ2P)c>&If zo7udFLmZS{`L3Ee6k9MnkvtTx<8Wy&hjW9I+WA{b=XXy`<=Mx-{D3oOZFPXx*MkqX zopgEQ%)BO|P0GxO`=7DhTSkX`)|Ov;_wF(JQ^qRb6;Z{!LrZLd&fRoXz1eGZZiJTX zm%F)N?!wuueJ>b}9}~N|e}$?_Y?+eN-boqvB=;!je&qhsWu|1$&{>iw>T&p)O5eGP z?&bGy2-@$?61i~7>)RH^=4TPFrtI4gsia;z^O)Hum9@`z9DjUbLid4H8UCA;o~gcI z;9{45H}4Xg_xk>?q7EhJ|FdO$xh>$s{He+0%H_s(BaX|Ao~)CalRmvyb&z|yU*ey9 qACrmXntbLwZDRvwC@P5A$Jpe($}z8};3Y8L89ZJ6T-G@yGywpxb1(q_ literal 0 HcmV?d00001 diff --git a/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png b/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png new file mode 100644 index 0000000000000000000000000000000000000000..56c9452f64ef0b1e71cecef3b4d07f56ae847633 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!mKPJ^=Hz5!W#wdNPn^2p^s67*vJwUgQb~?#2X}7uGm#gP zQ06^oDwgx$fq}uR<%$^@8TFMVidv2~UU@d+Y|c^~DgvxPb0$Wc7}!LuS~IT`$dN7y z@(X78j}sipEHVW;@~EeaV@SoEw^wiHEjAEfdvHHFiDPf3^4f2I61s;NV<1;Z1`L*Y6Om-ccvH#n)Czom43_rz45ef-N0ICIuk2Y7uw_+Z;f zmp9JLYa-gD%#67I8QZ;ObjW9I`L%cN9-}{HtO8yURm?lI#1`n>O;^>My;kQ&Xvu!L zoBQQ1oXy(zg5mfvv77r>sH()4DLL((lyOgTkAm(;?mt~-O7;w$C5fUQho7nRovY|x ze*cD`{q8K03#YukZBcA~7V&Dzz73H|>a{bEnSD}O`+Udo$0sIqA6S*)ze(wt>I()g zcKLVnF0py9@Bb?5P;&l1TgI2$0zS;2noO=-ZfrN=xXkFuI;lD7(|c71xu^Rj{>k?- onMkh5XU@|$HeiOLf|z}bP2Q^<^Lh$i0^^;*)78&qol`;+0O_S2&j0`b literal 0 HcmV?d00001 diff --git a/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png b/NeoForge/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png new file mode 100644 index 0000000000000000000000000000000000000000..adbd4aba3aedfc3c346c7fcbcd858cbe4dd261e6 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!Zjwt65OA~RHu2!IKd|xH`;UJotCY^rs5}_f`{vw>EiO$N z3LOzw<`r~)`(`)e=Yh7PEk`d-JKbu&a%s|urSjIR6`Z;x41ng`DxW(eV9(;TfP5fF zx+KUinBhN8a3r(H6zIsKo-U3d6?5KRy`8t%K!EMR{p2K$y_w2uzx|D07t}vHbT_ZS zqnACFPh7g3x0G8Pb3e8>o{E6%i-MMq;~$6()ryJQ+f9BFF)YSSz8_8_4VL` zZ6{scI5V$_Xp=HC;{IoB_m!M8-n(`vqUbO^7^(#vH4lVt10_7L@KG*&OB!JNoDQx9mgM^n9zM-Rfhj2rDv)y z7`WKw-_5(k=DoiEtEfZC`TuMgUv3NdFn?+?xpKL&-H78dqbKX6=A=*WRUPD>?w9x{ q-^XMkxh9`EPutjl8Hx&G_AxejuX4=mDR>EtcLq;aKbLh*2~7ZCIW7SJ literal 0 HcmV?d00001 diff --git a/NeoForge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png b/NeoForge/src/main/resources/assets/bluelib/textures/entity/rex/brown.png new file mode 100644 index 0000000000000000000000000000000000000000..f2956d0504901ccd33fb2067b7631ba08471c5ce GIT binary patch literal 3454 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 or57IkfgP>p|9}4H3?K* zd$|Vy0Lxt%z&JT@wO!)n0A&PtxcTWHMQ;CCUK+VbR@PgIE_Q-#4VZ+o>m>4&1Ni!+e7d%l_n? zxZ~ZcB#F9yLg{*Zse~b2F@UYst7MK&{iUQ_aG5EvBgvGNXSSOn&)a!Pwl4YxCIRZr zrAF;ib-vH8++2$fyhbC(n*6E`H_m9e5j)dx#4vTTIM(N7SJ&DT!#AwbRgg-JQwN5Q zx5emxTfD z<_{FgIf}z3c0d4#tD#w9mk5BOP9zjaEKzEgPdNzdq+Fv8RiifJ6`& zvx`(knW5m^Q7YzIDsK%yoEEKP*to+aayaWS%U7eh^5KPKEi0l+qpb>Sj3-;5;D+Kv zHlYL-i|VI}v!0##+8Tmz3N3|4)Zp-ePN_qE;D;FvD1ULzXKSxNHqSj&!)yt!U%(h8{>l>X*3G z4Q~FW@*G8)!++>u?i3VOvVR^=a}as+}U{ny5{`LCt;Y zkO{jf(STt?eR~A|C|L*A`=Jo@0c(8qWjZ!ts%wf4*qe=-BnD9I5Y1D}^z#BBF%pE) zl>}R84GSTDkh!q8L5V|p^W~sxAbO7}5@Gd2@dack6VEW$o1FSADwp;WBA#Fqs{UVX zGZnHihI?Q>wI2@j+hNz8O|0QYC41S$o%0jx; z@W29W8|&NuB)_Qaq9M|4Cg#m1olT!j+qyepp4OlgNrC8VrMEU={pUVObBMHjgc1wK zsq{7j52I5RW`nJ7;`ubl1cmNWI+;L9FSj+VU+T^N)LJM6Wp)lVs1y}8XHa_g~ z&Nvc@>7Bm1^WT@q#QUH2gpsl8jp!=!4$+J{6e2PuRC{AZAFtJoti}vQQz9%93)Jv@ zyFFLtJ?~V7jRsa)!wh|m--{awAi{odkjHLIAH4c(g@i>XrbqcZ2>P$-ncZB%-wva( zD?5>%sFYVXnp|OD@5wc&2RgL@X^*t^l|mto*0ZWOJ8mRKs-j|<=sELnkVIrOmN-@@ zLrD-VE0y(+ioeT_yL5E1rnaO3PxCqFpB1&`%C2%X+L$T~1m&1 + * Should always be false in production. + * + * @since 1.0.0 + */ + public static final Boolean isExampleEnabled = true; } \ No newline at end of file diff --git a/common/src/main/java/software/bluelib/annotations/EnableLogging.java b/common/src/main/java/software/bluelib/annotations/EnableLogging.java deleted file mode 100644 index cfe342a7..00000000 --- a/common/src/main/java/software/bluelib/annotations/EnableLogging.java +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) BlueLib. Licensed under the MIT License. - -package software.bluelib.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A custom annotation that acts as a boolean flag. - * If this annotation is present on a class or method, it is considered 'true'. - * Otherwise, it defaults to 'false'. - * - * @author MeAlam - * @version 1.0.0 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE, ElementType.METHOD}) -public @interface EnableLogging { -} diff --git a/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java b/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java index e3f9041d..f8257571 100644 --- a/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java +++ b/common/src/main/java/software/bluelib/entity/variant/VariantLoader.java @@ -69,33 +69,30 @@ public class VariantLoader implements IVariantEntityBase { * The merged JSON data is then parsed into {@link VariantParameter} instances and stored in {@link #entityVariantsMap}. *

          * - * @param folderPath {@link String} - The path to the folder containing JSON resources. + * @param pFolderPath {@link String} - The path to the folder containing JSON resources. * @param pServer {@link MinecraftServer} - The {@link MinecraftServer} instance used to access resources. * @param pEntityName {@link String} - The name of the entity whose variants should be cleared before loading new ones. */ - public static void loadVariants(String folderPath, MinecraftServer pServer, String pEntityName) { - BaseLogger.log(BaseLogLevel.INFO, "Starting to load variants for entity: " + pEntityName); + public static void loadVariants(String pFolderPath, MinecraftServer pServer, String pEntityName) { clearVariantsForEntity(pEntityName); ResourceManager resourceManager = pServer.getResourceManager(); JsonObject mergedJsonObject = new JsonObject(); - Collection collection = resourceManager.listResources(folderPath, pFiles -> pFiles.getPath().endsWith(".json")).keySet(); + Collection collection = resourceManager.listResources(pFolderPath, pFiles -> pFiles.getPath().endsWith(".json")).keySet(); - BaseLogger.log(BaseLogLevel.INFO, "Found resources: " + collection); + BaseLogger.log(BaseLogLevel.INFO, "Found resources: " + collection + " at: " + pFolderPath + " for: " + pEntityName, true); for (ResourceLocation resourceLocation : collection) { try { - BaseLogger.log(BaseLogLevel.INFO, "Loading JSON data from resource: " + resourceLocation.toString()); + BaseLogger.log(BaseLogLevel.INFO, "Loading JSON data from resource: " + resourceLocation.toString(), true); JsonObject jsonObject = jsonLoader.loadJson(resourceLocation, resourceManager); jsonMerger.mergeJsonObjects(mergedJsonObject, jsonObject); } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR, "Failed to load JSON data from resource: " + resourceLocation.toString(), pException); + BaseLogger.log(BaseLogLevel.ERROR, "Failed to load JSON data from resource: " + resourceLocation.toString(), pException, true); } } - - BaseLogger.log(BaseLogLevel.INFO, "Successfully loaded and merged JSON data for entity: " + pEntityName); parseVariants(mergedJsonObject); } @@ -108,7 +105,6 @@ public static void loadVariants(String folderPath, MinecraftServer pServer, Stri * @param pEntityName {@link String} - The name of the entity whose variants should be cleared. */ private static void clearVariantsForEntity(String pEntityName) { - BaseLogger.log(BaseLogLevel.INFO, "Clearing variants for entity: " + pEntityName); entityVariantsMap.remove(pEntityName); } @@ -125,7 +121,7 @@ private static void parseVariants(JsonObject pJsonObject) { String entityName = entry.getKey(); JsonArray textureArray = entry.getValue().getAsJsonArray(); - BaseLogger.log(BaseLogLevel.INFO, "Parsing variants for entity: " + entityName); + BaseLogger.log(BaseLogLevel.INFO, "Parsing variants for entity: " + entityName, true); List variantList = entityVariantsMap.computeIfAbsent(entityName, k -> new ArrayList<>()); for (JsonElement variant : textureArray) { @@ -165,7 +161,7 @@ private static VariantParameter getEntityVariant(String pJsonKey, JsonObject pJs * @return {@link List} - A {@link List} of {@link VariantParameter} instances for the specified entity. */ public static List getVariantsFromEntity(String pEntityName) { - BaseLogger.log(BaseLogLevel.INFO, "Retrieving variants for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO, "Retrieving variants for entity: " + pEntityName, true); return entityVariantsMap.getOrDefault(pEntityName, new ArrayList<>()); } @@ -180,14 +176,14 @@ public static List getVariantsFromEntity(String pEntityName) { * @return {@link VariantParameter} - The {@link VariantParameter} with the specified name, or {@code null} if not found. */ public static VariantParameter getVariantByName(String pEntityName, String pVariantName) { - BaseLogger.log(BaseLogLevel.INFO, "Retrieving variant by name: " + pVariantName + " for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO, "Retrieving variant by name: " + pVariantName + " for entity: " + pEntityName, true); List variants = getVariantsFromEntity(pEntityName); for (VariantParameter variant : variants) { if (variant.getVariantParameter().equals(pVariantName)) { return variant; } } - BaseLogger.log(BaseLogLevel.INFO, "Variant with name: " + pVariantName + " not found for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.INFO, "Variant with name: " + pVariantName + " not found for entity: " + pEntityName, true); return null; } } diff --git a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java index 753625ed..a3805dba 100644 --- a/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java +++ b/common/src/main/java/software/bluelib/entity/variant/VariantParameter.java @@ -72,17 +72,17 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { if (pJsonKey == null || pJsonObject == null) { Throwable throwable = new Throwable("JSON key or JSON object is null"); IllegalArgumentException exception = new IllegalArgumentException("JSON key and object must not be null"); - BaseLogger.log(BaseLogLevel.ERROR, exception.toString(), throwable); + BaseLogger.log(BaseLogLevel.ERROR, exception.toString(), throwable, true); throw exception; } this.jsonKey = pJsonKey; - BaseLogger.log(BaseLogLevel.INFO, "Creating VariantParameter with JSON key: " + pJsonKey); + BaseLogger.log(BaseLogLevel.INFO, "Creating VariantParameter with JSON key: " + pJsonKey, true); Set> entryMap = pJsonObject.entrySet(); for (Map.Entry entry : entryMap) { JsonElement element = entry.getValue(); if (element.isJsonPrimitive()) { addParameter(entry.getKey(), element.getAsString()); - BaseLogger.log(BaseLogLevel.SUCCESS, "Added primitive parameter: " + entry.getKey() + " = " + element.getAsString()); + BaseLogger.log(BaseLogLevel.SUCCESS, "Added primitive parameter: " + entry.getKey() + " = " + element.getAsString(), true); } else if (element.isJsonArray()) { StringBuilder arrayValues = new StringBuilder(); element.getAsJsonArray().forEach(e -> arrayValues.append(e.getAsString()).append(",")); @@ -90,13 +90,13 @@ public VariantParameter(String pJsonKey, JsonObject pJsonObject) { arrayValues.setLength(arrayValues.length() - 1); } addParameter(entry.getKey(), arrayValues.toString()); - BaseLogger.log(BaseLogLevel.SUCCESS, "Added array parameter: " + entry.getKey() + " = " + arrayValues.toString()); + BaseLogger.log(BaseLogLevel.SUCCESS, "Added array parameter: " + entry.getKey() + " = " + arrayValues, true); } else if (element.isJsonObject()) { addParameter(entry.getKey(), element.toString()); - BaseLogger.log(BaseLogLevel.SUCCESS, "Added object parameter: " + entry.getKey() + " = " + element.toString()); + BaseLogger.log(BaseLogLevel.SUCCESS, "Added object parameter: " + entry.getKey() + " = " + element, true); } else { addParameter(entry.getKey(), "null"); - BaseLogger.log(BaseLogLevel.SUCCESS, "Added null parameter for key: " + entry.getKey()); + BaseLogger.log(BaseLogLevel.SUCCESS, "Added null parameter for key: " + entry.getKey(), true); } } } @@ -116,10 +116,10 @@ public String getJsonKey() { if (this.jsonKey == null) { Throwable throwable = new Throwable("JSON key should not be null"); IllegalStateException exception = new IllegalStateException("JSON key is unexpectedly null when retrieving from VariantParameter."); - BaseLogger.log(BaseLogLevel.ERROR, "JSON key is unexpectedly null when retrieving from VariantParameter.", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "JSON key is unexpectedly null when retrieving from VariantParameter.", throwable, true); throw exception; } - BaseLogger.log(BaseLogLevel.INFO, "Retrieved JSON key: " + this.jsonKey); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved JSON key: " + this.jsonKey, true); return this.jsonKey; } @@ -136,7 +136,7 @@ public String getJsonKey() { */ public String getVariantParameter() { String variantName = getParameter(variantParameterName); - BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter name: " + variantName); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter name: " + variantName, true); return variantName; } @@ -152,7 +152,7 @@ public String getVariantParameter() { */ public void setVariantParameter(String pCustomVariantName) { variantParameterName = pCustomVariantName; - BaseLogger.log(BaseLogLevel.INFO, "Setting parameter name: " + variantParameterName); + BaseLogger.log(BaseLogLevel.INFO, "Setting parameter name: " + variantParameterName, true); } /** @@ -168,7 +168,7 @@ public void setVariantParameter(String pCustomVariantName) { */ public String getParameter(String pKey) { String value = (String) super.getParameter(pKey); - BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter for key " + pKey + ": " + value); + BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter for key " + pKey + ": " + value, true); return value; } } diff --git a/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java b/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java index ae0a3db7..8e62626e 100644 --- a/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java +++ b/common/src/main/java/software/bluelib/entity/variant/base/ParameterBase.java @@ -58,7 +58,6 @@ public abstract class ParameterBase { */ protected void addParameter(String pKey, Object pValue) { parameters.put(pKey, pValue); - BaseLogger.log(BaseLogLevel.SUCCESS, String.format("Parameter added: Key = %s, Value = %s", pKey, pValue), true); } /** @@ -73,9 +72,7 @@ protected void addParameter(String pKey, Object pValue) { * @since 1.0.0 */ protected Object getParameter(String pKey) { - Object value = parameters.get(pKey); - BaseLogger.log(BaseLogLevel.INFO, String.format("Parameter retrieved: Key = %s, Value = %s", pKey, value), true); - return value; + return parameters.get(pKey); } /** @@ -107,7 +104,6 @@ protected void removeParameter(String pKey) { * @since 1.0.0 */ protected Map getAllParameters() { - BaseLogger.log(BaseLogLevel.INFO, "Retrieved all parameters.", true); return new HashMap<>(parameters); } @@ -123,9 +119,7 @@ protected Map getAllParameters() { * @since 1.0.0 */ protected boolean containsParameter(String pKey) { - boolean exists = parameters.containsKey(pKey); - BaseLogger.log(BaseLogLevel.INFO, String.format("Parameter existence check: Key = %s, Exists = %b", pKey, exists), true); - return exists; + return parameters.containsKey(pKey); } /** @@ -139,9 +133,7 @@ protected boolean containsParameter(String pKey) { * @since 1.0.0 */ protected boolean isEmpty() { - boolean empty = parameters.isEmpty(); - BaseLogger.log(BaseLogLevel.INFO, "Checked if parameters are empty: " + empty, true); - return empty; + return parameters.isEmpty(); } /** @@ -152,7 +144,6 @@ protected boolean isEmpty() { */ protected void clearParameters() { parameters.clear(); - BaseLogger.log(BaseLogLevel.SUCCESS, "Cleared all parameters.", true); } /** @@ -163,9 +154,7 @@ protected void clearParameters() { * @since 1.0.0 */ protected int getParameterCount() { - int count = parameters.size(); - BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter count: " + count, true); - return count; + return parameters.size(); } /** @@ -179,7 +168,6 @@ protected int getParameterCount() { * @since 1.0.0 */ protected Set getParameterKeys() { - BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter keys.", true); return parameters.keySet(); } @@ -194,7 +182,6 @@ protected Set getParameterKeys() { * @since 1.0.0 */ protected Collection getParameterValues() { - BaseLogger.log(BaseLogLevel.INFO, "Retrieved parameter values.", true); return parameters.values(); } diff --git a/common/src/main/java/software/bluelib/event/ReloadEventHandler.java b/common/src/main/java/software/bluelib/event/ReloadEventHandler.java index 12d2bf2d..490c730b 100644 --- a/common/src/main/java/software/bluelib/event/ReloadEventHandler.java +++ b/common/src/main/java/software/bluelib/event/ReloadEventHandler.java @@ -63,16 +63,16 @@ public class ReloadEventHandler { */ protected static void registerEntityVariants(String pFolderPath, MinecraftServer pServer, String pModID, String pEntityName) { - BaseLogger.log(BaseLogLevel.INFO, "Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID); + BaseLogger.log(BaseLogLevel.INFO, "Attempting to register entity variants for " + pEntityName + " with ModID: " + pModID, true); try { VariantLoader.loadVariants(pFolderPath, pServer, pEntityName); - BaseLogger.log(BaseLogLevel.SUCCESS, "Successfully registered entity variants for " + pEntityName + " from ModID: " + pModID); + BaseLogger.log(BaseLogLevel.SUCCESS, "Successfully registered entity variants for " + pEntityName + " from ModID: " + pModID, true); } catch (JsonParseException pException) { - BaseLogger.log(BaseLogLevel.ERROR, "Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Failed to parse JSON(s) while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException, true); throw pException; } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR, "Unexpected error occurred while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Unexpected error occurred while registering entity variants for " + pEntityName + " from ModID: " + pModID, pException, true); throw pException; } } diff --git a/common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java b/common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java index 6938a537..22b5abc9 100644 --- a/common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java +++ b/common/src/main/java/software/bluelib/interfaces/platform/IPlatformHelper.java @@ -2,6 +2,9 @@ package software.bluelib.interfaces.platform; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; + /** * A {@code public interface} that defines platform-specific functionality for the BlueLib mod. *

          diff --git a/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java b/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java index 90336c54..40f83867 100644 --- a/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java +++ b/common/src/main/java/software/bluelib/interfaces/variant/IVariantEntity.java @@ -48,12 +48,12 @@ public interface IVariantEntity extends IVariantEntityBase { */ default String getRandomVariant(List pVariantNamesList, String pDefaultVariant) { if (pVariantNamesList.isEmpty()) { - BaseLogger.log(BaseLogLevel.INFO, "Variant names list is empty. Returning default variant: " + pDefaultVariant); + BaseLogger.log(BaseLogLevel.INFO, "Variant names list is empty. Returning default variant: " + pDefaultVariant, true); return pDefaultVariant; } int index = random.nextInt(pVariantNamesList.size()); String selectedVariant = pVariantNamesList.get(index); - BaseLogger.log(BaseLogLevel.SUCCESS, "Selected random variant: " + selectedVariant + " from list of size: " + pVariantNamesList.size()); + BaseLogger.log(BaseLogLevel.SUCCESS, "Selected random variant: " + selectedVariant + " from list of size: " + pVariantNamesList.size(), true); return selectedVariant; } } diff --git a/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java b/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java index a6c969a5..b74779a0 100644 --- a/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java +++ b/common/src/main/java/software/bluelib/interfaces/variant/base/IVariantEntityBase.java @@ -60,7 +60,7 @@ default List getEntityVariants(String pEntityName) { List variantNames = variants.stream() .map(VariantParameter::getVariantParameter) .collect(Collectors.toList()); - BaseLogger.log(BaseLogLevel.SUCCESS, "Retrieved " + variantNames.size() + " variants for entity: " + pEntityName); + BaseLogger.log(BaseLogLevel.SUCCESS, "Retrieved " + variantNames.size() + " variants for entity: " + pEntityName, true); return variantNames; } } diff --git a/common/src/main/java/software/bluelib/json/JSONLoader.java b/common/src/main/java/software/bluelib/json/JSONLoader.java index ed3ea2d2..fb1d607f 100644 --- a/common/src/main/java/software/bluelib/json/JSONLoader.java +++ b/common/src/main/java/software/bluelib/json/JSONLoader.java @@ -50,13 +50,11 @@ public class JSONLoader { * @since 1.0.0 */ public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager pResourceManager) { - BaseLogger.log(BaseLogLevel.INFO, "Attempting to load JSON resource: " + pResourceLocation); - try { Optional resource = pResourceManager.getResource(pResourceLocation); if (resource.isEmpty()) { - BaseLogger.log(BaseLogLevel.ERROR, "Resource not found: " + pResourceLocation); + BaseLogger.log(BaseLogLevel.ERROR, "Resource not found: " + pResourceLocation, true); return new JsonObject(); } @@ -64,12 +62,12 @@ public JsonObject loadJson(ResourceLocation pResourceLocation, ResourceManager p InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { JsonObject jsonObject = gson.fromJson(reader, JsonObject.class); - BaseLogger.log(BaseLogLevel.SUCCESS, "Successfully loaded JSON resource: " + pResourceLocation); + BaseLogger.log(BaseLogLevel.SUCCESS, "Successfully loaded JSON resource: " + pResourceLocation, true); return jsonObject; } } catch (IOException pException) { RuntimeException exception = new RuntimeException("Failed to load JSON resource: " + pResourceLocation, pException); - BaseLogger.log(BaseLogLevel.ERROR, "Failed to load JSON resource: " + pResourceLocation, exception); + BaseLogger.log(BaseLogLevel.ERROR, "Failed to load JSON resource: " + pResourceLocation, exception, true); throw exception; } } diff --git a/common/src/main/java/software/bluelib/json/JSONMerger.java b/common/src/main/java/software/bluelib/json/JSONMerger.java index a69d3c3f..e82cf1ff 100644 --- a/common/src/main/java/software/bluelib/json/JSONMerger.java +++ b/common/src/main/java/software/bluelib/json/JSONMerger.java @@ -39,7 +39,6 @@ public class JSONMerger { * @param pSource {@link JsonObject} - The source {@link JsonObject} to merge data from. This object is not modified by the operation. */ public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { - BaseLogger.log(BaseLogLevel.INFO, "Starting JSON merge operation."); for (Map.Entry entry : pSource.entrySet()) { String key = entry.getKey(); @@ -56,17 +55,15 @@ public void mergeJsonObjects(JsonObject pTarget, JsonObject pSource) { targetArray.add(element); } - BaseLogger.log(BaseLogLevel.ERROR, "Merged array for key: " + key); + BaseLogger.log(BaseLogLevel.ERROR, "Merged array for key: " + key, true); } else { pTarget.add(key, sourceElement); - BaseLogger.log(BaseLogLevel.WARNING, "Overwriting value for key: " + key); + BaseLogger.log(BaseLogLevel.WARNING, "Overwriting value for key: " + key, true); } } else { pTarget.add(key, sourceElement); - BaseLogger.log(BaseLogLevel.SUCCESS, "Added new key: " + key); + BaseLogger.log(BaseLogLevel.SUCCESS, "Added new key: " + key, true); } } - - BaseLogger.log(BaseLogLevel.SUCCESS, "JSON merge operation completed."); } } diff --git a/common/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java b/common/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java index 576caaa3..6beaa3f0 100644 --- a/common/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java +++ b/common/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java @@ -38,26 +38,26 @@ public class CaseConverterUtils { */ public static String toCamelCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.INFO, "Input for toCamelCase is null or empty."); + BaseLogger.log(BaseLogLevel.INFO, "Input for toCamelCase is null or empty.", true); return pInput; } if (Character.isUpperCase(pInput.charAt(0)) && !pInput.contains("_") && !pInput.contains("-")) { - BaseLogger.log(BaseLogLevel.INFO, "Input detected as PascalCase."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as PascalCase.", true); return pInput.substring(0, 1).toLowerCase() + pInput.substring(1); } if (pInput.contains("_")) { - BaseLogger.log(BaseLogLevel.INFO, "Input detected as snake_case."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as snake_case.", true); return convertUsingDelimiter(pInput, "_", true); } if (pInput.contains("-")) { - BaseLogger.log(BaseLogLevel.INFO, "Input detected as kebab-case."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as kebab-case.", true); return convertUsingDelimiter(pInput, "-", true); } - BaseLogger.log(BaseLogLevel.ERROR, "Input case is not recognized."); + BaseLogger.log(BaseLogLevel.ERROR, "Input case is not recognized.", true); return pInput; } @@ -73,26 +73,26 @@ public static String toCamelCase(String pInput) { */ public static String toPascalCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.WARNING, "Input for toPascalCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING, "Input for toPascalCase is null or empty.", true); return pInput; } if (!pInput.contains("_") && !pInput.contains("-") && Character.isLowerCase(pInput.charAt(0))) { - BaseLogger.log(BaseLogLevel.INFO, "Input detected as camelCase."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as camelCase.", true); return pInput.substring(0, 1).toUpperCase() + pInput.substring(1); } if (pInput.contains("_")) { - BaseLogger.log(BaseLogLevel.INFO, "Input detected as snake_case."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as snake_case.", true); return convertUsingDelimiter(pInput, "_", false); } if (pInput.contains("-")) { - BaseLogger.log(BaseLogLevel.INFO, "Input detected as kebab-case."); + BaseLogger.log(BaseLogLevel.INFO, "Input detected as kebab-case.", true); return convertUsingDelimiter(pInput, "-", false); } - BaseLogger.log(BaseLogLevel.ERROR, "Input case is not recognized."); + BaseLogger.log(BaseLogLevel.ERROR, "Input case is not recognized.", true); return pInput; } @@ -108,7 +108,7 @@ public static String toPascalCase(String pInput) { */ public static String toSnakeCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.WARNING, "Input for toSnakeCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING, "Input for toSnakeCase is null or empty.", true); return pInput; } @@ -116,7 +116,7 @@ public static String toSnakeCase(String pInput) { result = result.toLowerCase(); result = result.replace("-", "_"); - BaseLogger.log(BaseLogLevel.SUCCESS, "Converted to snake_case: " + result); + BaseLogger.log(BaseLogLevel.SUCCESS, "Converted to snake_case: " + result, true); return result; } @@ -132,7 +132,7 @@ public static String toSnakeCase(String pInput) { */ public static String toKebabCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.WARNING, "Input for toKebabCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING, "Input for toKebabCase is null or empty.", true); return pInput; } @@ -140,7 +140,7 @@ public static String toKebabCase(String pInput) { result = result.toLowerCase(); result = result.replace("_", "-"); - BaseLogger.log(BaseLogLevel.SUCCESS, "Converted to kebab-case: " + result); + BaseLogger.log(BaseLogLevel.SUCCESS, "Converted to kebab-case: " + result, true); return result; } @@ -157,7 +157,7 @@ public static String toKebabCase(String pInput) { */ public static String toUpperSnakeCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.WARNING, "Input for toUpperSnakeCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING, "Input for toUpperSnakeCase is null or empty.", true); return pInput; } @@ -178,7 +178,7 @@ public static String toUpperSnakeCase(String pInput) { */ public static String toTrainCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.WARNING, "Input for toTrainCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING, "Input for toTrainCase is null or empty.", true); return pInput; } @@ -198,7 +198,7 @@ public static String toTrainCase(String pInput) { */ public static String toFlatcase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.WARNING, "Input for toFlatcase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING, "Input for toFlatcase is null or empty.", true); return pInput; } @@ -218,7 +218,7 @@ public static String toFlatcase(String pInput) { */ public static String toCobolCase(String pInput) { if (pInput == null || pInput.isEmpty()) { - BaseLogger.log(BaseLogLevel.WARNING, "Input for toCobolCase is null or empty."); + BaseLogger.log(BaseLogLevel.WARNING, "Input for toCobolCase is null or empty.", true); return pInput; } diff --git a/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java b/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java index 7e98dd7c..f6211020 100644 --- a/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java +++ b/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java @@ -113,7 +113,7 @@ public static Date stringToDate(String pDateStr, String pFormat) throws ParseExc SimpleDateFormat formatter = new SimpleDateFormat(pFormat); return formatter.parse(pDateStr); } catch (ParseException pException) { - BaseLogger.log(BaseLogLevel.ERROR, "Error parsing date string: " + pDateStr + " with format: " + pFormat, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error parsing date string: " + pDateStr + " with format: " + pFormat, pException, true); throw pException; } } @@ -132,7 +132,7 @@ public static String dateToString(Date pDate, String pFormat) { SimpleDateFormat formatter = new SimpleDateFormat(pFormat); return formatter.format(pDate); } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR, "Error formatting date: " + pDate.toString() + " with format: " + pFormat, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error formatting date: " + pDate.toString() + " with format: " + pFormat, pException, true); return pException.getMessage(); } } diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java index 0d552f30..9651f89d 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -3,9 +3,7 @@ package software.bluelib.utils.logging; import software.bluelib.BlueLibConstants; -import software.bluelib.annotations.EnableLogging; -import java.lang.reflect.Method; import java.util.logging.Level; import java.util.logging.Logger; @@ -42,14 +40,14 @@ public class BaseLogger { * * @since 1.0.0 */ - private static boolean bluelibLogging = false; + private static boolean bluelibLogging = true; /** * A {@link Boolean} to enable or disable general logging. * * @since 1.0.0 */ - private static boolean isLoggingEnabled = false; + private static boolean isLoggingEnabled = true; /** * A {@code void} to enable or disable {@code BlueLib} specific logging. @@ -106,15 +104,12 @@ public static void setLoggingEnabled(boolean pEnabled) { * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, boolean pIsBlueLib) { - try { - if (pLogLevel == BaseLogLevel.ERROR || + if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB || pIsBlueLib && bluelibLogging || !pIsBlueLib && isLoggingEnabled) { - logger.log(pLogLevel, pMessage, pThrowable); - } - } catch (Exception ignored) { + logger.log(pLogLevel, pMessage, pThrowable); } } @@ -127,15 +122,12 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, b * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { - try { - if (pLogLevel == BaseLogLevel.ERROR || + if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB || pIsBlueLib && bluelibLogging || !pIsBlueLib && isLoggingEnabled) { - logger.log(pLogLevel, pMessage); - } - } catch (Exception ignored) { + logger.log(pLogLevel, pMessage); } } @@ -149,25 +141,11 @@ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { - try { - if (pLogLevel == BaseLogLevel.ERROR || + if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB || isLoggingEnabled) { - logger.log(pLogLevel, pMessage, pThrowable); - return; - } - StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - if (stackTrace.length > 3) { - Class callingClass = Class.forName(stackTrace[3].getClassName()); - Method callingMethod = callingClass.getMethod(stackTrace[3].getMethodName()); - - if (callingClass.isAnnotationPresent(EnableLogging.class) || - callingMethod.isAnnotationPresent(EnableLogging.class)) { - logger.log(pLogLevel, pMessage, pThrowable); - } - } - } catch (Exception ignored) { + logger.log(pLogLevel, pMessage, pThrowable); } } @@ -179,25 +157,11 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { * @since 1.0.0 */ public static void log(Level pLogLevel, String pMessage) { - try { - if (pLogLevel == BaseLogLevel.ERROR || + if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB || isLoggingEnabled) { - logger.log(pLogLevel, pMessage); - return; - } - StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - if (stackTrace.length > 3) { - Class callingClass = Class.forName(stackTrace[3].getClassName()); - Method callingMethod = callingClass.getMethod(stackTrace[3].getMethodName()); - - if (callingClass.isAnnotationPresent(EnableLogging.class) || - callingMethod.isAnnotationPresent(EnableLogging.class)) { - logger.log(pLogLevel, pMessage); - } - } - } catch (Exception ignored) { + logger.log(pLogLevel, pMessage); } } diff --git a/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java b/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java index b4156484..e314950d 100644 --- a/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java @@ -41,7 +41,7 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { double discriminant = pB * pB - 4 * pA * pC; if (discriminant < 0) { - BaseLogger.log(BaseLogLevel.WARNING, "No real roots found for the quadratic equation."); + BaseLogger.log(BaseLogLevel.WARNING, "No real roots found for the quadratic equation.", true); return new double[0]; } @@ -49,7 +49,7 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { double root1 = (-pB + sqrtDiscriminant) / (2 * pA); double root2 = (-pB - sqrtDiscriminant) / (2 * pA); - BaseLogger.log(BaseLogLevel.INFO, "Roots found: root1=" + root1 + ", root2=" + root2); + BaseLogger.log(BaseLogLevel.INFO, "Roots found: root1=" + root1 + ", root2=" + root2, true); return new double[]{root1, root2}; } @@ -65,7 +65,7 @@ public static double[] solveQuadraticEquation(double pA, double pB, double pC) { public static long factorial(int pNumber) { if (pNumber < 0) { IllegalArgumentException exception = new IllegalArgumentException("Number must be non-negative."); - BaseLogger.log(BaseLogLevel.INFO, "Attempted to calculate factorial of a negative number: " + pNumber, exception); + BaseLogger.log(BaseLogLevel.ERROR, "Attempted to calculate factorial of a negative number: " + pNumber, exception, true); throw exception; } @@ -74,7 +74,6 @@ public static long factorial(int pNumber) { result *= i; } - BaseLogger.log(BaseLogLevel.SUCCESS, "Factorial of " + pNumber + " is " + result); return result; } @@ -95,7 +94,6 @@ public static int calculateGCD(int pA, int pB) { pA = temp; } - BaseLogger.log(BaseLogLevel.SUCCESS, "GCD found: " + pA); return pA; } @@ -122,7 +120,6 @@ public static List> generatePowerSet(Set pSet) { powerSet.addAll(newSubsets); } - BaseLogger.log(BaseLogLevel.SUCCESS, "Power set generated with " + powerSet.size() + " subsets."); return powerSet; } } diff --git a/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java b/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java index e71ba71e..e2ad0b30 100644 --- a/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java @@ -77,7 +77,7 @@ public static double calculateDistance3D(double pX1, double pY1, double pZ1, dou public static double calculateCircleArea(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR, "Error calculating circle area", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating circle area", throwable, true); return Double.NaN; } return Math.PI * pRadius * pRadius; @@ -94,7 +94,7 @@ public static double calculateCircleArea(double pRadius) { public static double calculateCircleCircumference(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR, "Error calculating circle circumference", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating circle circumference", throwable, true); return Double.NaN; } return 2 * Math.PI * pRadius; @@ -112,7 +112,7 @@ public static double calculateCircleCircumference(double pRadius) { public static double calculateRectangleArea(double pWidth, double pHeight) { if (pWidth < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Width and height must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR, "Error calculating rectangle area", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating rectangle area", throwable, true); return Double.NaN; } return pWidth * pHeight; @@ -130,7 +130,7 @@ public static double calculateRectangleArea(double pWidth, double pHeight) { public static double calculateRectanglePerimeter(double pWidth, double pHeight) { if (pWidth < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Width and height must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR, "Error calculating rectangle perimeter", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating rectangle perimeter", throwable, true); return Double.NaN; } return 2 * (pWidth + pHeight); @@ -147,7 +147,7 @@ public static double calculateRectanglePerimeter(double pWidth, double pHeight) public static double calculateTriangleArea(double pBase, double pHeight) { if (pBase < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Base and height must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR, "Error calculating triangle area", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating triangle area", throwable, true); return Double.NaN; } return 0.5 * pBase * pHeight; @@ -165,7 +165,7 @@ public static double calculateTriangleArea(double pBase, double pHeight) { public static double calculateTrianglePerimeter(double pSide1, double pSide2, double pSide3) { if (pSide1 < 0 || pSide2 < 0 || pSide3 < 0) { Throwable throwable = new IllegalArgumentException("Sides must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR, "Error calculating triangle perimeter", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating triangle perimeter", throwable, true); return Double.NaN; } return pSide1 + pSide2 + pSide3; @@ -182,7 +182,7 @@ public static double calculateTrianglePerimeter(double pSide1, double pSide2, do public static double calculateSphereVolume(double pRadius) { if (pRadius < 0) { Throwable throwable = new IllegalArgumentException("Radius must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR, "Error calculating sphere volume", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating sphere volume", throwable, true); return Double.NaN; } return (4.0 / 3.0) * Math.PI * Math.pow(pRadius, 3); @@ -199,7 +199,7 @@ public static double calculateSphereVolume(double pRadius) { public static double calculateCubeSurfaceArea(double pSideLength) { if (pSideLength < 0) { Throwable throwable = new IllegalArgumentException("Side length must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR, "Error calculating cube surface area", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating cube surface area", throwable, true); return Double.NaN; } return 6 * Math.pow(pSideLength, 2); @@ -217,7 +217,7 @@ public static double calculateCubeSurfaceArea(double pSideLength) { public static double calculateCylinderVolume(double pRadius, double pHeight) { if (pRadius < 0 || pHeight < 0) { Throwable throwable = new IllegalArgumentException("Radius and height must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR, "Error calculating cylinder volume", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating cylinder volume", throwable, true); return Double.NaN; } return Math.PI * Math.pow(pRadius, 2) * pHeight; @@ -235,7 +235,7 @@ public static double calculateCylinderVolume(double pRadius, double pHeight) { public static double calculateConeSurfaceArea(double pRadius, double pSlantHeight) { if (pRadius < 0 || pSlantHeight < 0) { Throwable throwable = new IllegalArgumentException("Radius and slant height must be non-negative."); - BaseLogger.log(BaseLogLevel.ERROR, "Error calculating cone surface area", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating cone surface area", throwable, true); return Double.NaN; } return Math.PI * pRadius * (pRadius + pSlantHeight); diff --git a/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java b/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java index cde59e87..7c79f265 100644 --- a/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java @@ -37,7 +37,7 @@ public static double[][] multiplyMatrices(double[][] pMatrixA, double[][] pMatri int colsB = pMatrixB[0].length; if (colsA != pMatrixB.length) { Throwable throwable = new IllegalArgumentException("Number of columns in the first matrix must be equal to the number of rows in the second matrix."); - BaseLogger.log(BaseLogLevel.ERROR, "Error performing matrix multiplication", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error performing matrix multiplication", throwable, true); return new double[0][0]; } double[][] result = new double[rowsA][colsB]; @@ -83,7 +83,7 @@ public static double[][] transposeMatrix(double[][] pMatrix) { public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { if (pMatrix.length != 2 || pMatrix[0].length != 2) { Throwable throwable = new IllegalArgumentException("Matrix must be 2x2."); - BaseLogger.log(BaseLogLevel.ERROR, "Error calculating 2x2 matrix determinant", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error calculating 2x2 matrix determinant", throwable, true); return Double.NaN; } return pMatrix[0][0] * pMatrix[1][1] - pMatrix[0][1] * pMatrix[1][0]; @@ -101,13 +101,13 @@ public static double calculate2x2MatrixDeterminant(double[][] pMatrix) { public static double[][] invert2x2Matrix(double[][] pMatrix) { if (pMatrix.length != 2 || pMatrix[0].length != 2) { Throwable throwable = new IllegalArgumentException("Matrix must be 2x2."); - BaseLogger.log(BaseLogLevel.ERROR, "Error inverting 2x2 matrix", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error inverting 2x2 matrix", throwable, true); return new double[0][0]; } double determinant = calculate2x2MatrixDeterminant(pMatrix); if (determinant == 0) { Throwable throwable = new IllegalArgumentException("Matrix is not invertible."); - BaseLogger.log(BaseLogLevel.ERROR, "Error inverting 2x2 matrix", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error inverting 2x2 matrix", throwable, true); return new double[0][0]; } double[][] inverse = new double[2][2]; diff --git a/common/src/main/java/software/bluelib/utils/math/MiscUtils.java b/common/src/main/java/software/bluelib/utils/math/MiscUtils.java index 8f576256..c7e4e572 100644 --- a/common/src/main/java/software/bluelib/utils/math/MiscUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/MiscUtils.java @@ -47,7 +47,7 @@ public static int stringToIntWithDefault(String pString, int pDefaultValue) { try { return Integer.parseInt(pString); } catch (NumberFormatException pException) { - BaseLogger.log(BaseLogLevel.ERROR, "Error converting string to integer", pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error converting string to integer", pException, true); return pDefaultValue; } } @@ -93,7 +93,7 @@ public static int calculateLevenshteinDistance(String pStr1, String pStr2) { public static int[] hexToRGB(String pHex) { if (pHex == null || pHex.isEmpty()) { Throwable throwable = new IllegalArgumentException("Hex color code cannot be null or empty."); - BaseLogger.log(BaseLogLevel.ERROR, "Error converting hex to RGB", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error converting hex to RGB", throwable, true); return new int[]{0, 0, 0}; } if (pHex.charAt(0) == '#') { @@ -101,7 +101,7 @@ public static int[] hexToRGB(String pHex) { } if (pHex.length() != 6) { Throwable throwable = new IllegalArgumentException("Invalid hex color code."); - BaseLogger.log(BaseLogLevel.ERROR, "Error converting hex to RGB", throwable); + BaseLogger.log(BaseLogLevel.ERROR, "Error converting hex to RGB", throwable, true); return new int[]{0, 0, 0}; } try { @@ -110,7 +110,7 @@ public static int[] hexToRGB(String pHex) { int b = Integer.parseInt(pHex.substring(4, 6), 16); return new int[]{r, g, b}; } catch (NumberFormatException pException) { - BaseLogger.log(BaseLogLevel.ERROR, "Error parsing hex color code to RGB", pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error parsing hex color code to RGB", pException, true); return new int[]{0, 0, 0}; } } diff --git a/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java index 868a777d..38e88ca4 100644 --- a/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java @@ -44,7 +44,7 @@ public class RandomGenUtils { public static int generateRandomInt(int pMin, int pMax) { if (pMin > pMax) { Throwable throwable = new IllegalArgumentException("Minimum value must not be greater than maximum value."); - BaseLogger.log(BaseLogLevel.WARNING, "Error generating random integer", throwable); + BaseLogger.log(BaseLogLevel.WARNING, "Error generating random integer", throwable, true); return 0; } return pMin + (int) (Math.random() * (pMax - pMin + 1)); @@ -62,7 +62,7 @@ public static int generateRandomInt(int pMin, int pMax) { public static double generateRandomDouble(double pMin, double pMax) { if (pMin > pMax) { Throwable throwable = new IllegalArgumentException("Minimum value must not be greater than maximum value."); - BaseLogger.log(BaseLogLevel.WARNING, "Error generating random double", throwable); + BaseLogger.log(BaseLogLevel.WARNING, "Error generating random double", true); return 0; } return pMin + Math.random() * (pMax - pMin); @@ -91,7 +91,7 @@ public static boolean generateRandomBoolean() { public static String generateRandomString(int pLength) { if (pLength < 0) { Throwable throwable = new IllegalArgumentException("Length must be non-negative."); - BaseLogger.log(BaseLogLevel.WARNING, "Error generating random string", throwable); + BaseLogger.log(BaseLogLevel.WARNING, "Error generating random string", throwable, true); return "unknown"; } String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; @@ -115,7 +115,7 @@ public static String generateRandomString(int pLength) { public static String generateRandomStringWithPrefix(String pPrefix, int pLength) { if (pLength < 0) { Throwable throwable = new IllegalArgumentException("Length must be non-negative."); - BaseLogger.log(BaseLogLevel.WARNING, "Error generating random string with prefix", throwable); + BaseLogger.log(BaseLogLevel.WARNING, "Error generating random string with prefix", throwable, true); return "unknown"; } return pPrefix + generateRandomString(pLength - pPrefix.length()); diff --git a/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java index 04aa9303..54d048d8 100644 --- a/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java @@ -50,7 +50,7 @@ public class StatisticalUtils { */ public static double calculateMean(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, mean calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, mean calculation might fail.", true); return 0; } @@ -58,9 +58,7 @@ public static double calculateMean(double[] pValues) { for (double value : pValues) { sum += value; } - double mean = sum / pValues.length; - BaseLogger.log(BaseLogLevel.SUCCESS, "Mean successfully calculated: " + mean); - return mean; + return sum / pValues.length; } /** @@ -76,19 +74,17 @@ public static double calculateMean(double[] pValues) { */ public static double calculateMedian(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, median calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, median calculation might fail.", true); return 0; } double[] sorted = pValues.clone(); Arrays.sort(sorted); int middle = sorted.length / 2; - double median = (sorted.length % 2 == 0) ? + + return (sorted.length % 2 == 0) ? (sorted[middle - 1] + sorted[middle]) / 2.0 : sorted[middle]; - - BaseLogger.log(BaseLogLevel.SUCCESS, "Median successfully calculated: " + median); - return median; } /** @@ -104,7 +100,7 @@ public static double calculateMedian(double[] pValues) { */ public static double calculateMode(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, mode calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, mode calculation might fail.", true); return 0; } @@ -121,8 +117,6 @@ public static double calculateMode(double[] pValues) { mode = entry.getKey(); } } - - BaseLogger.log(BaseLogLevel.SUCCESS, "Mode successfully calculated: " + mode); return mode; } @@ -139,7 +133,7 @@ public static double calculateMode(double[] pValues) { */ public static double calculateStandardDeviation(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, standard deviation calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, standard deviation calculation might fail.", true); return 0; } @@ -148,9 +142,7 @@ public static double calculateStandardDeviation(double[] pValues) { for (double value : pValues) { sumSquaredDifferences += Math.pow(value - mean, 2); } - double stdDev = Math.sqrt(sumSquaredDifferences / pValues.length); - BaseLogger.log(BaseLogLevel.SUCCESS, "Standard deviation successfully calculated: " + stdDev); - return stdDev; + return Math.sqrt(sumSquaredDifferences / pValues.length); } /** @@ -166,7 +158,7 @@ public static double calculateStandardDeviation(double[] pValues) { */ public static double calculateVariance(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, variance calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, variance calculation might fail.", true); return 0; } @@ -175,9 +167,7 @@ public static double calculateVariance(double[] pValues) { for (double value : pValues) { sumSquaredDifferences += Math.pow(value - mean, 2); } - double variance = sumSquaredDifferences / pValues.length; - BaseLogger.log(BaseLogLevel.SUCCESS, "Variance successfully calculated: " + variance); - return variance; + return sumSquaredDifferences / pValues.length; } /** @@ -193,15 +183,13 @@ public static double calculateVariance(double[] pValues) { */ public static double calculateRange(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, range calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, range calculation might fail.", true); return 0; } double max = Arrays.stream(pValues).max().orElseThrow(); double min = Arrays.stream(pValues).min().orElseThrow(); - double range = max - min; - BaseLogger.log(BaseLogLevel.SUCCESS, "Range successfully calculated: " + range); - return range; + return max - min; } /** @@ -217,14 +205,12 @@ public static double calculateRange(double[] pValues) { */ public static double calculateCoefficientOfVariation(double[] pValues) { if (pValues.length == 0) { - BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, coefficient of variation calculation might fail."); + BaseLogger.log(BaseLogLevel.WARNING, "Array is empty, coefficient of variation calculation might fail.", true); return 0; } double mean = calculateMean(pValues); double stdDev = calculateStandardDeviation(pValues); - double coefficient = (stdDev / mean) * 100; - BaseLogger.log(BaseLogLevel.SUCCESS, "Coefficient of variation successfully calculated: " + coefficient); - return coefficient; + return (stdDev / mean) * 100; } } diff --git a/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java b/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java index c327045f..3a0896bf 100644 --- a/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java +++ b/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java @@ -51,11 +51,9 @@ public class ChunkUtils { */ public static Biome getBiomeOfChunk(Level pLevel, ChunkPos pChunkPos) { try { - Biome biome = pLevel.getBiome(pChunkPos.getWorldPosition()).value(); - BaseLogger.log(BaseLogLevel.INFO, "Retrieved biome for chunk at position " + pChunkPos + ": " + biome); - return biome; + return pLevel.getBiome(pChunkPos.getWorldPosition()).value(); } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving biome for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving biome for chunk at position " + pChunkPos, pException, true); throw pException; } } @@ -79,11 +77,9 @@ public static String getBiomeRegistryNameOfChunk(Level pLevel, ChunkPos pChunkPo if (biomeKey == null) { NullPointerException exception = new NullPointerException("Biome at chunk position " + pChunkPos + " is null"); - BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving biome registry name of chunk at " + pChunkPos, exception); + BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving biome registry name of chunk at " + pChunkPos, exception, true); return exception.getMessage(); } - - BaseLogger.log(BaseLogLevel.SUCCESS, "Retrieved biome registry name for chunk at position " + pChunkPos + ": " + biomeKey); return biomeKey.toString(); } @@ -118,11 +114,9 @@ public static String getBiomeSimpleNameOfChunk(Level pLevel, ChunkPos pChunkPos) public static Collection getChunkTileEntities(Level pLevel, ChunkPos pChunkPos) { try { LevelChunk chunk = pLevel.getChunk(pChunkPos.x, pChunkPos.z); - Collection tileEntities = chunk.getBlockEntities().values(); - BaseLogger.log(BaseLogLevel.INFO, "Retrieved " + tileEntities.size() + " tile entities for chunk at position " + pChunkPos); - return tileEntities; + return chunk.getBlockEntities().values(); } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving tile entities for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving tile entities for chunk at position " + pChunkPos, pException, true); throw pException; } } @@ -142,7 +136,8 @@ public static Collection getChunkTileEntities(Level pLevel, ChunkPo public static String getChunkTileEntitiesRegistryNames(Level pLevel, ChunkPos pChunkPos) { try { Collection blockEntities = getChunkTileEntities(pLevel, pChunkPos); - String registryNames = blockEntities.stream() + + return blockEntities.stream() .map(blockEntity -> { ResourceLocation key = pLevel.registryAccess() .registryOrThrow(Registries.BLOCK_ENTITY_TYPE) @@ -151,11 +146,8 @@ public static String getChunkTileEntitiesRegistryNames(Level pLevel, ChunkPos pC return key != null ? key.toString() : "unknown"; }) .collect(Collectors.joining(", ")); - - BaseLogger.log(BaseLogLevel.INFO, "Tile entities for chunk at position " + pChunkPos + ": " + registryNames); - return registryNames; } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving tile entity registry names for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error retrieving tile entity registry names for chunk at position " + pChunkPos, pException, true); throw pException; } } @@ -205,11 +197,9 @@ public static int getChunkBlockCount(Level pLevel, ChunkPos pChunkPos) { } } } - - BaseLogger.log(BaseLogLevel.INFO, "Non-air block count for chunk at position " + pChunkPos + ": " + blockCount); return blockCount; } catch (Exception pException) { - BaseLogger.log(BaseLogLevel.ERROR, "Error counting blocks for chunk at position " + pChunkPos, pException); + BaseLogger.log(BaseLogLevel.ERROR, "Error counting blocks for chunk at position " + pChunkPos, pException, true); throw pException; } } diff --git a/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java index bdba99b8..efe23bd6 100644 --- a/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java +++ b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java @@ -163,8 +163,8 @@ public ParameterBuilder connect() { } variantParametersMap.put(variantName, updatedParameters); } else { - Throwable cause = new Throwable("Variant or entity not found in the database"); - BaseLogger.log(BaseLogLevel.ERROR, "Variant '" + variantName + "' not found for entity '" + entityName + "'", cause); + Throwable throwable = new Throwable("Variant or entity not found in the database"); + BaseLogger.log(BaseLogLevel.ERROR, "Variant '" + variantName + "' not found for entity '" + entityName + "'", throwable, true); } return this; } diff --git a/fabric/build.gradle b/fabric/build.gradle index ff277547..7591cf5c 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -10,6 +10,9 @@ dependencies { } modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}" + + modCompileOnly("curse.maven:geckolib-388172:5605709") + modRuntimeOnly("curse.maven:geckolib-388172:5605709") } loom { diff --git a/fabric/src/main/java/software/bluelib/BlueLib.java b/fabric/src/main/java/software/bluelib/BlueLib.java index 846da7c5..469a4f01 100644 --- a/fabric/src/main/java/software/bluelib/BlueLib.java +++ b/fabric/src/main/java/software/bluelib/BlueLib.java @@ -4,6 +4,11 @@ import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; +import software.bluelib.example.entity.dragon.DragonEntity; +import software.bluelib.example.entity.rex.RexEntity; +import software.bluelib.example.event.ReloadHandler; +import software.bluelib.example.init.ModEntities; /** * A {@code public class} that implements {@link ModInitializer} to initialize the BlueLib mod on the Fabric platform. @@ -44,6 +49,12 @@ public class BlueLib implements ModInitializer { */ @Override public void onInitialize() { + if (BlueLibCommon.isDeveloperMode() && BlueLibCommon.PLATFORM.isModLoaded("geckolib") && BlueLibConstants.isExampleEnabled) { + ModEntities.initializeEntities(); + ReloadHandler.registerEventListeners(); + FabricDefaultAttributeRegistry.register(ModEntities.EXAMPLE_ONE, DragonEntity.createMobAttributes()); + FabricDefaultAttributeRegistry.register(ModEntities.EXAMPLE_TWO, RexEntity.createMobAttributes()); + } ClientTickEvents.END_CLIENT_TICK.register(client -> { if (!hasInitialized) { hasInitialized = true; diff --git a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java new file mode 100644 index 00000000..130d2740 --- /dev/null +++ b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -0,0 +1,141 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.dragon; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.*; +import net.minecraft.world.entity.ai.attributes.AttributeSupplier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; +import software.bluelib.interfaces.variant.IVariantAccessor; +import software.bluelib.interfaces.variant.IVariantEntity; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; +import software.bluelib.utils.variant.ParameterUtils; + +/** + * A {@code DragonEntity} class representing a dragon entity in the game, which extends {@link TamableAnimal} + * and implements {@link IVariantEntity} and {@link GeoEntity}. + *

          + * This class manages the dragon's variant system, its data synchronization, and integrates with the GeckoLib + * animation system. + *

          + * + *

          + * Key Methods: + *

            + *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
          • + *
          • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
          • + *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • + *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • + *
          + *

          + * + * @author MeAlam + * @since 1.0.0 + */ +public class DragonEntity extends TamableAnimal implements IVariantEntity, GeoEntity { + /** + * The name of the entity. + * + * @since 1.0.0 + */ + protected final String entityName = "dragon"; + + /** + * Constructs a new {@link DragonEntity} instance with the specified entity type and level. + * + * @param pEntityType {@link EntityType} - The type of the entity. + * @param pLevel {@link Level} - The level in which the entity is created. + * @author MeAlam + * @since 1.0.0 + */ + public DragonEntity(EntityType pEntityType, Level pLevel) { + super(pEntityType, pLevel); + } + + public void setVariantName(String pVariantName) { + ((IVariantAccessor) this).setEntityVariantName(pVariantName); + } + + public String getVariantName() { + return ((IVariantAccessor) this).getEntityVariantName(); + } + + /** + * Finalizes the spawning of the dragon entity. + *

          + * This method sets up the variant for the entity and connects parameters if needed. + *

          + * + * @param pLevel {@link ServerLevelAccessor} - The level in which the entity is spawned. + * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. + * @param pReason {@link MobSpawnType} - The reason for spawning the entity. + * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. + * @return {@link SpawnGroupData} - Updated spawn data. + * @author MeAlam + * @since 1.0.0 + */ + @Override + public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { + if (getVariantName() == null || getVariantName().isEmpty()) { + setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); + ParameterUtils.ParameterBuilder.forVariant(entityName, this.getVariantName()) + .withParameter("customParameter") + .withParameter("int") + .withParameter("bool") + .withParameter("array") + .connect(); + } + BaseLogger.log(BaseLogLevel.SUCCESS, "Dragon Spawned with Variant: " + getVariantName(), true); + return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); + } + + + /** + * All Code below this Fragment is not Library Related!!! + */ + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public static AttributeSupplier.Builder createAttributes() { + return Mob.createMobAttributes() + .add(Attributes.MOVEMENT_SPEED, 0.3) + .add(Attributes.MAX_HEALTH, 10) + .add(Attributes.ARMOR, 0) + .add(Attributes.ATTACK_DAMAGE, 3) + .add(Attributes.FOLLOW_RANGE, 16) + .add(Attributes.FLYING_SPEED, 0.3); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return cache; + } + + @Nullable + @Override + public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { + return null; + } + + @Override + public boolean isFood(@NotNull ItemStack pItemStack) { + return false; + } +} diff --git a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java new file mode 100644 index 00000000..2979ca65 --- /dev/null +++ b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java @@ -0,0 +1,29 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.dragon; + +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; +import software.bluelib.BlueLibConstants; + +public class DragonModel extends GeoModel { + + + // Get the Model Location + @Override + public ResourceLocation getModelResource(DragonEntity pObject) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/dragon.geo.json"); + } + + // Get the Texture Location + @Override + public ResourceLocation getTextureResource(DragonEntity pObject) { + return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); + } + + // Get the Animation Location + @Override + public ResourceLocation getAnimationResource(DragonEntity pAnimatable) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/dragon.animation.json"); + } +} diff --git a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java new file mode 100644 index 00000000..c770ac48 --- /dev/null +++ b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java @@ -0,0 +1,14 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.dragon; + +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class DragonRender extends GeoEntityRenderer { + + // Render the entity + public DragonRender(EntityRendererProvider.Context pRenderManager) { + super(pRenderManager, new DragonModel()); + } +} diff --git a/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java new file mode 100644 index 00000000..8c3d1fa7 --- /dev/null +++ b/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -0,0 +1,142 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.rex; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.*; +import net.minecraft.world.entity.ai.attributes.AttributeSupplier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; +import software.bluelib.interfaces.variant.IVariantAccessor; +import software.bluelib.interfaces.variant.IVariantEntity; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; +import software.bluelib.utils.variant.ParameterUtils; + +/** + * A {@code RexEntity} class representing a Rex entity in the game, which extends {@link TamableAnimal} + * and implements {@link IVariantEntity} and {@link GeoEntity}. + *

          + * This class manages the Rex's variant system, its data synchronization, and integrates with the GeckoLib + * animation system. + *

          + * + *

          + * Key Methods: + *

            + *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
          • + *
          • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
          • + *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • + *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • + *
          • {@link #setVariantName(String)} - Sets the variant name of the Rex.
          • + *
          • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
          • + *
          + *

          + * + * @author MeAlam + * @since 1.0.0 + */ +public class RexEntity extends TamableAnimal implements IVariantEntity, GeoEntity { + /** + * The name of the entity. + * + * @since 1.0.0 + */ + protected final String entityName = "rex"; + + /** + * Constructs a new {@link RexEntity} instance with the specified entity type and level. + * + * @param pEntityType {@link EntityType} - The type of the entity. + * @param pLevel {@link Level} - The level in which the entity is created. + * @author MeAlam + * @since 1.0.0 + */ + public RexEntity(EntityType pEntityType, Level pLevel) { + super(pEntityType, pLevel); + } + + public void setVariantName(String pVariantName) { + ((IVariantAccessor) this).setEntityVariantName(pVariantName); + } + + public String getVariantName() { + return ((IVariantAccessor) this).getEntityVariantName(); + } + + /** + * Finalizes the spawning of the Rex entity. + *

          + * This method sets up the variant for the entity and connects parameters if needed. + *

          + * + * @param pLevel {@link ServerLevelAccessor} - The level in which the entity is spawned. + * @param pDifficulty {@link DifficultyInstance} - The difficulty instance for spawning. + * @param pReason {@link MobSpawnType} - The reason for spawning the entity. + * @param pSpawnData {@link SpawnGroupData} - Data related to the spawn. + * @return {@link SpawnGroupData} - Updated spawn data. + * @author MeAlam + * @since 1.0.0 + */ + @Override + public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNull DifficultyInstance pDifficulty, @NotNull MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData) { + if (getVariantName() == null || getVariantName().isEmpty()) { + this.setVariantName(getRandomVariant(getEntityVariants(entityName), "normal")); + ParameterUtils.ParameterBuilder.forVariant(entityName, this.getVariantName()) + .withParameter("customParameter") + .withParameter("int") + .withParameter("bool") + .withParameter("array") + .connect(); + } + BaseLogger.log(BaseLogLevel.SUCCESS, "Dragon Spawned with Variant: " + getVariantName(), true); + return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); + } + + /** + * All Code below this Fragment is not Library Related!!! + */ + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + + public static AttributeSupplier.Builder createAttributes() { + return Mob.createMobAttributes() + .add(Attributes.MOVEMENT_SPEED, 0.3) + .add(Attributes.MAX_HEALTH, 10) + .add(Attributes.ARMOR, 0) + .add(Attributes.ATTACK_DAMAGE, 3) + .add(Attributes.FOLLOW_RANGE, 16) + .add(Attributes.FLYING_SPEED, 0.3); + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return cache; + } + + @Nullable + @Override + public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { + return null; + } + + @Override + public boolean isFood(@NotNull ItemStack pItemStack) { + return false; + } +} diff --git a/fabric/src/main/java/software/bluelib/example/entity/rex/RexModel.java b/fabric/src/main/java/software/bluelib/example/entity/rex/RexModel.java new file mode 100644 index 00000000..4323f872 --- /dev/null +++ b/fabric/src/main/java/software/bluelib/example/entity/rex/RexModel.java @@ -0,0 +1,29 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.rex; + +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.model.GeoModel; +import software.bluelib.BlueLibConstants; + +public class RexModel extends GeoModel { + + + // Get the Model Locations + @Override + public ResourceLocation getModelResource(RexEntity pObject) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/rex.geo.json"); + } + + // Get the Texture Location + @Override + public ResourceLocation getTextureResource(RexEntity pObject) { + return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); + } + + // Get the Animation Location + @Override + public ResourceLocation getAnimationResource(RexEntity pAnimatable) { + return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/rex.animation.json"); + } +} diff --git a/fabric/src/main/java/software/bluelib/example/entity/rex/RexRender.java b/fabric/src/main/java/software/bluelib/example/entity/rex/RexRender.java new file mode 100644 index 00000000..776c5920 --- /dev/null +++ b/fabric/src/main/java/software/bluelib/example/entity/rex/RexRender.java @@ -0,0 +1,14 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.entity.rex; + +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class RexRender extends GeoEntityRenderer { + + // Render the entity + public RexRender(EntityRendererProvider.Context pRenderManager) { + super(pRenderManager, new RexModel()); + } +} diff --git a/fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java b/fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java new file mode 100644 index 00000000..f82c12db --- /dev/null +++ b/fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java @@ -0,0 +1,133 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + +package software.bluelib.example.event; + +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.packs.PackType; +import software.bluelib.BlueLibConstants; +import software.bluelib.event.ReloadEventHandler; +import software.bluelib.utils.logging.BaseLogLevel; +import software.bluelib.utils.logging.BaseLogger; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +/** + * A {@code ReloadHandler} class that handles server start and reload events related to entity variants. + *

          + * This class extends {@link ReloadEventHandler} and implements event handling for server starting and reloading, + * ensuring that entity variant data is properly loaded and refreshed. + *

          + * + *

          + * Key Methods: + *

            + *
          • {@link #onServerStart(MinecraftServer)} - Handles server starting events to initialize entity variants.
          • + *
          • {@link #onReload()} - Handles reload events to refresh entity variants.
          • + *
          • {@link #LoadEntityVariants(MinecraftServer)} - Loads entity variants from JSON files into the server.
          • + *
          + *

          + * + * @author MeAlam + * @since 1.0.0 + */ +public class ReloadHandler extends ReloadEventHandler { + + /** + * The {@link MinecraftServer} instance for the server handling the events. + *

          + * This is initialized when the server starts and used to load entity variants. + *

          + * + * @since 1.0.0 + */ + private static MinecraftServer server; + + /** + * Handles the server starting event to initialize the {@link MinecraftServer} instance + * and load entity variants. + * + * @param pServer {@link MinecraftServer} - The server triggered when the server starts. + * @author MeAlam + * @since 1.0.0 + */ + public static void onServerStart(MinecraftServer pServer) { + server = pServer; + ReloadHandler.LoadEntityVariants(server); + BaseLogger.log(BaseLogLevel.INFO, "Entity variants loaded.", true); + } + + /** + * Handles the reload event by scheduling a task to reload entity variants. + *

          + * This method schedules the {@code LoadEntityVariants} method to run after a short delay. + *

          + * + * @author MeAlam + * @since 1.0.0 + */ + public static void onReload() { + if (server != null) { + BlueLibConstants.SCHEDULER.schedule(() -> { + server.execute(() -> { + ReloadHandler.LoadEntityVariants(server); + BaseLogger.log(BaseLogLevel.INFO, "Entity variants reloaded.", true); + }); + }, 1, TimeUnit.SECONDS); + } + } + + /** + * The base path for entity variant JSON files. + *

          + * This path is used to locate the files that contain variant data for entities. + *

          + * + * @since 1.0.0 + */ + private static final String basePath = "variant/entity/"; + + /** + * A {@link List} of entity names for which variants will be loaded. + *

          + * This list defines which entities will have their variants loaded from JSON files. + *

          + * + * @since 1.0.0 + */ + private static final List entityNames = Arrays.asList("dragon", "rex"); + + /** + * Loads entity variants from JSON files into the {@link MinecraftServer}. + *

          + * This method iterates through the list of entity names, constructs file paths, and registers + * entity variants using the {@link ReloadEventHandler}. + *

          + * + * @param pServer {@link MinecraftServer} - The server on which the entity variants will be loaded. + * @author MeAlam + * @since 1.0.0 + */ + public static void LoadEntityVariants(MinecraftServer pServer) { + for (String entityName : entityNames) { + String folderPath = basePath + entityName; + ReloadEventHandler.registerEntityVariants(folderPath, pServer, BlueLibConstants.MOD_ID, entityName); + BaseLogger.log(BaseLogLevel.INFO, "Entity variants loaded for " + entityName + ".", true); + } + } + + /** + * Registers the server start and reload event listeners. + * + * @author MeAlam + * @since 1.0.0 + */ + public static void registerEventListeners() { + ServerLifecycleEvents.SERVER_STARTING.register(ReloadHandler::onServerStart); + } +} diff --git a/fabric/src/main/java/software/bluelib/example/init/ClientInit.java b/fabric/src/main/java/software/bluelib/example/init/ClientInit.java new file mode 100644 index 00000000..587b51bf --- /dev/null +++ b/fabric/src/main/java/software/bluelib/example/init/ClientInit.java @@ -0,0 +1,14 @@ +package software.bluelib.example.init; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; +import software.bluelib.example.entity.dragon.DragonRender; +import software.bluelib.example.entity.rex.RexRender; + +public class ClientInit implements ClientModInitializer { + @Override + public void onInitializeClient() { + EntityRendererRegistry.register(ModEntities.EXAMPLE_ONE, DragonRender::new); + EntityRendererRegistry.register(ModEntities.EXAMPLE_TWO, RexRender::new); + } +} diff --git a/fabric/src/main/java/software/bluelib/example/init/ModEntities.java b/fabric/src/main/java/software/bluelib/example/init/ModEntities.java new file mode 100644 index 00000000..741751f0 --- /dev/null +++ b/fabric/src/main/java/software/bluelib/example/init/ModEntities.java @@ -0,0 +1,33 @@ +package software.bluelib.example.init; + +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EntityType; +import software.bluelib.BlueLibConstants; +import software.bluelib.example.entity.dragon.DragonEntity; +import software.bluelib.example.entity.rex.RexEntity; + +import static net.minecraft.world.entity.MobCategory.CREATURE; + +public class ModEntities { + + public static EntityType EXAMPLE_ONE; + public static EntityType EXAMPLE_TWO; + + public static void initializeEntities() { + EXAMPLE_ONE = Registry.register( + BuiltInRegistries.ENTITY_TYPE, + ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "example_one"), + EntityType.Builder.of(DragonEntity::new, CREATURE) + .sized(0.6F, 1.8F) + .build("example_one")); + + EXAMPLE_TWO = Registry.register( + BuiltInRegistries.ENTITY_TYPE, + ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "example_two"), + EntityType.Builder.of(RexEntity::new, CREATURE) + .sized(0.6F, 1.8F) + .build("example_two")); + } +} diff --git a/fabric/src/main/resources/assets/bluelib/animations/dragon.animation.json b/fabric/src/main/resources/assets/bluelib/animations/dragon.animation.json new file mode 100644 index 00000000..0b02f765 --- /dev/null +++ b/fabric/src/main/resources/assets/bluelib/animations/dragon.animation.json @@ -0,0 +1,63 @@ +{ + "format_version": "1.8.0", + "animations": { + "test": { + "loop": true, + "bones": { + "Body": { + "rotation": { + "vector": [-20.44582, 11.73507, -4.3361], + "easing": "linear" + }, + "position": { + "vector": [0, -1, 0], + "easing": "linear" + } + }, + "leftleg": { + "rotation": { + "vector": [0, 22.5, 0], + "easing": "linear" + } + }, + "rightleg": { + "rotation": { + "vector": [0, -22.5, 0], + "easing": "linear" + } + }, + "rightwing1": { + "rotation": { + "vector": [0, 0, -20], + "easing": "linear" + } + }, + "leftwing": { + "rotation": { + "vector": [0, 0, -10], + "easing": "linear" + } + }, + "leftwing1": { + "rotation": { + "vector": [0, 0, 30], + "easing": "linear" + } + }, + "neck": { + "rotation": { + "vector": [-40, 0, 0], + "easing": "linear" + } + }, + "Head": { + "rotation": { + "vector": [72.5, 0, 0], + "easing": "linear" + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/fabric/src/main/resources/assets/bluelib/animations/rex.animation.json b/fabric/src/main/resources/assets/bluelib/animations/rex.animation.json new file mode 100644 index 00000000..5d8891b4 --- /dev/null +++ b/fabric/src/main/resources/assets/bluelib/animations/rex.animation.json @@ -0,0 +1,51 @@ +{ + "format_version": "1.8.0", + "animations": { + "animation2": { + "loop": true, + "bones": { + "body": { + "rotation": { + "vector": [0, -15, 0] + } + }, + "tail2": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail3": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail4": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail5": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "tail6": { + "rotation": { + "vector": [0, 20, 0] + } + }, + "neck": { + "rotation": { + "vector": [0, -2.5, 0] + } + }, + "head": { + "rotation": { + "vector": [0, -20, 0] + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/fabric/src/main/resources/assets/bluelib/geo/dragon.geo.json b/fabric/src/main/resources/assets/bluelib/geo/dragon.geo.json new file mode 100644 index 00000000..8f038886 --- /dev/null +++ b/fabric/src/main/resources/assets/bluelib/geo/dragon.geo.json @@ -0,0 +1,93 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 64, + "texture_height": 64, + "visible_bounds_width": 4, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [0, 0.75, 0] + }, + "bones": [ + { + "name": "Body", + "pivot": [-0.16667, 5, -1], + "cubes": [ + {"origin": [-2, 4, 1], "size": [4, 2, 4], "uv": [17, 10]}, + {"origin": [-3, 4, -4], "size": [6, 2, 5], "uv": [0, 14]} + ] + }, + { + "name": "leftleg", + "parent": "Body", + "pivot": [1.5, 5, 5], + "cubes": [ + {"origin": [1.5, 3, 4.5], "size": [0, 4, 3], "pivot": [1.5, 5, 6], "rotation": [90, 0, 90], "uv": [0, 0]} + ] + }, + { + "name": "rightleg", + "parent": "Body", + "pivot": [-1.5, 5, 5], + "cubes": [ + {"origin": [-1.5, 3, 4.5], "size": [0, 4, 3], "pivot": [-1.5, 5, 6], "rotation": [90, 0, -90], "uv": [0, 0], "mirror": true} + ] + }, + { + "name": "rightwing", + "parent": "Body", + "pivot": [-2.5, 5, -3.5], + "cubes": [ + {"origin": [-10, 5, -5], "size": [7, 0, 7], "uv": [-7, 28], "mirror": true} + ] + }, + { + "name": "rightwing1", + "parent": "rightwing", + "pivot": [-9.5, 5, -1.5], + "cubes": [ + {"origin": [-17, 5, -5], "size": [7, 0, 7], "uv": [43, 0], "mirror": true} + ] + }, + { + "name": "leftwing", + "parent": "Body", + "pivot": [2.5, 5, -3.5], + "cubes": [ + {"origin": [3, 5, -5], "size": [7, 0, 7], "uv": [-7, 28]} + ] + }, + { + "name": "leftwing1", + "parent": "leftwing", + "pivot": [9.5, 5, -1.5], + "cubes": [ + {"origin": [10, 5, -5], "size": [7, 0, 7], "uv": [43, 0]} + ] + }, + { + "name": "neck", + "parent": "Body", + "pivot": [0, 5, -4], + "cubes": [ + {"origin": [-1, 4, -8], "size": [2, 2, 4], "uv": [10, 21]} + ] + }, + { + "name": "Head", + "parent": "neck", + "pivot": [0, 4.8, -7.5], + "cubes": [ + {"origin": [-1.5, 4, -12], "size": [3, 3, 4], "uv": [18, 17]}, + {"origin": [0, 6, -15], "size": [0, 3, 7], "uv": [0, 14]}, + {"origin": [-1, 4, -16], "size": [2, 2, 4], "uv": [21, 0]}, + {"origin": [-1, 3, -16], "size": [2, 1, 1], "uv": [29, 0]}, + {"origin": [0, 7, -8], "size": [0, 1, 3], "uv": [0, 23]} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/fabric/src/main/resources/assets/bluelib/geo/rex.geo.json b/fabric/src/main/resources/assets/bluelib/geo/rex.geo.json new file mode 100644 index 00000000..3d18bac7 --- /dev/null +++ b/fabric/src/main/resources/assets/bluelib/geo/rex.geo.json @@ -0,0 +1,390 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 512, + "texture_height": 512, + "visible_bounds_width": 29, + "visible_bounds_height": 7.5, + "visible_bounds_offset": [0, 3.25, 0] + }, + "bones": [ + { + "name": "Tyrannosaurus", + "pivot": [0, 0, 0] + }, + { + "name": "body", + "parent": "Tyrannosaurus", + "pivot": [0, 72, 0], + "cubes": [ + {"origin": [-19, 47, -8], "size": [38, 45, 34], "uv": [124, 51]}, + {"origin": [-15.475, 51.23327, -14.01496], "size": [31, 45, 35], "pivot": [0.025, 74.40827, 4.38504], "rotation": [-12.75, 0, 0], "uv": [130, 50]}, + {"origin": [-16, 40, -22.525], "size": [32, 16, 40], "inflate": -0.05, "pivot": [0, 72, 0.275], "rotation": [17.5, 0, 0], "uv": [0, 160]}, + {"origin": [-16, 54, -54], "size": [32, 37, 46], "uv": [1, 1]}, + {"origin": [-16, 71.46448, -54.53145], "size": [32, 30, 48], "inflate": -0.25, "pivot": [0, 89.46448, 3.46855], "rotation": [8.75, 0, 0], "uv": [-1, -1]}, + {"origin": [-16, 28.37894, -42.36923], "size": [32, 21, 49], "inflate": -0.025, "pivot": [0, 73.37894, 12.63077], "rotation": [-24, 0, 0], "uv": [0, 85]} + ] + }, + { + "name": "arm2", + "parent": "body", + "pivot": [13.56731, 58.46159, -45.9607], + "rotation": [29.07337, 19.05681, -20.20848], + "cubes": [ + {"origin": [12.56731, 47.46159, -47.9607], "size": [3, 11, 5], "uv": [111, 0]} + ] + }, + { + "name": "bone2", + "parent": "arm2", + "pivot": [15.06274, 49.29312, -45.32771], + "rotation": [-27.154, -2.96386, 4.54476], + "cubes": [ + {"origin": [13.13695, 39.306, -44.80271], "size": [2, 6, 2], "inflate": -0.075, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [0, 0]}, + {"origin": [14.86195, 37.306, -44.75271], "size": [0, 3, 2], "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [36, 26]}, + {"origin": [12.13695, 44.306, -47.52771], "size": [3, 5, 5], "inflate": -0.125, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [165, 257]} + ] + }, + { + "name": "bone3", + "parent": "bone2", + "pivot": [13.25685, 45.11756, -46.37771], + "rotation": [-14.50257, -2.95519, -2.10666], + "cubes": [ + {"origin": [13.13695, 41.306, -47.37771], "size": [2, 4, 2], "inflate": -0.075, "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [0, 28]}, + {"origin": [14.86195, 39.306, -47.37771], "size": [0, 3, 2], "pivot": [14.11195, 46.806, -45.02771], "rotation": [0, 0, 15], "uv": [36, 29]} + ] + }, + { + "name": "arm3", + "parent": "body", + "pivot": [-13.56731, 58.46159, -45.9607], + "rotation": [29.07337, -19.05681, 20.20848], + "cubes": [ + {"origin": [-15.56731, 47.46159, -47.9607], "size": [3, 11, 5], "uv": [111, 0], "mirror": true} + ] + }, + { + "name": "bone4", + "parent": "arm3", + "pivot": [-15.06274, 49.29312, -45.32771], + "rotation": [-27.154, 2.96386, -4.54476], + "cubes": [ + {"origin": [-15.13695, 39.306, -44.80271], "size": [2, 6, 2], "inflate": -0.075, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [0, 0], "mirror": true}, + {"origin": [-14.86195, 37.306, -44.75271], "size": [0, 3, 2], "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [36, 26], "mirror": true}, + {"origin": [-15.13695, 44.306, -47.52771], "size": [3, 5, 5], "inflate": -0.125, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [165, 257], "mirror": true} + ] + }, + { + "name": "bone5", + "parent": "bone4", + "pivot": [-13.25685, 45.11756, -46.37771], + "rotation": [-14.50257, 2.95519, 2.10666], + "cubes": [ + {"origin": [-15.13695, 41.306, -47.37771], "size": [2, 4, 2], "inflate": -0.075, "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [0, 28], "mirror": true}, + {"origin": [-14.86195, 39.306, -47.37771], "size": [0, 3, 2], "pivot": [-14.11195, 46.806, -45.02771], "rotation": [0, 0, -15], "uv": [36, 29], "mirror": true} + ] + }, + { + "name": "tail1", + "parent": "body", + "pivot": [0, 82.97049, 21.3522], + "cubes": [ + {"origin": [-15, 55.74549, 21.0272], "size": [30, 30, 39], "uv": [123, 128]}, + {"origin": [-15, 71.63781, 17.37365], "size": [30, 28, 35], "inflate": -0.2, "pivot": [0, 60.21281, -16.55135], "rotation": [-10.75, 0, 0], "uv": [127, 132]}, + {"origin": [-15, 39.02049, 26.7772], "size": [30, 13, 37], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [16, 0, 0], "uv": [159, 1]} + ] + }, + { + "name": "tail2", + "parent": "tail1", + "pivot": [0, 82.97049, 56.3522], + "cubes": [ + {"origin": [-10, 62.97049, 56.3522], "size": [20, 21, 38], "uv": [106, 199]}, + {"origin": [-9, 41.02049, 63.3522], "size": [18, 14, 35], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [13, 0, 0], "uv": [173, 3]} + ] + }, + { + "name": "tail3", + "parent": "tail2", + "pivot": [0, 82.97049, 93.3522], + "cubes": [ + {"origin": [-7, 66.97049, 93.3522], "size": [14, 14, 37], "uv": [0, 216]}, + {"origin": [-7, 54.52049, 94.3522], "size": [14, 7, 38], "inflate": -0.025, "pivot": [0, 30.97049, 1.3522], "rotation": [5.5, 0, 0], "uv": [174, 0]} + ] + }, + { + "name": "tail4", + "parent": "tail3", + "pivot": [0, 82.97049, 129.3522], + "cubes": [ + {"origin": [-5, 69.97049, 129.3522], "size": [10, 9, 37], "uv": [255, 14]}, + {"origin": [-5, 64.82049, 132.6022], "size": [10, 4, 37], "inflate": -0.025, "pivot": [0, 30.97049, 109.3522], "rotation": [4.75, 0, 0], "uv": [255, 14]} + ] + }, + { + "name": "tail5", + "parent": "tail4", + "pivot": [0, 82.97049, 158.3522], + "cubes": [ + {"origin": [-3, 70.97049, 158.3522], "size": [6, 6, 37], "uv": [149, 257]}, + {"origin": [-3, 69.22961, 165.59014], "size": [6, 3, 30], "inflate": -0.1, "pivot": [0, 70.15461, 147.99014], "rotation": [0.5, 0, 0], "uv": [266, 21]} + ] + }, + { + "name": "tail6", + "parent": "tail5", + "pivot": [0, 82.97049, 182.3522], + "cubes": [ + {"origin": [-2, 71.97049, 182.3522], "size": [4, 4, 37], "uv": [0, 285]}, + {"origin": [-2, 66.99549, 197.7022], "size": [4, 4, 25], "inflate": -0.175, "pivot": [0, 30.97049, 162.3522], "rotation": [4.75, 0, 0], "uv": [12, 297]} + ] + }, + { + "name": "neck", + "parent": "body", + "pivot": [0, 74.22605, -48.50511], + "cubes": [ + {"origin": [-15, 55, -67], "size": [30, 31, 17], "uv": [251, 113]}, + {"origin": [-14.25, 80.39311, -64.98257], "size": [30, 11, 17], "inflate": -1, "pivot": [0.75, 82.39311, -53.98257], "rotation": [24.25, 0, 0], "uv": [251, 113]}, + {"origin": [-10, 66.05, -70.125], "size": [20, 34, 25], "inflate": -0.225, "pivot": [0, 87.575, -69.125], "rotation": [-39.25, 0, 0], "uv": [221, 200]}, + {"origin": [-10, 59.575, -78.125], "size": [20, 13, 25], "inflate": -1.325, "pivot": [0, 87.575, -69.125], "rotation": [-14.25, 0, 0], "uv": [235, 259]}, + {"origin": [-9, 71.2, -85.125], "size": [18, 19, 24], "inflate": -0.325, "pivot": [0, 85.2, -69.125], "rotation": [7.5, 0, 0], "uv": [268, 61]}, + {"origin": [-8, 83.89159, -88.09601], "size": [16, 12, 13], "inflate": -0.275, "pivot": [0, 89.89159, -79.09601], "rotation": [42.5, 0, 0], "uv": [198, 259]}, + {"origin": [-8, 86.39159, -80.39601], "size": [16, 11, 19], "inflate": -0.25, "pivot": [0, 89.89159, -68.09601], "rotation": [2.5, 0, 0], "uv": [111, 0]} + ] + }, + { + "name": "head", + "parent": "neck", + "pivot": [0, 83.05369, -83.57238], + "cubes": [ + {"origin": [-8.725, 71, -101], "size": [17, 19, 19], "uv": [286, 165]}, + {"origin": [-8.775, 84, -101], "size": [17, 2, 7], "inflate": 0.225, "uv": [104, 155]}, + {"origin": [-7, 93.5819, -99.5906], "size": [14, 5, 10], "inflate": -0.05, "pivot": [0, 90.5819, -77.5906], "rotation": [21.5, 0, 0], "uv": [0, 111]}, + {"origin": [-7, 81.46532, -93.49693], "size": [14, 5, 9], "inflate": -0.075, "pivot": [0, 78.46532, -74.49693], "rotation": [-25, 0, 0], "uv": [111, 30]}, + {"origin": [-7, 88.64032, -92.02193], "size": [14, 5, 4], "inflate": -0.125, "uv": [0, 191]}, + {"origin": [9, 86, -102], "size": [4, 3, 13], "inflate": -0.025, "pivot": [7, 80.5, -90.5], "rotation": [0, 0, -17.5], "uv": [149, 277]}, + {"origin": [4.59053, 84.6097, -93.1055], "size": [4, 3, 9], "inflate": -0.05, "pivot": [2.59053, 79.1097, -81.6055], "rotation": [0, -27.5, -17.5], "uv": [255, 23]}, + {"origin": [-8.59053, 84.6097, -93.1055], "size": [4, 3, 9], "inflate": -0.05, "pivot": [-2.59053, 79.1097, -81.6055], "rotation": [0, 27.5, 17.5], "uv": [184, 225]}, + {"origin": [12.62776, 90.52364, -107.52067], "size": [4, 3, 11], "inflate": -0.1, "pivot": [10.62776, 85.02364, -91.02067], "rotation": [27.87149, 36.42355, -5.95346], "uv": [0, 239]}, + {"origin": [-16.62776, 90.52364, -107.52067], "size": [4, 3, 11], "inflate": -0.1, "pivot": [-10.62776, 85.02364, -91.02067], "rotation": [27.87149, -36.42355, 5.95346], "uv": [162, 0]}, + {"origin": [-13, 86, -102], "size": [4, 3, 13], "inflate": -0.025, "pivot": [-7, 80.5, -90.5], "rotation": [0, 0, 17.5], "uv": [109, 216]}, + {"origin": [-7, 78.725, -121], "size": [14, 10, 16], "inflate": -0.05, "pivot": [0, 81.725, -99], "rotation": [27.5, 0, 0], "uv": [300, 243]}, + {"origin": [-7, 78.35, -106], "size": [14, 11, 11], "pivot": [0, 81.35, -99], "rotation": [33.5, 0, 0], "uv": [286, 203]}, + {"origin": [-7, 69.519, -125.21974], "size": [14, 11, 7.85], "inflate": -0.075, "pivot": [0, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [259, 165]}, + {"origin": [-6, 78.519, -128.21974], "size": [11, 0, 7.85], "pivot": [0, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [141, 30]}, + {"origin": [5, 61.519, -128.21974], "size": [0, 17, 6.85], "pivot": [-2, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [234, 45]}, + {"origin": [-5, 61.519, -128.21974], "size": [0, 17, 6.85], "pivot": [2, 72.519, -118.21974], "rotation": [90, 0, 0], "uv": [28, 154]}, + {"origin": [-7, 73.394, -115.21974], "size": [14, 10, 6.85], "inflate": -0.1, "pivot": [0, 74.394, -109.21974], "rotation": [110.5, 0, 0], "uv": [65, 237]}, + {"origin": [-7, 84.31148, -108.92962], "size": [14, 4, 6.85], "inflate": -0.15, "pivot": [0, 79.31148, -102.92962], "rotation": [128, 0, 0], "uv": [272, 0]}, + {"origin": [-7, 74.31148, -110.92962], "size": [14, 9, 8.85], "inflate": -0.175, "pivot": [0, 79.31148, -102.92962], "rotation": [88, 0, 0], "uv": [0, 28]}, + {"origin": [-7, 69.019, -122.66974], "size": [14, 10, 7], "inflate": -0.125, "pivot": [0, 72.019, -117.66974], "rotation": [47.5, 0, 0], "uv": [0, 267]} + ] + }, + { + "name": "jaw", + "parent": "head", + "pivot": [0, 73.374, -85.20224], + "cubes": [ + {"origin": [-9.125, 61.47673, -99.81697], "size": [18, 13, 12], "inflate": 0.025, "uv": [184, 200]}, + {"origin": [-9.15, 64.14383, -89.12484], "size": [18, 12, 7], "inflate": 0.075, "pivot": [-3, 73.14383, -68.12484], "rotation": [7.5, 0, 0], "uv": [312, 0]}, + {"origin": [7.8, 70.81044, -97.91351], "size": [1, 6, 9], "uv": [104, 179]}, + {"origin": [7.85, 63.60089, -93.15375], "size": [1, 6, 7], "pivot": [-2.975, 63.60089, -72.15375], "rotation": [-22.5, 0, 0], "uv": [65, 216]}, + {"origin": [-7.125, 72.47673, -98.81697], "size": [14, 14, 16], "inflate": 0.025, "uv": [219, 297]}, + {"origin": [6.375, 68.47673, -105.81697], "size": [0, 18, 14], "uv": [0, 159]}, + {"origin": [-6.625, 68.47673, -105.81697], "size": [0, 18, 14], "uv": [0, 141]}, + {"origin": [7.875, 65.38327, -112.3007], "size": [1, 8, 15], "inflate": -0.05, "pivot": [0, 73.88327, -104.8007], "rotation": [27.5, 0, 0], "uv": [255, 0]}, + {"origin": [-9.125, 65.38327, -112.3007], "size": [1, 8, 15], "inflate": -0.05, "pivot": [0, 73.88327, -104.8007], "rotation": [27.5, 0, 0], "uv": [0, 216]}, + {"origin": [-9.05, 70.81044, -97.91351], "size": [1, 6, 9], "uv": [104, 164]}, + {"origin": [-9.1, 63.60089, -93.15375], "size": [1, 6, 7], "pivot": [2.975, 63.60089, -72.15375], "rotation": [-22.5, 0, 0], "uv": [17, 216]}, + {"origin": [-9.125, 64.31864, -111.04094], "size": [18, 8, 15], "inflate": -0.025, "pivot": [0, 70.56864, -103.54094], "rotation": [17.5, 0, 0], "uv": [149, 300]}, + {"origin": [-6.125, 66.9078, -126.60427], "size": [12, 5, 15], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [126, 257]}, + {"origin": [-6.125, 71.5078, -125.60427], "size": [12, 5, 0], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [62, 155]}, + {"origin": [5.725, 71.5078, -125.60427], "size": [0, 5, 17], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [28, 138]}, + {"origin": [-5.975, 71.5078, -125.60427], "size": [0, 5, 17], "pivot": [0, 72.4078, -104.10427], "rotation": [15, 0, 0], "uv": [0, 109]}, + {"origin": [-6.125, 60.70962, -124.43479], "size": [12, 5, 15], "inflate": -0.05, "pivot": [0, 63.78462, -115.43479], "rotation": [-3.5, 0, 0], "uv": [234, 61]}, + {"origin": [-7.125, 61.71743, -111.29498], "size": [14, 5, 16], "inflate": -0.025, "pivot": [0, 66.69243, -101.79498], "rotation": [9.25, 0, 0], "uv": [65, 216]} + ] + }, + { + "name": "leg_left", + "parent": "Tyrannosaurus", + "pivot": [20.42923, 70.7324, 8.85434], + "rotation": [-15.09173, -1.85092, -0.08398], + "cubes": [ + {"origin": [12.54366, 41.02086, -4.25109], "size": [12.875, 42.825, 23.725], "uv": [79, 257]} + ] + }, + { + "name": "leg_left2", + "parent": "leg_left", + "pivot": [21.99279, 43.52539, 1.69711], + "cubes": [ + {"origin": [12.844, 24.19389, 3.09297], "size": [12.4, 20.375, 15.95], "pivot": [21.944, 35.38139, 0.96797], "rotation": [34, 0, 0], "uv": [279, 297]} + ] + }, + { + "name": "leg_left3", + "parent": "leg_left2", + "pivot": [19.76532, 33.92692, 13.90262], + "rotation": [55, 0, 0], + "cubes": [ + {"origin": [14.22989, 14.97535, 9.92239], "size": [10, 19, 9], "inflate": -0.1, "uv": [0, 0]} + ] + }, + { + "name": "leg_left4", + "parent": "leg_left3", + "pivot": [19.76532, 14.92692, 13.90262], + "rotation": [-60, 0, 0], + "cubes": [ + {"origin": [14.22989, 2.41759, 7.14887], "size": [10, 17, 9], "inflate": 0.375, "uv": [0, 85]} + ] + }, + { + "name": "Claw5", + "parent": "leg_left4", + "pivot": [18.03922, 11.69239, 7.72125], + "rotation": [3.25353, -39.92899, -4.10228], + "cubes": [ + {"origin": [19.68942, 7.60244, 18.32118], "size": [2, 5, 6], "inflate": -0.2, "pivot": [20.68942, 10.90244, 16.32118], "rotation": [4, 5, 0], "uv": [19, 239]}, + {"origin": [15.96316, 8.07744, 15.28926], "size": [2, 3, 4], "inflate": 0.5, "pivot": [20.4918, 5.40696, 3.40745], "rotation": [2.31336, 4.43385, 27.58957], "uv": [29, 0]} + ] + }, + { + "name": "leg_left5", + "parent": "leg_left4", + "pivot": [19.76532, 2.72669, 9.58045], + "rotation": [32.5, 0, 0], + "cubes": [ + {"origin": [14.22989, -4.78265, 7.2517], "size": [10, 8, 8], "inflate": 0.35, "uv": [42, 267]} + ] + }, + { + "name": "Claw3", + "parent": "leg_left5", + "pivot": [14.03922, -1.93376, 9.83799], + "rotation": [-11.28559, 36.03256, -29.0792], + "cubes": [ + {"origin": [15.68942, -5.02371, -6.76194], "size": [2, 4, 9], "inflate": -0.2, "pivot": [16.68942, -2.72371, 1.23806], "rotation": [-4, -5, 0], "uv": [78, 267]}, + {"origin": [11.96316, -5.54871, -1.73002], "size": [2, 3, 12], "inflate": 0.5, "pivot": [16.4918, -8.21919, 14.15179], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [45, 298]}, + {"origin": [13.86316, -1.04871, -0.45502], "size": [2, 3, 12], "inflate": 0.4, "pivot": [18.3918, -3.71919, 15.42679], "rotation": [14.70847, -5.40113, 27.33492], "uv": [263, 297]} + ] + }, + { + "name": "Claw2", + "parent": "leg_left5", + "pivot": [18.00128, -1.52657, 8.77203], + "rotation": [6.46283, 10.46681, -26.49382], + "cubes": [ + {"origin": [19.65148, -4.61652, -7.8279], "size": [2, 4, 9], "inflate": -0.2, "pivot": [20.65148, -2.31652, 0.1721], "rotation": [-8.25367, -3.37646, 28.00254], "uv": [259, 183]}, + {"origin": [15.92522, -5.14152, -2.79598], "size": [2, 3, 12], "inflate": 0.5, "pivot": [20.45386, -7.812, 13.08583], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [0, 284]}, + {"origin": [17.82522, -0.64152, -1.52098], "size": [2, 3, 12], "inflate": 0.4, "pivot": [22.35386, -3.312, 14.36083], "rotation": [14.70847, -5.40113, 27.33492], "uv": [45, 283]} + ] + }, + { + "name": "Claw4", + "parent": "leg_left5", + "pivot": [25.00339, -1.78444, 9.60342], + "rotation": [-6.62428, -31.83686, 25.40349], + "cubes": [ + {"origin": [21.35319, -4.87439, -6.99651], "size": [2, 4, 9], "inflate": -0.2, "pivot": [22.35319, -2.57439, 1.00349], "rotation": [-4, 5, 0], "uv": [172, 21]}, + {"origin": [25.07945, -5.39939, -1.96459], "size": [2, 3, 12], "inflate": 0.5, "pivot": [22.55081, -8.06987, 13.91722], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [222, 145]}, + {"origin": [23.17945, -0.89939, -0.68959], "size": [2, 3, 12], "inflate": 0.4, "pivot": [20.65081, -3.56987, 15.19222], "rotation": [14.70847, 5.40113, -27.33492], "uv": [222, 130]} + ] + }, + { + "name": "leg_right", + "parent": "Tyrannosaurus", + "pivot": [-20.42923, 70.7324, 8.85434], + "rotation": [-15.09173, 1.85092, 0.08398], + "cubes": [ + {"origin": [-25.41866, 41.02086, -4.25109], "size": [12.875, 42.825, 23.725], "uv": [79, 257], "mirror": true} + ] + }, + { + "name": "leg_right2", + "parent": "leg_right", + "pivot": [-21.99279, 43.52539, 1.69711], + "cubes": [ + {"origin": [-25.244, 24.19389, 3.09297], "size": [12.4, 20.375, 15.95], "pivot": [-21.944, 35.38139, 0.96797], "rotation": [34, 0, 0], "uv": [279, 297], "mirror": true} + ] + }, + { + "name": "leg_right3", + "parent": "leg_right2", + "pivot": [-19.76532, 33.92692, 13.90262], + "rotation": [55, 0, 0], + "cubes": [ + {"origin": [-24.22989, 14.97535, 9.92239], "size": [10, 19, 9], "inflate": -0.1, "uv": [0, 0], "mirror": true} + ] + }, + { + "name": "leg_right4", + "parent": "leg_right3", + "pivot": [-19.76532, 14.92692, 13.90262], + "rotation": [-60, 0, 0], + "cubes": [ + {"origin": [-24.22989, 2.41759, 7.14887], "size": [10, 17, 9], "inflate": 0.375, "uv": [0, 85], "mirror": true} + ] + }, + { + "name": "Claw6", + "parent": "leg_right4", + "pivot": [-18.03922, 11.69239, 7.72125], + "rotation": [3.25353, 39.92899, 4.10228], + "cubes": [ + {"origin": [-21.68942, 7.60244, 18.32118], "size": [2, 5, 6], "inflate": -0.2, "pivot": [-20.68942, 10.90244, 16.32118], "rotation": [4, -5, 0], "uv": [19, 239], "mirror": true}, + {"origin": [-17.96316, 8.07744, 15.28926], "size": [2, 3, 4], "inflate": 0.5, "pivot": [-20.4918, 5.40696, 3.40745], "rotation": [2.31336, -4.43385, -27.58957], "uv": [29, 0], "mirror": true} + ] + }, + { + "name": "leg_right5", + "parent": "leg_right4", + "pivot": [-19.76532, 2.72669, 9.58045], + "rotation": [32.5, 0, 0], + "cubes": [ + {"origin": [-24.22989, -4.78265, 7.2517], "size": [10, 8, 8], "inflate": 0.35, "uv": [42, 267], "mirror": true} + ] + }, + { + "name": "Claw7", + "parent": "leg_right5", + "pivot": [-14.03922, -1.93376, 9.83799], + "rotation": [-11.28559, -36.03256, 29.0792], + "cubes": [ + {"origin": [-17.68942, -5.02371, -6.76194], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-16.68942, -2.72371, 1.23806], "rotation": [-4, 5, 0], "uv": [78, 267], "mirror": true}, + {"origin": [-13.96316, -5.54871, -1.73002], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-16.4918, -8.21919, 14.15179], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [45, 298], "mirror": true}, + {"origin": [-15.86316, -1.04871, -0.45502], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-18.3918, -3.71919, 15.42679], "rotation": [14.70847, 5.40113, -27.33492], "uv": [263, 297], "mirror": true} + ] + }, + { + "name": "Claw8", + "parent": "leg_right5", + "pivot": [-18.00128, -1.52657, 8.77203], + "rotation": [6.46283, -10.46681, 26.49382], + "cubes": [ + {"origin": [-21.65148, -4.61652, -7.8279], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-20.65148, -2.31652, 0.1721], "rotation": [-8.25367, 3.37646, -28.00254], "uv": [259, 183], "mirror": true}, + {"origin": [-17.92522, -5.14152, -2.79598], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-20.45386, -7.812, 13.08583], "rotation": [-2.31336, 4.43385, -27.58957], "uv": [0, 284], "mirror": true}, + {"origin": [-19.82522, -0.64152, -1.52098], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-22.35386, -3.312, 14.36083], "rotation": [14.70847, 5.40113, -27.33492], "uv": [45, 283], "mirror": true} + ] + }, + { + "name": "Claw9", + "parent": "leg_right5", + "pivot": [-25.00339, -1.78444, 9.60342], + "rotation": [-6.62428, 31.83686, -25.40349], + "cubes": [ + {"origin": [-23.35319, -4.87439, -6.99651], "size": [2, 4, 9], "inflate": -0.2, "pivot": [-22.35319, -2.57439, 1.00349], "rotation": [-4, -5, 0], "uv": [172, 21], "mirror": true}, + {"origin": [-27.07945, -5.39939, -1.96459], "size": [2, 3, 12], "inflate": 0.5, "pivot": [-22.55081, -8.06987, 13.91722], "rotation": [-2.31336, -4.43385, 27.58957], "uv": [222, 145], "mirror": true}, + {"origin": [-25.17945, -0.89939, -0.68959], "size": [2, 3, 12], "inflate": 0.4, "pivot": [-20.65081, -3.56987, 15.19222], "rotation": [14.70847, -5.40113, 27.33492], "uv": [222, 130], "mirror": true} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/fabric/src/main/resources/assets/bluelib/lang/en_us.json b/fabric/src/main/resources/assets/bluelib/lang/en_us.json new file mode 100644 index 00000000..8371c823 --- /dev/null +++ b/fabric/src/main/resources/assets/bluelib/lang/en_us.json @@ -0,0 +1,4 @@ +{ + "entity.bluelib.example_one": "Example", + "entity.bluelib.example_two": "Example" +} \ No newline at end of file diff --git a/fabric/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png b/fabric/src/main/resources/assets/bluelib/textures/entity/dragon/blue.png new file mode 100644 index 0000000000000000000000000000000000000000..83be2147b8db3aaab415e12dc3b6e9a11a594ea4 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!7Pn|)P)=iz4q{MmaJHmZ`5KTT zT@vIM%(v z(aRpoCoWyiTgojaD&F|F!PdZVM@UbNjptVBj4jLF?f%O$LFQ-3hJ{yuCnpH{RqTF0 zeUaRrN`{moTZcM{69EVLnQmQO%s%OtOoW(UeeqPr*})2&$=17>Km8Ke@%eU3;;UAl z_dE-lA2QvTo9bV8@y{Lo#EEr$XX6_ew|<>1!7nqtJ8%c@3EiH9*VZm)@~qx!CojNR zaWk9uaEODlE8kU9hhhtcCz6N4bsR43<#29rQagW3>HO}AsXY7mmmhHEtgR04`g-ue zwv#SzoSD}|v`Lv6asM;6d&}sM&)V{9@7_H|f67<|ydtWYcW8+%(7BtgsyBPB&W+HL z{c<<=%Uw8|weJPP@nd2)_peY@i7iud+B+%Zp5z_{-H+UVy3Ca989GZ6MLiBbQ|UWb z(Y^fs4MF?eSt1usd41cW*!(Qw)s%f3B9+u@XC5>Aq_Xz;j^mF{Oz1waD#L%1(lgZ; z3|#E;@8(@%^IqToRn(#6{C~ELFSiAJm_Id{T)EuXZp3k!(UWyjbJC~xst$5b_e=bf q?_)BNT$9h7r)_M&3`GSo`xu+NS2^bO6ubn+JAk44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!&W-dj)XETq4p!hyw%*PB>6gHc&$n9=U$y$Y z=ULGFkm<(URR6k*f9~ifPORfQ8{fFN_3La2ewpdrfjf9l==L1Ewstv_XZ2P)c>&If zo7udFLmZS{`L3Ee6k9MnkvtTx<8Wy&hjW9I+WA{b=XXy`<=Mx-{D3oOZFPXx*MkqX zopgEQ%)BO|P0GxO`=7DhTSkX`)|Ov;_wF(JQ^qRb6;Z{!LrZLd&fRoXz1eGZZiJTX zm%F)N?!wuueJ>b}9}~N|e}$?_Y?+eN-boqvB=;!je&qhsWu|1$&{>iw>T&p)O5eGP z?&bGy2-@$?61i~7>)RH^=4TPFrtI4gsia;z^O)Hum9@`z9DjUbLid4H8UCA;o~gcI z;9{45H}4Xg_xk>?q7EhJ|FdO$xh>$s{He+0%H_s(BaX|Ao~)CalRmvyb&z|yU*ey9 qACrmXntbLwZDRvwC@P5A$Jpe($}z8};3Y8L89ZJ6T-G@yGywpxb1(q_ literal 0 HcmV?d00001 diff --git a/fabric/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png b/fabric/src/main/resources/assets/bluelib/textures/entity/dragon/dark.png new file mode 100644 index 0000000000000000000000000000000000000000..56c9452f64ef0b1e71cecef3b4d07f56ae847633 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!mKPJ^=Hz5!W#wdNPn^2p^s67*vJwUgQb~?#2X}7uGm#gP zQ06^oDwgx$fq}uR<%$^@8TFMVidv2~UU@d+Y|c^~DgvxPb0$Wc7}!LuS~IT`$dN7y z@(X78j}sipEHVW;@~EeaV@SoEw^wiHEjAEfdvHHFiDPf3^4f2I61s;NV<1;Z1`L*Y6Om-ccvH#n)Czom43_rz45ef-N0ICIuk2Y7uw_+Z;f zmp9JLYa-gD%#67I8QZ;ObjW9I`L%cN9-}{HtO8yURm?lI#1`n>O;^>My;kQ&Xvu!L zoBQQ1oXy(zg5mfvv77r>sH()4DLL((lyOgTkAm(;?mt~-O7;w$C5fUQho7nRovY|x ze*cD`{q8K03#YukZBcA~7V&Dzz73H|>a{bEnSD}O`+Udo$0sIqA6S*)ze(wt>I()g zcKLVnF0py9@Bb?5P;&l1TgI2$0zS;2noO=-ZfrN=xXkFuI;lD7(|c71xu^Rj{>k?- onMkh5XU@|$HeiOLf|z}bP2Q^<^Lh$i0^^;*)78&qol`;+0O_S2&j0`b literal 0 HcmV?d00001 diff --git a/fabric/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png b/fabric/src/main/resources/assets/bluelib/textures/entity/dragon/pink.png new file mode 100644 index 0000000000000000000000000000000000000000..adbd4aba3aedfc3c346c7fcbcd858cbe4dd261e6 GIT binary patch literal 676 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@I14-?iy0WW zg+Z8+Vb&Z8pkQEtPlzj!Zjwt65OA~RHu2!IKd|xH`;UJotCY^rs5}_f`{vw>EiO$N z3LOzw<`r~)`(`)e=Yh7PEk`d-JKbu&a%s|urSjIR6`Z;x41ng`DxW(eV9(;TfP5fF zx+KUinBhN8a3r(H6zIsKo-U3d6?5KRy`8t%K!EMR{p2K$y_w2uzx|D07t}vHbT_ZS zqnACFPh7g3x0G8Pb3e8>o{E6%i-MMq;~$6()ryJQ+f9BFF)YSSz8_8_4VL` zZ6{scI5V$_Xp=HC;{IoB_m!M8-n(`vqUbO^7^(#vH4lVt10_7L@KG*&OB!JNoDQx9mgM^n9zM-Rfhj2rDv)y z7`WKw-_5(k=DoiEtEfZC`TuMgUv3NdFn?+?xpKL&-H78dqbKX6=A=*WRUPD>?w9x{ q-^XMkxh9`EPutjl8Hx&G_AxejuX4=mDR>EtcLq;aKbLh*2~7ZCIW7SJ literal 0 HcmV?d00001 diff --git a/fabric/src/main/resources/assets/bluelib/textures/entity/rex/brown.png b/fabric/src/main/resources/assets/bluelib/textures/entity/rex/brown.png new file mode 100644 index 0000000000000000000000000000000000000000..f2956d0504901ccd33fb2067b7631ba08471c5ce GIT binary patch literal 3454 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 or57IkfgP>p|9}4H3?K* zd$|Vy0Lxt%z&JT@wO!)n0A&PtxcTWHMQ;CCUK+VbR@PgIE_Q-#4VZ+o>m>4&1Ni!+e7d%l_n? zxZ~ZcB#F9yLg{*Zse~b2F@UYst7MK&{iUQ_aG5EvBgvGNXSSOn&)a!Pwl4YxCIRZr zrAF;ib-vH8++2$fyhbC(n*6E`H_m9e5j)dx#4vTTIM(N7SJ&DT!#AwbRgg-JQwN5Q zx5emxTfD z<_{FgIf}z3c0d4#tD#w9mk5BOP9zjaEKzEgPdNzdq+Fv8RiifJ6`& zvx`(knW5m^Q7YzIDsK%yoEEKP*to+aayaWS%U7eh^5KPKEi0l+qpb>Sj3-;5;D+Kv zHlYL-i|VI}v!0##+8Tmz3N3|4)Zp-ePN_qE;D;FvD1ULzXKSxNHqSj&!)yt!U%(h8{>l>X*3G z4Q~FW@*G8)!++>u?i3VOvVR^=a}as+}U{ny5{`LCt;Y zkO{jf(STt?eR~A|C|L*A`=Jo@0c(8qWjZ!ts%wf4*qe=-BnD9I5Y1D}^z#BBF%pE) zl>}R84GSTDkh!q8L5V|p^W~sxAbO7}5@Gd2@dack6VEW$o1FSADwp;WBA#Fqs{UVX zGZnHihI?Q>wI2@j+hNz8O|0QYC41S$o%0jx; z@W29W8|&NuB)_Qaq9M|4Cg#m1olT!j+qyepp4OlgNrC8VrMEU={pUVObBMHjgc1wK zsq{7j52I5RW`nJ7;`ubl1cmNWI+;L9FSj+VU+T^N)LJM6Wp)lVs1y}8XHa_g~ z&Nvc@>7Bm1^WT@q#QUH2gpsl8jp!=!4$+J{6e2PuRC{AZAFtJoti}vQQz9%93)Jv@ zyFFLtJ?~V7jRsa)!wh|m--{awAi{odkjHLIAH4c(g@i>XrbqcZ2>P$-ncZB%-wva( zD?5>%sFYVXnp|OD@5wc&2RgL@X^*t^l|mto*0ZWOJ8mRKs-j|<=sELnkVIrOmN-@@ zLrD-VE0y(+ioeT_yL5E1rnaO3PxCqFpB1&`%C2%X+L$T~1m&1 Date: Wed, 9 Oct 2024 02:01:57 +0200 Subject: [PATCH 53/62] Check Previous Commit --- Forge/build.gradle | 5 +- .../main/java/software/bluelib/BlueLib.java | 46 +++++++++++++++++-- .../main/java/software/bluelib/BlueLib.java | 10 ++++ gradle.properties | 8 ++-- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/Forge/build.gradle b/Forge/build.gradle index f2919988..b9e5dee6 100644 --- a/Forge/build.gradle +++ b/Forge/build.gradle @@ -4,7 +4,7 @@ plugins { id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' } base { - archivesName = "${mod_name}-forge-${minecraft_version}-${version}" + archivesName = "${mod_name}-forge-${minecraft_version}" } mixin { config("${mod_id}.mixins.json") @@ -70,6 +70,9 @@ dependencies { minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT:processor") + compileOnly("curse.maven:geckolib-388172:5605712") + runtimeOnly("curse.maven:geckolib-388172:5605712") + // Forge's hack fix implementation('net.sf.jopt-simple:jopt-simple:5.0.4') { version { strictly '5.0.4' } } } diff --git a/Forge/src/main/java/software/bluelib/BlueLib.java b/Forge/src/main/java/software/bluelib/BlueLib.java index 4f8fc622..4ee00b8e 100644 --- a/Forge/src/main/java/software/bluelib/BlueLib.java +++ b/Forge/src/main/java/software/bluelib/BlueLib.java @@ -2,11 +2,18 @@ package software.bluelib; +import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import software.bluelib.example.event.ReloadHandler; +import software.bluelib.example.init.ModEntities; +import software.bluelib.example.proxy.ClientProxy; +import software.bluelib.example.proxy.CommonProxy; /** * The main class of the {@link BlueLib} mod. @@ -28,19 +35,50 @@ @Mod(BlueLibConstants.MOD_ID) public class BlueLib { + /** + * A {@code public static} {@link CommonProxy} instance that handles the mod's initialization and event handling. + */ + public static CommonProxy PROXY = DistExecutor.safeRunForDist(() -> ClientProxy::new, () -> CommonProxy::new); + /** * Constructs a new {@link BlueLib} instance and registers the mod event bus. - *

          - * This constructor sets up the mod's event handling by registering the current instance - * with the Forge mod event bus. - *

          * * @author MeAlam + * @Co-author Dan * @since 1.0.0 */ public BlueLib() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); modEventBus.register(this); + + if (BlueLibCommon.isDeveloperMode() && BlueLibCommon.PLATFORM.isModLoaded("geckolib") && BlueLibConstants.isExampleEnabled) { + ModEntities.register(modEventBus); + MinecraftForge.EVENT_BUS.register(ReloadHandler.class); + modEventBus.addListener(this::setupComplete); + modEventBus.addListener(this::setupClient); + } + } + + /** + * A {@code private void} that handles the {@link FMLClientSetupEvent}.
          + * Once the client setup process is complete, this method calls {@link ClientProxy#clientInit()} to perform additional client-side initialization. + * + * @param pEvent {@link FMLClientSetupEvent} - The event fired after the client setup process completes. + */ + private void setupClient(final FMLClientSetupEvent pEvent) { + pEvent.enqueueWork(() -> { + PROXY.clientInit(); + }); + } + + /** + * A {@code private void} that handles the {@link FMLLoadCompleteEvent}.
          + * Once the mod loading process is complete, this method calls {@link CommonProxy#postInit()} to perform additional initialization. + * + * @param pEvent {@link FMLLoadCompleteEvent} - The event fired after the mod loading process completes. + */ + private void setupComplete(final FMLLoadCompleteEvent pEvent) { + PROXY.postInit(); } /** diff --git a/NeoForge/src/main/java/software/bluelib/BlueLib.java b/NeoForge/src/main/java/software/bluelib/BlueLib.java index d2d0dc21..a294bf24 100644 --- a/NeoForge/src/main/java/software/bluelib/BlueLib.java +++ b/NeoForge/src/main/java/software/bluelib/BlueLib.java @@ -7,7 +7,10 @@ import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLLoadCompleteEvent; +import net.neoforged.fml.loading.FMLEnvironment; import org.spongepowered.asm.launch.MixinBootstrap; +import software.bluelib.example.event.ClientEvents; +import software.bluelib.example.init.ModEntities; /** * The main class of the {@code BlueLib} mod. @@ -44,6 +47,13 @@ public class BlueLib { public BlueLib(IEventBus pModEventBus, ModContainer pModContainer) { pModEventBus.register(this); MixinBootstrap.init(); + if (BlueLibCommon.isDeveloperMode() && BlueLibCommon.PLATFORM.isModLoaded("geckolib") && BlueLibConstants.isExampleEnabled) { + ModEntities.REGISTRY.register(pModEventBus); + if (FMLEnvironment.dist.isClient()) { + pModEventBus.addListener(ClientEvents::registerAttributes); + pModEventBus.addListener(ClientEvents::registerRenderers); + } + } } /** diff --git a/gradle.properties b/gradle.properties index dd4fe5db..64d4bab2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,7 +16,7 @@ mod_author=Dan, Aram description=BlueLib is an All round Minecraft mod library that offers data-driven features, allowing users to implement and customize its features with full freedom. \nIt supports both Resource and Datapacks, ensuring seamless integration and flexibility. credits= -minecraft_version_range=[1.21, 1.22) +minecraft_version_range=[1.21, 1.22] ## This is the version of minecraft that the 'common' project uses, you can find a list of all versions here ## https://projects.neoforged.net/neoforged/neoform @@ -26,11 +26,11 @@ parchment_minecraft=1.21 parchment_version=2024.06.23 # Fabric -fabric_version=0.100.1+1.21 -fabric_loader_version=0.15.11 +fabric_version=0.102.0+1.21 +fabric_loader_version=0.16.5 # Forge -forge_version=51.0.17 +forge_version=51.0.33 forge_version_range=[51,) forge_loader_version_range=[0,) From cc5cc253b9dd91595f11593204cd65af273ab759 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 9 Oct 2024 13:17:41 +0200 Subject: [PATCH 54/62] Moved some Constants --- .../software/bluelib/BlueLibConstants.java | 16 ++++++++- .../bluelib/utils/logging/BaseLogger.java | 35 ++++++------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/common/src/main/java/software/bluelib/BlueLibConstants.java b/common/src/main/java/software/bluelib/BlueLibConstants.java index d07fa8a6..0197e110 100644 --- a/common/src/main/java/software/bluelib/BlueLibConstants.java +++ b/common/src/main/java/software/bluelib/BlueLibConstants.java @@ -49,11 +49,25 @@ public class BlueLibConstants { */ public static final String MOD_NAME = "BlueLib"; - /** + /** TODO: Always have on False when pushing to production * A {@code public static final} {@link Boolean} indicating whether the example features should be enabled.
          * Should always be false in production. * * @since 1.0.0 */ public static final Boolean isExampleEnabled = true; + + /** TODO: Always have on False when pushing to production + * A {@link Boolean} to enable or disable BlueLib specific logging. + * + * @since 1.0.0 + */ + public static boolean isBlueLibLoggingEnabled = true; + + /** TODO: Always have on False when pushing to production + * A {@link Boolean} to enable or disable general logging. + * + * @since 1.0.0 + */ + public static boolean isLoggingEnabled = true; } \ No newline at end of file diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java index 9651f89d..87b42958 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -34,21 +34,6 @@ public class BaseLogger { */ private static final Logger logger = Logger.getLogger(BlueLibConstants.MOD_NAME); - //FIXME: Set to false before release - /** - * A {@link Boolean} to enable or disable BlueLib specific logging. - * - * @since 1.0.0 - */ - private static boolean bluelibLogging = true; - - /** - * A {@link Boolean} to enable or disable general logging. - * - * @since 1.0.0 - */ - private static boolean isLoggingEnabled = true; - /** * A {@code void} to enable or disable {@code BlueLib} specific logging. * @@ -56,7 +41,7 @@ public class BaseLogger { * @since 1.0.0 */ public static void setBlueLibLoggingEnabled(boolean pEnabled) { - bluelibLogging = pEnabled; + BlueLibConstants.isBlueLibLoggingEnabled = pEnabled; } /** @@ -66,7 +51,7 @@ public static void setBlueLibLoggingEnabled(boolean pEnabled) { * @since 1.0.0 */ public static boolean isBlueLibLoggingEnabled() { - return bluelibLogging; + return BlueLibConstants.isBlueLibLoggingEnabled; } /** @@ -76,7 +61,7 @@ public static boolean isBlueLibLoggingEnabled() { * @since 1.0.0 */ public static boolean isLoggingEnabled() { - return isLoggingEnabled; + return BlueLibConstants.isLoggingEnabled; } /** @@ -86,7 +71,7 @@ public static boolean isLoggingEnabled() { * @since 1.0.0 */ public static void setLoggingEnabled(boolean pEnabled) { - isLoggingEnabled = pEnabled; + BlueLibConstants.isLoggingEnabled = pEnabled; } static { @@ -107,8 +92,8 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, b if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB || - pIsBlueLib && bluelibLogging || - !pIsBlueLib && isLoggingEnabled) { + pIsBlueLib && BlueLibConstants.isBlueLibLoggingEnabled || + !pIsBlueLib && BlueLibConstants.isLoggingEnabled) { logger.log(pLogLevel, pMessage, pThrowable); } } @@ -125,8 +110,8 @@ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB || - pIsBlueLib && bluelibLogging || - !pIsBlueLib && isLoggingEnabled) { + pIsBlueLib && BlueLibConstants.isBlueLibLoggingEnabled || + !pIsBlueLib && BlueLibConstants.isLoggingEnabled) { logger.log(pLogLevel, pMessage); } } @@ -144,7 +129,7 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB || - isLoggingEnabled) { + BlueLibConstants.isLoggingEnabled) { logger.log(pLogLevel, pMessage, pThrowable); } } @@ -160,7 +145,7 @@ public static void log(Level pLogLevel, String pMessage) { if (pLogLevel == BaseLogLevel.ERROR || pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB || - isLoggingEnabled) { + BlueLibConstants.isLoggingEnabled) { logger.log(pLogLevel, pMessage); } } From 5620d08249b3f218890d371451fd3b996cfc801a Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 9 Oct 2024 14:05:31 +0200 Subject: [PATCH 55/62] Commented all Example Code --- .../example/entity/dragon/DragonEntity.java | 62 +++++++++++++++-- .../example/entity/dragon/DragonModel.java | 36 +++++++++- .../example/entity/dragon/DragonRender.java | 14 +++- .../bluelib/example/entity/rex/RexEntity.java | 61 +++++++++++++++-- .../bluelib/example/entity/rex/RexModel.java | 36 +++++++++- .../bluelib/example/entity/rex/RexRender.java | 14 +++- .../bluelib/example/event/ClientEvents.java | 18 ++++- .../bluelib/example/event/CommonModEvent.java | 21 ++++++ .../bluelib/example/init/ModEntities.java | 36 +++++++++- .../bluelib/example/proxy/ClientProxy.java | 25 +++++-- .../bluelib/example/proxy/CommonProxy.java | 26 +++++++ .../example/entity/dragon/DragonEntity.java | 62 +++++++++++++++-- .../example/entity/dragon/DragonModel.java | 37 ++++++++-- .../example/entity/dragon/DragonRender.java | 14 +++- .../bluelib/example/entity/rex/RexEntity.java | 61 +++++++++++++++-- .../bluelib/example/entity/rex/RexModel.java | 36 +++++++++- .../bluelib/example/entity/rex/RexRender.java | 14 +++- .../bluelib/example/event/ClientEvents.java | 29 +++++++- .../bluelib/example/event/ReloadHandler.java | 2 - .../bluelib/example/init/ModEntities.java | 35 +++++++++- .../main/java/software/bluelib/BlueLib.java | 4 ++ .../example/entity/dragon/DragonEntity.java | 67 ++++++++++++++----- .../example/entity/dragon/DragonModel.java | 36 +++++++++- .../example/entity/dragon/DragonRender.java | 14 +++- .../bluelib/example/entity/rex/RexEntity.java | 62 +++++++++++++---- .../bluelib/example/entity/rex/RexModel.java | 36 +++++++++- .../bluelib/example/entity/rex/RexRender.java | 14 +++- .../bluelib/example/event/ReloadHandler.java | 4 -- .../bluelib/example/init/ClientInit.java | 20 ++++++ .../bluelib/example/init/ModEntities.java | 26 +++++++ 30 files changed, 836 insertions(+), 86 deletions(-) diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 130d2740..5f9d893f 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -32,7 +32,6 @@ * animation system. *

          * - *

          * Key Methods: *

            *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
          • @@ -40,7 +39,6 @@ *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • *
          - *

          * * @author MeAlam * @since 1.0.0 @@ -65,10 +63,24 @@ public DragonEntity(EntityType pEntityType, Level pLeve super(pEntityType, pLevel); } + /** + * A {@code public void} that defines the Variant data for the dragon entity. + * + * @param pVariantName {@link String} - The variant name of the dragon entity. + * @author MeAlam + * @since 1.0.0 + */ public void setVariantName(String pVariantName) { ((IVariantAccessor) this).setEntityVariantName(pVariantName); } + /** + * A {@code public} {@link String} that retrieves the Variant data for the dragon entity. + * + * @return {@link String} - The variant name of the dragon entity. + * @author MeAlam + * @since 1.0.0 + */ public String getVariantName() { return ((IVariantAccessor) this).getEntityVariantName(); } @@ -103,12 +115,23 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul } + + /* All Code below this Fragment is not Library Related!!! */ + /** - * All Code below this Fragment is not Library Related!!! + * The cache for the animatable instance. + * + * @since 1.0.0 */ - private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + /** + * Defines the synchronized data for the dragon entity. + * @return {@link SynchedEntityData.Builder} - The builder for the synchronized data. + * + * @author MeAlam + * @since 1.0.0 + */ public static AttributeSupplier.Builder createAttributes() { return Mob.createMobAttributes() .add(Attributes.MOVEMENT_SPEED, 0.3) @@ -119,21 +142,52 @@ public static AttributeSupplier.Builder createAttributes() { .add(Attributes.FLYING_SPEED, 0.3); } + /** + * Adds custom data to the entity's NBT for saving. + * @param pControllerRegistrar {@link CompoundTag} - The tag to add the data to. + * + * @author MeAlam + * @since 1.0.0 + */ @Override public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { } + /** + * Adds custom data to the entity's NBT for saving. + * @return {@link CompoundTag} - The tag with the custom data. + * + * @author MeAlam + * @since 1.0.0 + */ @Override public AnimatableInstanceCache getAnimatableInstanceCache() { return cache; } + /** + * Adds custom data to the entity's NBT for saving. + * @param pLevel {@link CompoundTag} - The tag to add the data to. + * @param pOtherParent {@link CompoundTag} - The other tag to add the data from. + * @return {@link CompoundTag} - The tag with the custom data. + * + * @author MeAlam + * @since 1.0.0 + */ @Nullable @Override public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { return null; } + /** + * Adds custom data to the entity's NBT for saving. + * @param pItemStack {@link ItemStack} - The item stack to check. + * @return {@link boolean} - Whether the item is food or not. + * + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isFood(@NotNull ItemStack pItemStack) { return false; diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java index 2979ca65..640dbe36 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java +++ b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java @@ -6,22 +6,52 @@ import software.bernie.geckolib.model.GeoModel; import software.bluelib.BlueLibConstants; +/** + * A {@code public class} that extends {@link GeoModel} for the {@link DragonEntity} entity. + * Key Methods: + *
            + *
          • {@link #getModelResource(DragonEntity)} - Get the Model Location.
          • + *
          • {@link #getTextureResource(DragonEntity)} - Get the Texture Location.
          • + *
          • {@link #getAnimationResource(DragonEntity)} - Get the Animation Location.
          • + *
          + */ public class DragonModel extends GeoModel { - // Get the Model Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the model. + * + * @param pObject {@link DragonEntity} - The entity to get the model for. + * @return {@link ResourceLocation} - The location of the model. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getModelResource(DragonEntity pObject) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/dragon.geo.json"); } - // Get the Texture Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the texture. + * + * @param pObject {@link DragonEntity} - The entity to get the texture for. + * @return {@link ResourceLocation} - The location of the texture. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getTextureResource(DragonEntity pObject) { return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); } - // Get the Animation Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the animation. + * + * @param pAnimatable {@link DragonEntity} - The entity to get the animation for. + * @return {@link ResourceLocation} - The location of the animation. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getAnimationResource(DragonEntity pAnimatable) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/dragon.animation.json"); diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java index c770ac48..d6a4e340 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java +++ b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java @@ -5,9 +5,21 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider; import software.bernie.geckolib.renderer.GeoEntityRenderer; +/** + * A {@code public class} that extends {@link GeoEntityRenderer} for rendering the dragon entity. + * + * @author MeAlam + * @since 1.0.0 + */ public class DragonRender extends GeoEntityRenderer { - // Render the entity + /** + * Constructor + * + * @param pRenderManager {@link EntityRendererProvider.Context} - The render manager. + * @author MeAlam + * @since 1.0.0 + */ public DragonRender(EntityRendererProvider.Context pRenderManager) { super(pRenderManager, new DragonModel()); } diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index 8c3d1fa7..ea368713 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -32,7 +32,6 @@ * animation system. *

          * - *

          * Key Methods: *

            *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
          • @@ -42,7 +41,6 @@ *
          • {@link #setVariantName(String)} - Sets the variant name of the Rex.
          • *
          • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
          • *
          - *

          * * @author MeAlam * @since 1.0.0 @@ -67,10 +65,24 @@ public RexEntity(EntityType pEntityType, Level pLevel) super(pEntityType, pLevel); } + /** + * A {@code public void} that defines the Variant data for the rex entity. + * + * @param pVariantName {@link String} - The variant name of the rex entity. + * @author MeAlam + * @since 1.0.0 + */ public void setVariantName(String pVariantName) { ((IVariantAccessor) this).setEntityVariantName(pVariantName); } + /** + * A {@code public} {@link String} that retrieves the Variant data for the rex entity. + * + * @return {@link String} - The variant name of the rex entity. + * @author MeAlam + * @since 1.0.0 + */ public String getVariantName() { return ((IVariantAccessor) this).getEntityVariantName(); } @@ -104,12 +116,22 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } + /* All Code below this Fragment is not Library Related!!! */ + /** - * All Code below this Fragment is not Library Related!!! + * The cache for the animatable instance. + * + * @since 1.0.0 */ - private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + /** + * Defines the synchronized data for the dragon entity. + * + * @return {@link SynchedEntityData.Builder} - The builder for the synchronized data. + * @author MeAlam + * @since 1.0.0 + */ public static AttributeSupplier.Builder createAttributes() { return Mob.createMobAttributes() .add(Attributes.MOVEMENT_SPEED, 0.3) @@ -120,21 +142,52 @@ public static AttributeSupplier.Builder createAttributes() { .add(Attributes.FLYING_SPEED, 0.3); } + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pControllerRegistrar {@link CompoundTag} - The tag to add the data to. + * @author MeAlam + * @since 1.0.0 + */ @Override public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { } + /** + * Adds custom data to the entity's NBT for saving. + * + * @return {@link CompoundTag} - The tag with the custom data. + * @author MeAlam + * @since 1.0.0 + */ @Override public AnimatableInstanceCache getAnimatableInstanceCache() { return cache; } + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pLevel {@link CompoundTag} - The tag to add the data to. + * @param pOtherParent {@link CompoundTag} - The other tag to add the data from. + * @return {@link CompoundTag} - The tag with the custom data. + * @author MeAlam + * @since 1.0.0 + */ @Nullable @Override public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { return null; } + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pItemStack {@link ItemStack} - The item stack to check. + * @return {@link boolean} - Whether the item is food or not. + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isFood(@NotNull ItemStack pItemStack) { return false; diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java index a5f87895..0a00e31e 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java +++ b/Forge/src/main/java/software/bluelib/example/entity/rex/RexModel.java @@ -6,22 +6,52 @@ import software.bernie.geckolib.model.GeoModel; import software.bluelib.BlueLibConstants; +/** + * A {@code public class} that extends {@link GeoModel} for the {@link RexEntity} entity. + * Key Methods: + *
            + *
          • {@link #getModelResource(RexEntity)} - Get the Model Location.
          • + *
          • {@link #getTextureResource(RexEntity)} - Get the Texture Location.
          • + *
          • {@link #getAnimationResource(RexEntity)} - Get the Animation Location.
          • + *
          + */ public class RexModel extends GeoModel { - // Get the Model Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the model. + * + * @param pObject {@link RexEntity} - The entity to get the model for. + * @return {@link ResourceLocation} - The location of the model. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getModelResource(RexEntity pObject) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/rex.geo.json"); } - // Get the Texture Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the texture. + * + * @param pObject {@link RexEntity} - The entity to get the texture for. + * @return {@link ResourceLocation} - The location of the texture. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getTextureResource(RexEntity pObject) { return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); } - // Get the Animation Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the animation. + * + * @param pAnimatable {@link RexEntity} - The entity to get the animation for. + * @return {@link ResourceLocation} - The location of the animation. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getAnimationResource(RexEntity pAnimatable) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/rex.animation.json"); diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java index 776c5920..2ca92fae 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java +++ b/Forge/src/main/java/software/bluelib/example/entity/rex/RexRender.java @@ -5,9 +5,21 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider; import software.bernie.geckolib.renderer.GeoEntityRenderer; +/** + * A {@code public class} that extends {@link GeoEntityRenderer} for rendering the rex entity. + * + * @author MeAlam + * @since 1.0.0 + */ public class RexRender extends GeoEntityRenderer { - // Render the entity + /** + * Constructor + * + * @param pRenderManager {@link EntityRendererProvider.Context} - The render manager. + * @author MeAlam + * @since 1.0.0 + */ public RexRender(EntityRendererProvider.Context pRenderManager) { super(pRenderManager, new RexModel()); } diff --git a/Forge/src/main/java/software/bluelib/example/event/ClientEvents.java b/Forge/src/main/java/software/bluelib/example/event/ClientEvents.java index 03e70c8e..76e7f603 100644 --- a/Forge/src/main/java/software/bluelib/example/event/ClientEvents.java +++ b/Forge/src/main/java/software/bluelib/example/event/ClientEvents.java @@ -12,11 +12,27 @@ import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; +/** + * A {@code public class} that contains the events that are fired on the client side. + *

          + * Key Methods: + *

            + *
          • {@link #registerRenderers()} - Registers the renderers for the entities.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ @Mod.EventBusSubscriber(modid = BlueLibConstants.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public class ClientEvents { + /** + * A {@code public static void} that registers the renderers for the entities. + * + * @author MeAlam + * @since 1.0.0 + */ public static void registerRenderers() { - // Register the renderer for all the Entities EntityRenderers.register(ModEntities.DRAGON.get(), DragonRender::new); EntityRenderers.register(ModEntities.REX.get(), RexRender::new); BaseLogger.log(BaseLogLevel.INFO, "Registered Renderers for Entities", true); diff --git a/Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java b/Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java index 2a760459..c53aada8 100644 --- a/Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java +++ b/Forge/src/main/java/software/bluelib/example/event/CommonModEvent.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.example.event; import net.minecraftforge.event.entity.EntityAttributeCreationEvent; @@ -10,8 +12,27 @@ import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; +/** + * A {@code public class} that contains the events that are fired on the common side. + *

          + * Key Methods: + *

            + *
          • {@link #onAttributeCreate(EntityAttributeCreationEvent)} - Registers the attributes for the entities.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ @Mod.EventBusSubscriber(modid = BlueLibConstants.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public class CommonModEvent { + + /** + * A {@code public static void} that registers the attributes for the entities. + * + * @param pEvent {@link EntityAttributeCreationEvent} - The event that is fired when the attributes are being registered. + * @author MeAlam + * @since 1.0.0 + */ @SubscribeEvent public static void onAttributeCreate(EntityAttributeCreationEvent pEvent) { pEvent.put(ModEntities.DRAGON.get(), DragonEntity.createAttributes().build()); diff --git a/Forge/src/main/java/software/bluelib/example/init/ModEntities.java b/Forge/src/main/java/software/bluelib/example/init/ModEntities.java index c7c5c3e0..674c42fd 100644 --- a/Forge/src/main/java/software/bluelib/example/init/ModEntities.java +++ b/Forge/src/main/java/software/bluelib/example/init/ModEntities.java @@ -13,11 +13,29 @@ import software.bluelib.example.entity.dragon.DragonEntity; import software.bluelib.example.entity.rex.RexEntity; +/** + * A {@code public class} for registering {@link EntityType} for this mod. + *

          + * Key Methods: + *

            + *
          • {@link #register(IEventBus)} - Registers the {@link EntityType} for this mod.
          • + *
          + */ public class ModEntities { + + /** + * A {@code public static final} {@link DeferredRegister} of {@link EntityType} for this mod. + * + * @since 1.0.0 + */ public static final DeferredRegister> REGISTER = DeferredRegister.create(ForgeRegistries.ENTITY_TYPES, BlueLibConstants.MOD_ID); - // List of Entities + /** + * A {@code public static final} {@link RegistryObject} of {@link EntityType} for the {@link DragonEntity}. + * + * @since 1.0.0 + */ public static final RegistryObject> DRAGON = REGISTER.register("example_one", () -> EntityType.Builder.of(DragonEntity::new, MobCategory.AMBIENT) .setShouldReceiveVelocityUpdates(true) @@ -27,6 +45,11 @@ public class ModEntities { .sized(0.6f, 1.8f) .build(ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "dragon").toString())); + /** + * A {@code public static final} {@link RegistryObject} of {@link EntityType} for the {@link RexEntity}. + * + * @since 1.0.0 + */ public static final RegistryObject> REX = REGISTER.register("example_two", () -> EntityType.Builder.of(RexEntity::new, MobCategory.AMBIENT) .setShouldReceiveVelocityUpdates(true) @@ -36,7 +59,14 @@ public class ModEntities { .sized(0.6f, 1.8f) .build(ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "rex").toString())); - public static void register(IEventBus eventBus) { - REGISTER.register(eventBus); + /** + * A {@code public static} method to register the {@link EntityType} for this mod. + * @param pEventBus {@link IEventBus} - The event bus to register the {@link EntityType} with. + * + * @author MeAlam + * @since 1.0.0 + */ + public static void register(IEventBus pEventBus) { + REGISTER.register(pEventBus); } } diff --git a/Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java b/Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java index eb894483..ce2612a5 100644 --- a/Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java +++ b/Forge/src/main/java/software/bluelib/example/proxy/ClientProxy.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.example.proxy; import net.minecraftforge.api.distmarker.Dist; @@ -5,13 +7,28 @@ import software.bluelib.BlueLibConstants; import software.bluelib.example.event.ClientEvents; +/** + * A {@code public class} that extends {@link CommonProxy} and is annotated with {@link Mod.EventBusSubscriber} to handle + * client-side events. + *

          + * Key Methods: + *

            + *
          • {@link #clientInit()} - Handles the event after the initialization of the client.
          • + *
          + * + * @author MeAlam + * @see CommonProxy + * @since 1.0.0 + */ @Mod.EventBusSubscriber(modid = BlueLibConstants.MOD_ID, value = Dist.CLIENT) public class ClientProxy extends CommonProxy { - @Override - public void postInit() { - } - + /** + * A {@code public void} method that is called after the initialization of the client. + * + * @author MeAlam + * @since 1.0.0 + */ @Override public void clientInit() { super.clientInit(); diff --git a/Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java b/Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java index 33ae075c..18692b69 100644 --- a/Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java +++ b/Forge/src/main/java/software/bluelib/example/proxy/CommonProxy.java @@ -1,14 +1,40 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.example.proxy; import net.minecraftforge.fml.common.Mod; import software.bluelib.BlueLibConstants; +/** + * A {@code public class} that is annotated with {@link Mod.EventBusSubscriber} to handle common events. + *

          + * Key Methods: + *

            + *
          • {@link #postInit()} - Handles the event after the initialization of the mod.
          • + *
          • {@link #clientInit()} - Handles the event after the initialization of the client.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ @Mod.EventBusSubscriber(modid = BlueLibConstants.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public class CommonProxy { + /** + * A {@code public void} method that is called after the initialization of the mod. + * + * @author MeAlam + * @since 1.0.0 + */ public void postInit() { } + /** + * A {@code public void} method that is called after the initialization of the client. + * + * @author MeAlam + * @since 1.0.0 + */ public void clientInit() { } } diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 130d2740..5f9d893f 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -32,7 +32,6 @@ * animation system. *

          * - *

          * Key Methods: *

            *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
          • @@ -40,7 +39,6 @@ *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • *
          - *

          * * @author MeAlam * @since 1.0.0 @@ -65,10 +63,24 @@ public DragonEntity(EntityType pEntityType, Level pLeve super(pEntityType, pLevel); } + /** + * A {@code public void} that defines the Variant data for the dragon entity. + * + * @param pVariantName {@link String} - The variant name of the dragon entity. + * @author MeAlam + * @since 1.0.0 + */ public void setVariantName(String pVariantName) { ((IVariantAccessor) this).setEntityVariantName(pVariantName); } + /** + * A {@code public} {@link String} that retrieves the Variant data for the dragon entity. + * + * @return {@link String} - The variant name of the dragon entity. + * @author MeAlam + * @since 1.0.0 + */ public String getVariantName() { return ((IVariantAccessor) this).getEntityVariantName(); } @@ -103,12 +115,23 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul } + + /* All Code below this Fragment is not Library Related!!! */ + /** - * All Code below this Fragment is not Library Related!!! + * The cache for the animatable instance. + * + * @since 1.0.0 */ - private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + /** + * Defines the synchronized data for the dragon entity. + * @return {@link SynchedEntityData.Builder} - The builder for the synchronized data. + * + * @author MeAlam + * @since 1.0.0 + */ public static AttributeSupplier.Builder createAttributes() { return Mob.createMobAttributes() .add(Attributes.MOVEMENT_SPEED, 0.3) @@ -119,21 +142,52 @@ public static AttributeSupplier.Builder createAttributes() { .add(Attributes.FLYING_SPEED, 0.3); } + /** + * Adds custom data to the entity's NBT for saving. + * @param pControllerRegistrar {@link CompoundTag} - The tag to add the data to. + * + * @author MeAlam + * @since 1.0.0 + */ @Override public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { } + /** + * Adds custom data to the entity's NBT for saving. + * @return {@link CompoundTag} - The tag with the custom data. + * + * @author MeAlam + * @since 1.0.0 + */ @Override public AnimatableInstanceCache getAnimatableInstanceCache() { return cache; } + /** + * Adds custom data to the entity's NBT for saving. + * @param pLevel {@link CompoundTag} - The tag to add the data to. + * @param pOtherParent {@link CompoundTag} - The other tag to add the data from. + * @return {@link CompoundTag} - The tag with the custom data. + * + * @author MeAlam + * @since 1.0.0 + */ @Nullable @Override public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { return null; } + /** + * Adds custom data to the entity's NBT for saving. + * @param pItemStack {@link ItemStack} - The item stack to check. + * @return {@link boolean} - Whether the item is food or not. + * + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isFood(@NotNull ItemStack pItemStack) { return false; diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java index 58da8fbc..640dbe36 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java @@ -5,24 +5,53 @@ import net.minecraft.resources.ResourceLocation; import software.bernie.geckolib.model.GeoModel; import software.bluelib.BlueLibConstants; -import software.bluelib.utils.logging.BaseLogger; +/** + * A {@code public class} that extends {@link GeoModel} for the {@link DragonEntity} entity. + * Key Methods: + *
            + *
          • {@link #getModelResource(DragonEntity)} - Get the Model Location.
          • + *
          • {@link #getTextureResource(DragonEntity)} - Get the Texture Location.
          • + *
          • {@link #getAnimationResource(DragonEntity)} - Get the Animation Location.
          • + *
          + */ public class DragonModel extends GeoModel { - // Get the Model Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the model. + * + * @param pObject {@link DragonEntity} - The entity to get the model for. + * @return {@link ResourceLocation} - The location of the model. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getModelResource(DragonEntity pObject) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/dragon.geo.json"); } - // Get the Texture Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the texture. + * + * @param pObject {@link DragonEntity} - The entity to get the texture for. + * @return {@link ResourceLocation} - The location of the texture. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getTextureResource(DragonEntity pObject) { return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); } - // Get the Animation Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the animation. + * + * @param pAnimatable {@link DragonEntity} - The entity to get the animation for. + * @return {@link ResourceLocation} - The location of the animation. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getAnimationResource(DragonEntity pAnimatable) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/dragon.animation.json"); diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java index c770ac48..d6a4e340 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java @@ -5,9 +5,21 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider; import software.bernie.geckolib.renderer.GeoEntityRenderer; +/** + * A {@code public class} that extends {@link GeoEntityRenderer} for rendering the dragon entity. + * + * @author MeAlam + * @since 1.0.0 + */ public class DragonRender extends GeoEntityRenderer { - // Render the entity + /** + * Constructor + * + * @param pRenderManager {@link EntityRendererProvider.Context} - The render manager. + * @author MeAlam + * @since 1.0.0 + */ public DragonRender(EntityRendererProvider.Context pRenderManager) { super(pRenderManager, new DragonModel()); } diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index 8c3d1fa7..ea368713 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -32,7 +32,6 @@ * animation system. *

          * - *

          * Key Methods: *

            *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
          • @@ -42,7 +41,6 @@ *
          • {@link #setVariantName(String)} - Sets the variant name of the Rex.
          • *
          • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
          • *
          - *

          * * @author MeAlam * @since 1.0.0 @@ -67,10 +65,24 @@ public RexEntity(EntityType pEntityType, Level pLevel) super(pEntityType, pLevel); } + /** + * A {@code public void} that defines the Variant data for the rex entity. + * + * @param pVariantName {@link String} - The variant name of the rex entity. + * @author MeAlam + * @since 1.0.0 + */ public void setVariantName(String pVariantName) { ((IVariantAccessor) this).setEntityVariantName(pVariantName); } + /** + * A {@code public} {@link String} that retrieves the Variant data for the rex entity. + * + * @return {@link String} - The variant name of the rex entity. + * @author MeAlam + * @since 1.0.0 + */ public String getVariantName() { return ((IVariantAccessor) this).getEntityVariantName(); } @@ -104,12 +116,22 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } + /* All Code below this Fragment is not Library Related!!! */ + /** - * All Code below this Fragment is not Library Related!!! + * The cache for the animatable instance. + * + * @since 1.0.0 */ - private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + /** + * Defines the synchronized data for the dragon entity. + * + * @return {@link SynchedEntityData.Builder} - The builder for the synchronized data. + * @author MeAlam + * @since 1.0.0 + */ public static AttributeSupplier.Builder createAttributes() { return Mob.createMobAttributes() .add(Attributes.MOVEMENT_SPEED, 0.3) @@ -120,21 +142,52 @@ public static AttributeSupplier.Builder createAttributes() { .add(Attributes.FLYING_SPEED, 0.3); } + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pControllerRegistrar {@link CompoundTag} - The tag to add the data to. + * @author MeAlam + * @since 1.0.0 + */ @Override public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { } + /** + * Adds custom data to the entity's NBT for saving. + * + * @return {@link CompoundTag} - The tag with the custom data. + * @author MeAlam + * @since 1.0.0 + */ @Override public AnimatableInstanceCache getAnimatableInstanceCache() { return cache; } + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pLevel {@link CompoundTag} - The tag to add the data to. + * @param pOtherParent {@link CompoundTag} - The other tag to add the data from. + * @return {@link CompoundTag} - The tag with the custom data. + * @author MeAlam + * @since 1.0.0 + */ @Nullable @Override public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { return null; } + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pItemStack {@link ItemStack} - The item stack to check. + * @return {@link boolean} - Whether the item is food or not. + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isFood(@NotNull ItemStack pItemStack) { return false; diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java index 4323f872..0a00e31e 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexModel.java @@ -6,22 +6,52 @@ import software.bernie.geckolib.model.GeoModel; import software.bluelib.BlueLibConstants; +/** + * A {@code public class} that extends {@link GeoModel} for the {@link RexEntity} entity. + * Key Methods: + *
            + *
          • {@link #getModelResource(RexEntity)} - Get the Model Location.
          • + *
          • {@link #getTextureResource(RexEntity)} - Get the Texture Location.
          • + *
          • {@link #getAnimationResource(RexEntity)} - Get the Animation Location.
          • + *
          + */ public class RexModel extends GeoModel { - // Get the Model Locations + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the model. + * + * @param pObject {@link RexEntity} - The entity to get the model for. + * @return {@link ResourceLocation} - The location of the model. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getModelResource(RexEntity pObject) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/rex.geo.json"); } - // Get the Texture Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the texture. + * + * @param pObject {@link RexEntity} - The entity to get the texture for. + * @return {@link ResourceLocation} - The location of the texture. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getTextureResource(RexEntity pObject) { return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); } - // Get the Animation Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the animation. + * + * @param pAnimatable {@link RexEntity} - The entity to get the animation for. + * @return {@link ResourceLocation} - The location of the animation. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getAnimationResource(RexEntity pAnimatable) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/rex.animation.json"); diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java index 776c5920..2ca92fae 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexRender.java @@ -5,9 +5,21 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider; import software.bernie.geckolib.renderer.GeoEntityRenderer; +/** + * A {@code public class} that extends {@link GeoEntityRenderer} for rendering the rex entity. + * + * @author MeAlam + * @since 1.0.0 + */ public class RexRender extends GeoEntityRenderer { - // Render the entity + /** + * Constructor + * + * @param pRenderManager {@link EntityRendererProvider.Context} - The render manager. + * @author MeAlam + * @since 1.0.0 + */ public RexRender(EntityRendererProvider.Context pRenderManager) { super(pRenderManager, new RexModel()); } diff --git a/NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java b/NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java index 7e6f8cca..ff44b592 100644 --- a/NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java +++ b/NeoForge/src/main/java/software/bluelib/example/event/ClientEvents.java @@ -13,16 +13,41 @@ import software.bluelib.utils.logging.BaseLogLevel; import software.bluelib.utils.logging.BaseLogger; +/** + * A {@code public class} that contains the events that are fired on the client side. + *

          + * Key Methods: + *

            + *
          • {@link #registerRenderers(EntityRenderersEvent.RegisterRenderers)} - Registers the renderers for the entities.
          • + *
          • {@link #registerAttributes(EntityAttributeCreationEvent)} - Registers the attributes for the entities.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ public class ClientEvents { + + /** + * A {@code public static void} that registers the renderers for the entities. + * + * @param pEvent {@link EntityRenderersEvent} - The event that is fired when the renderers are being registered. + * @author MeAlam + * @since 1.0.0 + */ @SubscribeEvent public static void registerRenderers(final EntityRenderersEvent.RegisterRenderers pEvent) { - // Register the renderer for all the Entities pEvent.registerEntityRenderer(ModEntities.DRAGON.get(), DragonRender::new); pEvent.registerEntityRenderer(ModEntities.REX.get(), RexRender::new); BaseLogger.log(BaseLogLevel.INFO, "Registered Renderers for Entities", true); } - // Register the Attributes + /** + * A {@code public static void} that registers the attributes for the entities. + * + * @param pEvent {@link EntityAttributeCreationEvent} - The event that is fired when the attributes are being registered. + * @author MeAlam + * @since 1.0.0 + */ @SubscribeEvent public static void registerAttributes(EntityAttributeCreationEvent pEvent) { pEvent.put(ModEntities.DRAGON.get(), DragonEntity.createAttributes().build()); diff --git a/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java b/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java index a8d19c93..3d56a476 100644 --- a/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java +++ b/NeoForge/src/main/java/software/bluelib/example/event/ReloadHandler.java @@ -25,14 +25,12 @@ * ensuring that entity variant data is properly loaded and refreshed. *

          * - *

          * Key Methods: *

            *
          • {@link #onServerStart(ServerStartingEvent)} - Handles server starting events to initialize entity variants.
          • *
          • {@link #onReload(AddReloadListenerEvent)} - Handles reload events to refresh entity variants.
          • *
          • {@link #LoadEntityVariants(MinecraftServer)} - Loads entity variants from JSON files into the server.
          • *
          - *

          * * @author MeAlam * @since 1.0.0 diff --git a/NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java b/NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java index cd90fea8..9f79c471 100644 --- a/NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java +++ b/NeoForge/src/main/java/software/bluelib/example/init/ModEntities.java @@ -12,10 +12,28 @@ import software.bluelib.example.entity.dragon.DragonEntity; import software.bluelib.example.entity.rex.RexEntity; +/** + * A {@code public class} for registering {@link EntityType} for this mod. + *

          + * Key Methods: + *

            + *
          • {@link #register(String, EntityType.Builder)} - Registers an {@link EntityType} with the specified {@code pRegistryName} and {@code pEntityTypeBuilder}.
          • + *
          + */ public class ModEntities { + + /** + * A {@code public static final} {@link DeferredRegister} of {@link EntityType} for this mod. + * + * @since 1.0.0 + */ public static final DeferredRegister> REGISTRY = DeferredRegister.create(Registries.ENTITY_TYPE, BlueLibConstants.MOD_ID); - // List of Entities + /** + * A {@code public static final} {@link DeferredHolder} of {@link EntityType} for the {@link DragonEntity}. + * + * @since 1.0.0 + */ public static final DeferredHolder, EntityType> DRAGON = register( "example_one", EntityType.Builder.of(DragonEntity::new, MobCategory.AMBIENT) @@ -25,6 +43,11 @@ public class ModEntities { .fireImmune() .sized(0.6f, 1.8f)); + /** + * A {@code public static final} {@link DeferredHolder} of {@link EntityType} for the {@link RexEntity}. + * + * @since 1.0.0 + */ public static final DeferredHolder, EntityType> REX = register( "example_two", EntityType.Builder.of(RexEntity::new, MobCategory.AMBIENT) @@ -34,6 +57,16 @@ public class ModEntities { .fireImmune() .sized(0.6f, 1.8f)); + /** + * A {@code private static} {@link Entity} method to register an {@link EntityType} with the specified {@code pRegistryName} and {@code pEntityTypeBuilder}. + * + * @param pRegistryName {@link String} - The registry name of the {@link EntityType}. + * @param pEntityTypeBuilder {@link EntityType.Builder} - The builder of the {@link EntityType}. + * @param The type of the entity. + * @return {@link DeferredHolder} - The deferred holder of the {@link EntityType}. + * @author MeAlam + * @since 1.0.0 + */ private static DeferredHolder, EntityType> register(String pRegistryName, EntityType.Builder pEntityTypeBuilder) { return REGISTRY.register(pRegistryName, () -> pEntityTypeBuilder.build(pRegistryName)); } diff --git a/fabric/src/main/java/software/bluelib/BlueLib.java b/fabric/src/main/java/software/bluelib/BlueLib.java index 469a4f01..fce107db 100644 --- a/fabric/src/main/java/software/bluelib/BlueLib.java +++ b/fabric/src/main/java/software/bluelib/BlueLib.java @@ -40,6 +40,10 @@ public class BlueLib implements ModInitializer { /** * A {@code public void} that registers a client tick event to initialize the BlueLib mod. *

          + * This method checks if the mod is being run in developer mode and if the Geckolib mod is loaded. If both conditions + * are met, it initializes the entities and registers the event listeners for the reload handler. + *

          + *

          * This method uses {@link ClientTickEvents#END_CLIENT_TICK} to register a callback that checks * whether the mod has already been initialized and calls {@link BlueLibCommon#init()} if necessary. *

          diff --git a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 130d2740..f8325ae0 100644 --- a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -7,8 +7,6 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.*; -import net.minecraft.world.entity.ai.attributes.AttributeSupplier; -import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; @@ -31,7 +29,6 @@ * This class manages the dragon's variant system, its data synchronization, and integrates with the GeckoLib * animation system. *

          - * *

          * Key Methods: *

            @@ -40,7 +37,6 @@ *
          • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
          • *
          • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
          • *
          - *

          * * @author MeAlam * @since 1.0.0 @@ -65,10 +61,24 @@ public DragonEntity(EntityType pEntityType, Level pLeve super(pEntityType, pLevel); } + /** + * A {@code public void} that defines the Variant data for the dragon entity. + * + * @param pVariantName {@link String} - The variant name of the dragon entity. + * @author MeAlam + * @since 1.0.0 + */ public void setVariantName(String pVariantName) { ((IVariantAccessor) this).setEntityVariantName(pVariantName); } + /** + * A {@code public} {@link String} that retrieves the Variant data for the dragon entity. + * + * @return {@link String} - The variant name of the dragon entity. + * @author MeAlam + * @since 1.0.0 + */ public String getVariantName() { return ((IVariantAccessor) this).getEntityVariantName(); } @@ -103,37 +113,62 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul } + + /* All Code below this Fragment is not Library Related!!! */ + /** - * All Code below this Fragment is not Library Related!!! + * The cache for the animatable instance. + * + * @since 1.0.0 */ - private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); - public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes() - .add(Attributes.MOVEMENT_SPEED, 0.3) - .add(Attributes.MAX_HEALTH, 10) - .add(Attributes.ARMOR, 0) - .add(Attributes.ATTACK_DAMAGE, 3) - .add(Attributes.FOLLOW_RANGE, 16) - .add(Attributes.FLYING_SPEED, 0.3); - } - + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pControllerRegistrar {@link CompoundTag} - The tag to add the data to. + * @author MeAlam + * @since 1.0.0 + */ @Override public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { } + /** + * Adds custom data to the entity's NBT for saving. + * + * @return {@link CompoundTag} - The tag with the custom data. + * @author MeAlam + * @since 1.0.0 + */ @Override public AnimatableInstanceCache getAnimatableInstanceCache() { return cache; } + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pLevel {@link CompoundTag} - The tag to add the data to. + * @param pOtherParent {@link CompoundTag} - The other tag to add the data from. + * @return {@link CompoundTag} - The tag with the custom data. + * @author MeAlam + * @since 1.0.0 + */ @Nullable @Override public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { return null; } + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pItemStack {@link ItemStack} - The item stack to check. + * @return {@link boolean} - Whether the item is food or not. + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isFood(@NotNull ItemStack pItemStack) { return false; diff --git a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java index 2979ca65..640dbe36 100644 --- a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java +++ b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonModel.java @@ -6,22 +6,52 @@ import software.bernie.geckolib.model.GeoModel; import software.bluelib.BlueLibConstants; +/** + * A {@code public class} that extends {@link GeoModel} for the {@link DragonEntity} entity. + * Key Methods: + *
            + *
          • {@link #getModelResource(DragonEntity)} - Get the Model Location.
          • + *
          • {@link #getTextureResource(DragonEntity)} - Get the Texture Location.
          • + *
          • {@link #getAnimationResource(DragonEntity)} - Get the Animation Location.
          • + *
          + */ public class DragonModel extends GeoModel { - // Get the Model Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the model. + * + * @param pObject {@link DragonEntity} - The entity to get the model for. + * @return {@link ResourceLocation} - The location of the model. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getModelResource(DragonEntity pObject) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/dragon.geo.json"); } - // Get the Texture Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the texture. + * + * @param pObject {@link DragonEntity} - The entity to get the texture for. + * @return {@link ResourceLocation} - The location of the texture. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getTextureResource(DragonEntity pObject) { return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); } - // Get the Animation Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the animation. + * + * @param pAnimatable {@link DragonEntity} - The entity to get the animation for. + * @return {@link ResourceLocation} - The location of the animation. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getAnimationResource(DragonEntity pAnimatable) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/dragon.animation.json"); diff --git a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java index c770ac48..d6a4e340 100644 --- a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java +++ b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonRender.java @@ -5,9 +5,21 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider; import software.bernie.geckolib.renderer.GeoEntityRenderer; +/** + * A {@code public class} that extends {@link GeoEntityRenderer} for rendering the dragon entity. + * + * @author MeAlam + * @since 1.0.0 + */ public class DragonRender extends GeoEntityRenderer { - // Render the entity + /** + * Constructor + * + * @param pRenderManager {@link EntityRendererProvider.Context} - The render manager. + * @author MeAlam + * @since 1.0.0 + */ public DragonRender(EntityRendererProvider.Context pRenderManager) { super(pRenderManager, new DragonModel()); } diff --git a/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index 8c3d1fa7..1ed1b583 100644 --- a/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -67,10 +67,24 @@ public RexEntity(EntityType pEntityType, Level pLevel) super(pEntityType, pLevel); } + /** + * A {@code public void} that defines the Variant data for the rex entity. + * + * @param pVariantName {@link String} - The variant name of the rex entity. + * @author MeAlam + * @since 1.0.0 + */ public void setVariantName(String pVariantName) { ((IVariantAccessor) this).setEntityVariantName(pVariantName); } + /** + * A {@code public} {@link String} that retrieves the Variant data for the rex entity. + * + * @return {@link String} - The variant name of the rex entity. + * @author MeAlam + * @since 1.0.0 + */ public String getVariantName() { return ((IVariantAccessor) this).getEntityVariantName(); } @@ -104,37 +118,61 @@ public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor pLevel, @NotNul return super.finalizeSpawn(pLevel, pDifficulty, pReason, pSpawnData); } + /* All Code below this Fragment is not Library Related!!! */ + /** - * All Code below this Fragment is not Library Related!!! + * The cache for the animatable instance. + * + * @since 1.0.0 */ - private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); - public static AttributeSupplier.Builder createAttributes() { - return Mob.createMobAttributes() - .add(Attributes.MOVEMENT_SPEED, 0.3) - .add(Attributes.MAX_HEALTH, 10) - .add(Attributes.ARMOR, 0) - .add(Attributes.ATTACK_DAMAGE, 3) - .add(Attributes.FOLLOW_RANGE, 16) - .add(Attributes.FLYING_SPEED, 0.3); - } - + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pControllerRegistrar {@link CompoundTag} - The tag to add the data to. + * @author MeAlam + * @since 1.0.0 + */ @Override public void registerControllers(AnimatableManager.ControllerRegistrar pControllerRegistrar) { } + /** + * Adds custom data to the entity's NBT for saving. + * + * @return {@link CompoundTag} - The tag with the custom data. + * @author MeAlam + * @since 1.0.0 + */ @Override public AnimatableInstanceCache getAnimatableInstanceCache() { return cache; } + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pLevel {@link CompoundTag} - The tag to add the data to. + * @param pOtherParent {@link CompoundTag} - The other tag to add the data from. + * @return {@link CompoundTag} - The tag with the custom data. + * @author MeAlam + * @since 1.0.0 + */ @Nullable @Override public AgeableMob getBreedOffspring(@NotNull ServerLevel pLevel, @NotNull AgeableMob pOtherParent) { return null; } + /** + * Adds custom data to the entity's NBT for saving. + * + * @param pItemStack {@link ItemStack} - The item stack to check. + * @return {@link boolean} - Whether the item is food or not. + * @author MeAlam + * @since 1.0.0 + */ @Override public boolean isFood(@NotNull ItemStack pItemStack) { return false; diff --git a/fabric/src/main/java/software/bluelib/example/entity/rex/RexModel.java b/fabric/src/main/java/software/bluelib/example/entity/rex/RexModel.java index 4323f872..0a00e31e 100644 --- a/fabric/src/main/java/software/bluelib/example/entity/rex/RexModel.java +++ b/fabric/src/main/java/software/bluelib/example/entity/rex/RexModel.java @@ -6,22 +6,52 @@ import software.bernie.geckolib.model.GeoModel; import software.bluelib.BlueLibConstants; +/** + * A {@code public class} that extends {@link GeoModel} for the {@link RexEntity} entity. + * Key Methods: + *
            + *
          • {@link #getModelResource(RexEntity)} - Get the Model Location.
          • + *
          • {@link #getTextureResource(RexEntity)} - Get the Texture Location.
          • + *
          • {@link #getAnimationResource(RexEntity)} - Get the Animation Location.
          • + *
          + */ public class RexModel extends GeoModel { - // Get the Model Locations + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the model. + * + * @param pObject {@link RexEntity} - The entity to get the model for. + * @return {@link ResourceLocation} - The location of the model. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getModelResource(RexEntity pObject) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "geo/rex.geo.json"); } - // Get the Texture Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the texture. + * + * @param pObject {@link RexEntity} - The entity to get the texture for. + * @return {@link ResourceLocation} - The location of the texture. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getTextureResource(RexEntity pObject) { return pObject.getTextureLocation(BlueLibConstants.MOD_ID, "textures/entity/" + pObject.entityName + "/" + pObject.getVariantName() + ".png"); } - // Get the Animation Location + /** + * A {@code public} {@link ResourceLocation} method that returns the location of the animation. + * + * @param pAnimatable {@link RexEntity} - The entity to get the animation for. + * @return {@link ResourceLocation} - The location of the animation. + * @author MeAlam + * @since 1.0.0 + */ @Override public ResourceLocation getAnimationResource(RexEntity pAnimatable) { return ResourceLocation.fromNamespaceAndPath(BlueLibConstants.MOD_ID, "animations/rex.animation.json"); diff --git a/fabric/src/main/java/software/bluelib/example/entity/rex/RexRender.java b/fabric/src/main/java/software/bluelib/example/entity/rex/RexRender.java index 776c5920..2ca92fae 100644 --- a/fabric/src/main/java/software/bluelib/example/entity/rex/RexRender.java +++ b/fabric/src/main/java/software/bluelib/example/entity/rex/RexRender.java @@ -5,9 +5,21 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider; import software.bernie.geckolib.renderer.GeoEntityRenderer; +/** + * A {@code public class} that extends {@link GeoEntityRenderer} for rendering the rex entity. + * + * @author MeAlam + * @since 1.0.0 + */ public class RexRender extends GeoEntityRenderer { - // Render the entity + /** + * Constructor + * + * @param pRenderManager {@link EntityRendererProvider.Context} - The render manager. + * @author MeAlam + * @since 1.0.0 + */ public RexRender(EntityRendererProvider.Context pRenderManager) { super(pRenderManager, new RexModel()); } diff --git a/fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java b/fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java index f82c12db..25e83b84 100644 --- a/fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java +++ b/fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java @@ -3,10 +3,7 @@ package software.bluelib.example.event; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; -import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; -import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.packs.PackType; import software.bluelib.BlueLibConstants; import software.bluelib.event.ReloadEventHandler; import software.bluelib.utils.logging.BaseLogLevel; @@ -14,7 +11,6 @@ import java.util.Arrays; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; /** diff --git a/fabric/src/main/java/software/bluelib/example/init/ClientInit.java b/fabric/src/main/java/software/bluelib/example/init/ClientInit.java index 587b51bf..9fe1fa1d 100644 --- a/fabric/src/main/java/software/bluelib/example/init/ClientInit.java +++ b/fabric/src/main/java/software/bluelib/example/init/ClientInit.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.example.init; import net.fabricmc.api.ClientModInitializer; @@ -5,7 +7,25 @@ import software.bluelib.example.entity.dragon.DragonRender; import software.bluelib.example.entity.rex.RexRender; +/** + * A {@code public class} that extends {@link ClientModInitializer} and contains the events that are fired on the client side. + *

          + * Key Methods: + *

            + *
          • {@link #onInitializeClient()} - Registers the renderers for the entities.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ public class ClientInit implements ClientModInitializer { + + /** + * A {@code public void} that registers the renderers for the entities. + * + * @author MeAlam + * @since 1.0.0 + */ @Override public void onInitializeClient() { EntityRendererRegistry.register(ModEntities.EXAMPLE_ONE, DragonRender::new); diff --git a/fabric/src/main/java/software/bluelib/example/init/ModEntities.java b/fabric/src/main/java/software/bluelib/example/init/ModEntities.java index 741751f0..b650b03e 100644 --- a/fabric/src/main/java/software/bluelib/example/init/ModEntities.java +++ b/fabric/src/main/java/software/bluelib/example/init/ModEntities.java @@ -1,3 +1,5 @@ +// Copyright (c) BlueLib. Licensed under the MIT License. + package software.bluelib.example.init; import net.minecraft.core.Registry; @@ -10,11 +12,35 @@ import static net.minecraft.world.entity.MobCategory.CREATURE; +/** + * A {@code public class} that contains the entities for the mod. + *

          + * Key Methods: + *

            + *
          • {@link #initializeEntities()} - Initializes the entities.
          • + *
          + * + * @author MeAlam + * @since 1.0.0 + */ public class ModEntities { + /** + * The {@code public static} field that stores Example One. + */ public static EntityType EXAMPLE_ONE; + + /** + * The {@code public static} field that stores Example Two. + */ public static EntityType EXAMPLE_TWO; + /** + * A {@code public static void} that initializes the entities. + * + * @author MeAlam + * @since 1.0.0 + */ public static void initializeEntities() { EXAMPLE_ONE = Registry.register( BuiltInRegistries.ENTITY_TYPE, From f4c7386febbf7c1e4cdf544098b7b15bb6134fc9 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 9 Oct 2024 14:15:20 +0200 Subject: [PATCH 56/62] Added Private Constructors to remove Build Warning --- .../bluelib/example/entity/rex/RexEntity.java | 1 - .../bluelib/example/event/ReloadHandler.java | 3 --- .../java/software/bluelib/BlueLibCommon.java | 12 +++++++++++ .../software/bluelib/BlueLibConstants.java | 20 ++++++++++++++++++ .../software/bluelib/json/JSONLoader.java | 1 - .../utils/conversion/CaseConverterUtils.java | 12 +++++++++++ .../utils/conversion/MathConverterUtils.java | 12 +++++++++++ .../bluelib/utils/logging/BaseLogLevel.java | 13 ++++++++++++ .../bluelib/utils/logging/BaseLogger.java | 21 ++++++++++++------- .../bluelib/utils/math/AlgebraicUtils.java | 12 +++++++++++ .../bluelib/utils/math/GeometricUtils.java | 12 +++++++++++ .../bluelib/utils/math/MatrixUtils.java | 12 +++++++++++ .../bluelib/utils/math/MiscUtils.java | 12 +++++++++++ .../bluelib/utils/math/RandomGenUtils.java | 12 +++++++++++ .../bluelib/utils/math/StatisticalUtils.java | 12 +++++++++++ .../bluelib/utils/minecraft/ChunkUtils.java | 12 +++++++++++ .../bluelib/utils/variant/ParameterUtils.java | 12 +++++++++++ .../main/java/software/bluelib/BlueLib.java | 11 ++++++++++ .../example/entity/dragon/DragonEntity.java | 1 - .../bluelib/example/entity/rex/RexEntity.java | 3 --- .../bluelib/example/event/ReloadHandler.java | 3 --- 21 files changed, 189 insertions(+), 20 deletions(-) diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index ea368713..89f1bdda 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -31,7 +31,6 @@ * This class manages the Rex's variant system, its data synchronization, and integrates with the GeckoLib * animation system. *

          - * * Key Methods: *
            *
          • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
          • diff --git a/Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java b/Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java index e6c5a509..8fc6be4a 100644 --- a/Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java +++ b/Forge/src/main/java/software/bluelib/example/event/ReloadHandler.java @@ -23,15 +23,12 @@ * This class extends {@link ReloadEventHandler} and implements event handling for server starting and reloading, * ensuring that entity variant data is properly loaded and refreshed. *

            - * - *

            * Key Methods: *

              *
            • {@link #onServerStart(ServerStartingEvent)} - Handles server starting events to initialize entity variants.
            • *
            • {@link #onReload(AddReloadListenerEvent)} - Handles reload events to refresh entity variants.
            • *
            • {@link #LoadEntityVariants(MinecraftServer)} - Loads entity variants from JSON files into the server.
            • *
            - *

            * * @author MeAlam * @since 1.0.0 diff --git a/common/src/main/java/software/bluelib/BlueLibCommon.java b/common/src/main/java/software/bluelib/BlueLibCommon.java index 8fcd5070..6dac3dd8 100644 --- a/common/src/main/java/software/bluelib/BlueLibCommon.java +++ b/common/src/main/java/software/bluelib/BlueLibCommon.java @@ -29,6 +29,18 @@ */ public class BlueLibCommon { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private BlueLibCommon() { + } + /** * A {@code public static final} {@link IPlatformHelper} instance that represents the current platform helper loaded for the mod. * This is used to identify platform-specific functionalities. diff --git a/common/src/main/java/software/bluelib/BlueLibConstants.java b/common/src/main/java/software/bluelib/BlueLibConstants.java index 0197e110..0950db7a 100644 --- a/common/src/main/java/software/bluelib/BlueLibConstants.java +++ b/common/src/main/java/software/bluelib/BlueLibConstants.java @@ -4,6 +4,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.logging.Logger; /** * A {@code public class} that defines common constants used across the BlueLib mod. @@ -24,6 +25,25 @@ */ public class BlueLibConstants { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private BlueLibConstants() { + } + + /** + * A {@link Logger} instance for logging messages. + * + * @since 1.0.0 + */ + public static final Logger LOGGER = Logger.getLogger(BlueLibConstants.MOD_NAME); + /** * A {@code public static final} {@link ScheduledExecutorService} used to schedule tasks, such as printing messages after a delay. *

            diff --git a/common/src/main/java/software/bluelib/json/JSONLoader.java b/common/src/main/java/software/bluelib/json/JSONLoader.java index fb1d607f..6fa2d5b1 100644 --- a/common/src/main/java/software/bluelib/json/JSONLoader.java +++ b/common/src/main/java/software/bluelib/json/JSONLoader.java @@ -40,7 +40,6 @@ public class JSONLoader { * A {@code public} {@link JsonObject} that loads JSON data from a {@link ResourceLocation}.
            * This method is typically used to load configuration files or other JSON-based resources * in a Minecraft mod environment. - *

            * * @param pResourceLocation {@link ResourceLocation} - The {@link ResourceLocation} of the JSON resource. * @param pResourceManager {@link ResourceManager} - The {@link ResourceManager} used to load the resource. diff --git a/common/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java b/common/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java index 6beaa3f0..725ef360 100644 --- a/common/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java +++ b/common/src/main/java/software/bluelib/utils/conversion/CaseConverterUtils.java @@ -26,6 +26,18 @@ */ public class CaseConverterUtils { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this utility class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private CaseConverterUtils() { + } + /** * A {@link String} that converts a given {@link String} to camelCase. *

            diff --git a/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java b/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java index f6211020..69275a6f 100644 --- a/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java +++ b/common/src/main/java/software/bluelib/utils/conversion/MathConverterUtils.java @@ -29,6 +29,18 @@ */ public class MathConverterUtils { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this utility class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private MathConverterUtils() { + } + /** * A {@link Double} that converts a length from inches to centimeters. * diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java index 56bb022a..d7e17285 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogLevel.java @@ -21,6 +21,19 @@ * @since 1.0.0 */ public class BaseLogLevel { + + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private BaseLogLevel() { + } + /** * Standard informational log level. * diff --git a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java index 87b42958..f0424fed 100644 --- a/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java +++ b/common/src/main/java/software/bluelib/utils/logging/BaseLogger.java @@ -28,11 +28,16 @@ public class BaseLogger { /** - * A {@link Logger} instance for logging messages. + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this class. + *

            * + * @author MeAlam * @since 1.0.0 */ - private static final Logger logger = Logger.getLogger(BlueLibConstants.MOD_NAME); + private BaseLogger() { + } /** * A {@code void} to enable or disable {@code BlueLib} specific logging. @@ -75,7 +80,7 @@ public static void setLoggingEnabled(boolean pEnabled) { } static { - LoggerConfig.configureLogger(logger, new DefaultLogColorProvider()); + LoggerConfig.configureLogger(BlueLibConstants.LOGGER, new DefaultLogColorProvider()); } /** @@ -94,7 +99,7 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable, b pLogLevel == BaseLogLevel.BLUELIB || pIsBlueLib && BlueLibConstants.isBlueLibLoggingEnabled || !pIsBlueLib && BlueLibConstants.isLoggingEnabled) { - logger.log(pLogLevel, pMessage, pThrowable); + BlueLibConstants.LOGGER.log(pLogLevel, pMessage, pThrowable); } } @@ -112,7 +117,7 @@ public static void log(Level pLogLevel, String pMessage, boolean pIsBlueLib) { pLogLevel == BaseLogLevel.BLUELIB || pIsBlueLib && BlueLibConstants.isBlueLibLoggingEnabled || !pIsBlueLib && BlueLibConstants.isLoggingEnabled) { - logger.log(pLogLevel, pMessage); + BlueLibConstants.LOGGER.log(pLogLevel, pMessage); } } @@ -130,7 +135,7 @@ public static void log(Level pLogLevel, String pMessage, Throwable pThrowable) { pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB || BlueLibConstants.isLoggingEnabled) { - logger.log(pLogLevel, pMessage, pThrowable); + BlueLibConstants.LOGGER.log(pLogLevel, pMessage, pThrowable); } } @@ -146,7 +151,7 @@ public static void log(Level pLogLevel, String pMessage) { pLogLevel == BaseLogLevel.WARNING || pLogLevel == BaseLogLevel.BLUELIB || BlueLibConstants.isLoggingEnabled) { - logger.log(pLogLevel, pMessage); + BlueLibConstants.LOGGER.log(pLogLevel, pMessage); } } @@ -157,6 +162,6 @@ public static void log(Level pLogLevel, String pMessage) { * @since 1.0.0 */ public static void logBlueLib(String pMessage) { - logger.log(BaseLogLevel.BLUELIB, pMessage); + BlueLibConstants.LOGGER.log(BaseLogLevel.BLUELIB, pMessage); } } diff --git a/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java b/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java index e314950d..82c38c63 100644 --- a/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/AlgebraicUtils.java @@ -26,6 +26,18 @@ */ public class AlgebraicUtils { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this utility class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private AlgebraicUtils() { + } + /** * A {@link Double}{@code []} that solves the quadratic equation {@code ax^2 + bx + c = 0} * using the quadratic formula. diff --git a/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java b/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java index e2ad0b30..20116480 100644 --- a/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/GeometricUtils.java @@ -29,6 +29,18 @@ */ public class GeometricUtils { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this utility class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private GeometricUtils() { + } + /** * A {@link Double} that calculates the Euclidean distance between two points in 2D space. * diff --git a/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java b/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java index 7c79f265..38d39d65 100644 --- a/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/MatrixUtils.java @@ -21,6 +21,18 @@ */ public class MatrixUtils { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this utility class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private MatrixUtils() { + } + /** * A {@link Double}{@code [][]} that performs matrix multiplication on two matrices. * diff --git a/common/src/main/java/software/bluelib/utils/math/MiscUtils.java b/common/src/main/java/software/bluelib/utils/math/MiscUtils.java index c7e4e572..35729c20 100644 --- a/common/src/main/java/software/bluelib/utils/math/MiscUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/MiscUtils.java @@ -21,6 +21,18 @@ */ public class MiscUtils { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this utility class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private MiscUtils() { + } + /** * A {@link Boolean} that checks if a string is a valid email address. * diff --git a/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java b/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java index 38e88ca4..2c60f24b 100644 --- a/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/RandomGenUtils.java @@ -32,6 +32,18 @@ */ public class RandomGenUtils { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this utility class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private RandomGenUtils() { + } + /** * A {@link Integer} that generates a random integer between a specified minimum and maximum value (inclusive). * diff --git a/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java b/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java index 54d048d8..dcdd1b9b 100644 --- a/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java +++ b/common/src/main/java/software/bluelib/utils/math/StatisticalUtils.java @@ -37,6 +37,18 @@ */ public class StatisticalUtils { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this utility class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private StatisticalUtils() { + } + /** * A {@link Double} that calculates the mean (average) of an array of values. *

            diff --git a/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java b/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java index 3a0896bf..52704d81 100644 --- a/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java +++ b/common/src/main/java/software/bluelib/utils/minecraft/ChunkUtils.java @@ -37,6 +37,18 @@ */ public class ChunkUtils { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this utility class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private ChunkUtils() { + } + /** * A {@link Biome} that retrieves the {@link Biome} of the specified chunk. *

            diff --git a/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java index efe23bd6..da316636 100644 --- a/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java +++ b/common/src/main/java/software/bluelib/utils/variant/ParameterUtils.java @@ -35,6 +35,18 @@ */ public class ParameterUtils { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this utility class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private ParameterUtils() { + } + /** * Holds custom parameters for each variant. *

            diff --git a/fabric/src/main/java/software/bluelib/BlueLib.java b/fabric/src/main/java/software/bluelib/BlueLib.java index fce107db..a3373dd3 100644 --- a/fabric/src/main/java/software/bluelib/BlueLib.java +++ b/fabric/src/main/java/software/bluelib/BlueLib.java @@ -27,6 +27,17 @@ */ public class BlueLib implements ModInitializer { + /** + * Private constructor to prevent instantiation. + *

            + * This constructor is intentionally empty to prevent creating instances of this class. + *

            + * + * @author MeAlam + * @since 1.0.0 + */ + private BlueLib() {} + /** * A {@code private} {@link Boolean} flag indicating whether the mod has been initialized. *

            diff --git a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index f8325ae0..298ef733 100644 --- a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -29,7 +29,6 @@ * This class manages the dragon's variant system, its data synchronization, and integrates with the GeckoLib * animation system. *

            - *

            * Key Methods: *

              *
            • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
            • diff --git a/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index 1ed1b583..a61cf95c 100644 --- a/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -31,8 +31,6 @@ * This class manages the Rex's variant system, its data synchronization, and integrates with the GeckoLib * animation system. *

              - * - *

              * Key Methods: *

                *
              • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
              • @@ -42,7 +40,6 @@ *
              • {@link #setVariantName(String)} - Sets the variant name of the Rex.
              • *
              • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
              • *
              - *

              * * @author MeAlam * @since 1.0.0 diff --git a/fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java b/fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java index 25e83b84..b96a2d0c 100644 --- a/fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java +++ b/fabric/src/main/java/software/bluelib/example/event/ReloadHandler.java @@ -19,15 +19,12 @@ * This class extends {@link ReloadEventHandler} and implements event handling for server starting and reloading, * ensuring that entity variant data is properly loaded and refreshed. *

              - * - *

              * Key Methods: *

                *
              • {@link #onServerStart(MinecraftServer)} - Handles server starting events to initialize entity variants.
              • *
              • {@link #onReload()} - Handles reload events to refresh entity variants.
              • *
              • {@link #LoadEntityVariants(MinecraftServer)} - Loads entity variants from JSON files into the server.
              • *
              - *

              * * @author MeAlam * @since 1.0.0 From 5feddfd180f246eeed5175ceed74c5dd612ac46f Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 9 Oct 2024 14:58:32 +0200 Subject: [PATCH 57/62] Fixed Fabric not loading --- fabric/src/main/java/software/bluelib/BlueLib.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/fabric/src/main/java/software/bluelib/BlueLib.java b/fabric/src/main/java/software/bluelib/BlueLib.java index a3373dd3..fce107db 100644 --- a/fabric/src/main/java/software/bluelib/BlueLib.java +++ b/fabric/src/main/java/software/bluelib/BlueLib.java @@ -27,17 +27,6 @@ */ public class BlueLib implements ModInitializer { - /** - * Private constructor to prevent instantiation. - *

              - * This constructor is intentionally empty to prevent creating instances of this class. - *

              - * - * @author MeAlam - * @since 1.0.0 - */ - private BlueLib() {} - /** * A {@code private} {@link Boolean} flag indicating whether the mod has been initialized. *

              From f3ffe9dd8c051d11b92bc7963aa8442a4fc384f9 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 9 Oct 2024 15:01:54 +0200 Subject: [PATCH 58/62] Removed an old tag --- Forge/src/main/java/software/bluelib/BlueLib.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Forge/src/main/java/software/bluelib/BlueLib.java b/Forge/src/main/java/software/bluelib/BlueLib.java index 4ee00b8e..6d06a5d3 100644 --- a/Forge/src/main/java/software/bluelib/BlueLib.java +++ b/Forge/src/main/java/software/bluelib/BlueLib.java @@ -44,7 +44,6 @@ public class BlueLib { * Constructs a new {@link BlueLib} instance and registers the mod event bus. * * @author MeAlam - * @Co-author Dan * @since 1.0.0 */ public BlueLib() { From bb9a0cf4671be17727b165100c4745904ec34cb6 Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 9 Oct 2024 15:11:09 +0200 Subject: [PATCH 59/62] Added Checks to the Rendering --- .../java/software/bluelib/example/init/ClientInit.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fabric/src/main/java/software/bluelib/example/init/ClientInit.java b/fabric/src/main/java/software/bluelib/example/init/ClientInit.java index 9fe1fa1d..b46334a3 100644 --- a/fabric/src/main/java/software/bluelib/example/init/ClientInit.java +++ b/fabric/src/main/java/software/bluelib/example/init/ClientInit.java @@ -4,6 +4,8 @@ import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; +import software.bluelib.BlueLibCommon; +import software.bluelib.BlueLibConstants; import software.bluelib.example.entity.dragon.DragonRender; import software.bluelib.example.entity.rex.RexRender; @@ -28,7 +30,9 @@ public class ClientInit implements ClientModInitializer { */ @Override public void onInitializeClient() { - EntityRendererRegistry.register(ModEntities.EXAMPLE_ONE, DragonRender::new); - EntityRendererRegistry.register(ModEntities.EXAMPLE_TWO, RexRender::new); + if (BlueLibCommon.isDeveloperMode() && BlueLibCommon.PLATFORM.isModLoaded("geckolib") && BlueLibConstants.isExampleEnabled) { + EntityRendererRegistry.register(ModEntities.EXAMPLE_ONE, DragonRender::new); + EntityRendererRegistry.register(ModEntities.EXAMPLE_TWO, RexRender::new); + } } } From f877d1471530ebe5720f0c47ccd2796c3a08760d Mon Sep 17 00:00:00 2001 From: Aram Date: Wed, 9 Oct 2024 16:51:56 +0200 Subject: [PATCH 60/62] Fixed some comments --- .../software/bluelib/example/entity/dragon/DragonEntity.java | 5 ++--- .../java/software/bluelib/example/entity/rex/RexEntity.java | 3 --- .../software/bluelib/example/entity/dragon/DragonEntity.java | 5 ++--- .../java/software/bluelib/example/entity/rex/RexEntity.java | 3 --- .../software/bluelib/example/entity/dragon/DragonEntity.java | 5 ++--- .../java/software/bluelib/example/entity/rex/RexEntity.java | 3 --- 6 files changed, 6 insertions(+), 18 deletions(-) diff --git a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 5f9d893f..111d04c2 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/Forge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -34,10 +34,9 @@ * * Key Methods: *

                - *
              • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
              • - *
              • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
              • - *
              • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
              • *
              • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
              • + *
              • {@link #setVariantName(String)} - Sets the variant name of the Rex.
              • + *
              • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
              • *
              * * @author MeAlam diff --git a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index 89f1bdda..58a2cc27 100644 --- a/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/Forge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -33,9 +33,6 @@ *

              * Key Methods: *
                - *
              • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
              • - *
              • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
              • - *
              • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
              • *
              • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
              • *
              • {@link #setVariantName(String)} - Sets the variant name of the Rex.
              • *
              • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
              • diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 5f9d893f..111d04c2 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -34,10 +34,9 @@ * * Key Methods: *
                  - *
                • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
                • - *
                • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
                • - *
                • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
                • *
                • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
                • + *
                • {@link #setVariantName(String)} - Sets the variant name of the Rex.
                • + *
                • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
                • *
                * * @author MeAlam diff --git a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index ea368713..8f8ce9c0 100644 --- a/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/NeoForge/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -34,9 +34,6 @@ * * Key Methods: *
                  - *
                • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
                • - *
                • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
                • - *
                • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
                • *
                • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
                • *
                • {@link #setVariantName(String)} - Sets the variant name of the Rex.
                • *
                • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
                • diff --git a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java index 298ef733..b413123b 100644 --- a/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java +++ b/fabric/src/main/java/software/bluelib/example/entity/dragon/DragonEntity.java @@ -31,10 +31,9 @@ *

                  * Key Methods: *
                    - *
                  • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the dragon entity, including its variant.
                  • - *
                  • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
                  • - *
                  • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
                  • *
                  • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
                  • + *
                  • {@link #setVariantName(String)} - Sets the variant name of the Rex.
                  • + *
                  • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
                  • *
                  * * @author MeAlam diff --git a/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java b/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java index a61cf95c..94023ba2 100644 --- a/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java +++ b/fabric/src/main/java/software/bluelib/example/entity/rex/RexEntity.java @@ -33,9 +33,6 @@ *

                  * Key Methods: *
                    - *
                  • {@link #defineSynchedData(SynchedEntityData.Builder)} - Defines the synchronized data for the Rex entity, including its variant.
                  • - *
                  • {@link #addAdditionalSaveData(CompoundTag)} - Adds custom data to the entity's NBT for saving.
                  • - *
                  • {@link #readAdditionalSaveData(CompoundTag)} - Reads custom data from the entity's NBT for loading.
                  • *
                  • {@link #finalizeSpawn(ServerLevelAccessor, DifficultyInstance, MobSpawnType, SpawnGroupData)} - Finalizes the spawning process and sets up parameters.
                  • *
                  • {@link #setVariantName(String)} - Sets the variant name of the Rex.
                  • *
                  • {@link #getVariantName()} - Retrieves the current variant name of the Rex.
                  • From 30430a95607cadea79596edc85ba32e0d29dd0cd Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 24 Oct 2024 13:20:08 +0200 Subject: [PATCH 61/62] Updated README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 618c966c..6ff35f0e 100644 --- a/README.md +++ b/README.md @@ -65,4 +65,10 @@

                    Discord

                    +

                    + BlueLib Licence  + BlueLib Release  + BlueLib Commit Activity  +

                    + From 6a3ad5655f9f888069850b097e939dc5dfb60a3e Mon Sep 17 00:00:00 2001 From: Aram Date: Thu, 24 Oct 2024 13:21:49 +0200 Subject: [PATCH 62/62] Added Fabric to ReadMe --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 6ff35f0e..96c38d62 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Neoforge Forge + Fabric @@ -29,6 +30,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
                    VersionSupport
                    1.16.5Active
                    1.18.2Active
                    1.20.xActive
                    1.21.xActive
                    +