diff --git a/LICENSE_SBLForked b/LICENSE_SBLForked deleted file mode 100644 index a612ad981..000000000 --- a/LICENSE_SBLForked +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/buildSrc/src/main/groovy/multiloader-common.gradle b/buildSrc/src/main/groovy/multiloader-common.gradle index 3e94563dd..85f092448 100644 --- a/buildSrc/src/main/groovy/multiloader-common.gradle +++ b/buildSrc/src/main/groovy/multiloader-common.gradle @@ -1,4 +1,5 @@ plugins { + id 'com.diffplug.spotless' id 'java-library' id 'maven-publish' id 'idea' @@ -143,4 +144,18 @@ idea { downloadSources = true downloadJavadoc = true } -} \ No newline at end of file +} + +spotless { + java { + eclipse().configFile("$rootDir/eclipse-formatter.xml") + endWithNewline() + importOrder("", "java", group.toString(), "\\#") + indentWithSpaces(4) + removeUnusedImports() + trimTrailingWhitespace() + } +} +tasks.build { + dependsOn("spotlessApply") +} diff --git a/changelog.md b/changelog.md index 55f6d406c..e3d042973 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,50 @@ -v2.3.27 +v3.0.0 -- Remove format version check, unneeded -- Add GeoItemRender#useNewOffset() which will remove the y offset on item displays, due to change in BlockBench 4.11 item displays \ No newline at end of file +- Rewrite Entity animation system. See guide for converting here: + - No longer have to supply a cache. + - No longer have to use a GeoEnity interface. +- Rewrite Item animation system. See guide for converting here: + - Fixes issue with Item animations not working the first time due to missing NBT tag check. + - No longer have to supply a cache. + - No longer have to use a GeoItem interface. + - "Item" rendering/animating is now considered "ItemStack" rendering/animating. + - No longer register the render in the Item. + - This is done in your clients onInitializeClient for Fabric and NeoForges FMLClientSetupEvent using AzItemRendererRegistry#register. +- Rewrite Block Entity animation system. See guide for converting here: + - No longer have to supply a cache. + - No longer have to use a GeoEntity interface. +- Rewrite Armor animation system. See guide for converting here: + - No longer have to supply a cache. + - No longer have to use a GeoItem interface. + - "Item" rendering/animating is now considered "ItemStack" rendering/animating. + - No longer register the render in the Item. + - This is done in your clients onInitializeClient for Fabric and NeoForges FMLClientSetupEvent using AzArmorRendererRegistry#register. +- Animations are now done fully using a trigger animation call from the AzAnimator, which is set in your class like so: +```java +public class PistolItem extends Item { + + private final CustomAzItemAnimator dispatcher; + + public PistolItem() { + super(new Properties().stacksTo(1)); + this.dispatcher = new CustomAzItemAnimator(); + } + + public void exampleMethod(Level level) { + if (level.isClientSide()) { + this.dispatcher.fromClient(FIRING_COMMAND).sendForItem(entity, itemStack); + } else { + this.dispatcher.fromServer(FIRING_COMMAND).sendForItem(entity, itemStack); + } + } +} +``` +- New system fixes Animations not firing properly on Items on first use. + - You have to now register your item in your mods onInitialize for Fabric and NeoForges FMLCommonSetupEvent using AzIdentityRegistry#register + - AzIdentityRegistry#register can take 1 item or multiple if you have a lot of item. +- New system fixes Aniamtions not pausing correctly when in singleplayer. (Old system/Geckolib "pauses" it but it still ticks so doesn't hold the animations spot properly) +- New system fixes Animation triggers not working with armors. +- New system shows about a 40% drop in memory usage compared to old systems/Azurelib. +- Move to new Az Naming scheme from Geo +- No longer ship with a forked SBL, no longer being used in my mods moving forward. +- MORE WIP \ No newline at end of file diff --git a/common/build.gradle b/common/build.gradle index 5a448f365..028722d21 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,6 +1,7 @@ plugins { id 'multiloader-common' id 'net.neoforged.moddev' + id 'com.diffplug.spotless' version "7.0.0.BETA3" } neoForge { @@ -42,4 +43,4 @@ configurations { artifacts { commonJava sourceSets.main.java.sourceDirectories.singleFile commonResources sourceSets.main.resources.sourceDirectories.singleFile -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/helper/ClientUtils.java b/common/src/main/java/mod/azure/azurelib/common/api/client/helper/ClientUtils.java index 543d98313..95e80520b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/helper/ClientUtils.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/helper/ClientUtils.java @@ -2,7 +2,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; import net.minecraft.util.Mth; @@ -10,6 +9,8 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; + /** * Helper class for segregating client-side code */ @@ -19,10 +20,12 @@ public record ClientUtils() { * Common reload KeyMapping for my various mods */ public static KeyMapping RELOAD; + /** * Common scope KeyMapping for my various mods */ public static KeyMapping SCOPE; + /** * Common scope KeyMapping for my various mods */ diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java index 7f20fd9fe..52cc7b8a5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedBlockGeoModel.java @@ -1,19 +1,19 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.model; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * {@link DefaultedGeoModel} specific to {@link net.minecraft.world.level.block.Block Blocks}. Using this class * pre-sorts provided asset paths into the "block" subdirectory */ +@Deprecated(forRemoval = true) public class DefaultedBlockGeoModel extends DefaultedGeoModel { /** diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java index 7e37ccf4b..b34ec1424 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedEntityGeoModel.java @@ -1,25 +1,25 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.model; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; + import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; import mod.azure.azurelib.common.internal.common.constant.DataTickets; import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animation.AnimationState; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; /** * {@link DefaultedGeoModel} specific to {@link net.minecraft.world.entity.Entity Entities}. Using this class pre-sorts * provided asset paths into the "entity" subdirectory Additionally it can automatically handle head-turning if the * entity has a "head" bone */ +@Deprecated(forRemoval = true) public class DefaultedEntityGeoModel extends DefaultedGeoModel { private final boolean turnsHead; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java index 8c63be7b4..14891b926 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedGeoModel.java @@ -1,20 +1,20 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.model; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Defaulted model class for AzureLib models.
* This class allows for minimal boilerplate when implementing basic models, and saves on new classes.
* Additionally, it encourages consistency and sorting of asset paths. */ +@Deprecated(forRemoval = true) public abstract class DefaultedGeoModel extends GeoModel { private ResourceLocation modelPath; @@ -81,14 +81,15 @@ public DefaultedGeoModel withAltTexture(ResourceLocation altPath) { * @param basePath The base path of your resource. E.G. * *
{@code ResourceLocation.fromNamespaceAndPath(MyMod.MOD_ID, "animal/goat")}
+ * * @return The formatted model resource path based on recommended defaults. E.G. * - *
{@code "mymod:geo/entity/animal/goat.geo.json"}
+ *
{@code "mymod:geo/entity/animal/goat.geo.json"}
*/ public ResourceLocation buildFormattedModelPath(ResourceLocation basePath) { return ResourceLocation.fromNamespaceAndPath( - basePath.getNamespace(), - "geo/" + subtype() + "/" + basePath.getPath() + ".geo.json" + basePath.getNamespace(), + "geo/" + subtype() + "/" + basePath.getPath() + ".geo.json" ); } @@ -99,14 +100,15 @@ public ResourceLocation buildFormattedModelPath(ResourceLocation basePath) { * @param basePath The base path of your resource. E.G. * *
{@code ResourceLocation.fromNamespaceAndPath(MyMod.MOD_ID, "animal/goat")}
+ * * @return The formatted animation resource path based on recommended defaults. E.G. * - *
{@code "mymod:animations/entity/animal/goat.animation.json"}
+ *
{@code "mymod:animations/entity/animal/goat.animation.json"}
*/ public ResourceLocation buildFormattedAnimationPath(ResourceLocation basePath) { return ResourceLocation.fromNamespaceAndPath( - basePath.getNamespace(), - "animations/" + subtype() + "/" + basePath.getPath() + ".animation.json" + basePath.getNamespace(), + "animations/" + subtype() + "/" + basePath.getPath() + ".animation.json" ); } @@ -117,14 +119,15 @@ public ResourceLocation buildFormattedAnimationPath(ResourceLocation basePath) { * @param basePath The base path of your resource. E.G. * *
{@code ResourceLocation.fromNamespaceAndPath(MyMod.MOD_ID, "animal/goat")}
+ * * @return The formatted texture resource path based on recommended defaults. E.G. * - *
{@code "mymod:textures/entity/animal/goat.png"}
+ *
{@code "mymod:textures/entity/animal/goat.png"}
*/ public ResourceLocation buildFormattedTexturePath(ResourceLocation basePath) { return ResourceLocation.fromNamespaceAndPath( - basePath.getNamespace(), - "textures/" + subtype() + "/" + basePath.getPath() + ".png" + basePath.getNamespace(), + "textures/" + subtype() + "/" + basePath.getPath() + ".png" ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java index c98555197..c85f75de1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/DefaultedItemGeoModel.java @@ -1,19 +1,19 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.model; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * {@link DefaultedGeoModel} specific to {@link net.minecraft.world.item.Item Items}. Using this class pre-sorts * provided asset paths into the "item" subdirectory */ +@Deprecated(forRemoval = true) public class DefaultedItemGeoModel extends DefaultedGeoModel { /** diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java b/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java index eb8cb7c9c..67d13afe4 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/model/GeoModel.java @@ -1,12 +1,21 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.model; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.phys.Vec3; + +import java.util.Optional; +import java.util.function.BiConsumer; + import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.AzureLibException; @@ -24,21 +33,12 @@ import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.MolangQueries; import mod.azure.azurelib.core.object.DataTicket; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.phys.Vec3; - -import java.util.Optional; -import java.util.function.BiConsumer; /** * Base class for all code-based model objects.
* All models to registered to a {@link GeoRenderer} should be an instance of this or one of its subclasses. */ +@Deprecated(forRemoval = true) public abstract class GeoModel implements CoreGeoModel { private final AnimationProcessor processor = new AnimationProcessor<>(this); @@ -144,8 +144,7 @@ public AnimationProcessor getAnimationProcessor() { * @param instanceId The unique instance id of the animatable being animated * @param dataConsumer The DataTicket + data consumer to be added to the AnimationEvent */ - public void addAdditionalStateData(T animatable, long instanceId, BiConsumer, T> dataConsumer) { - } + public void addAdditionalStateData(T animatable, long instanceId, BiConsumer, T> dataConsumer) {} @Override public void handleAnimations(T animatable, long instanceId, AnimationState animationState) { @@ -155,15 +154,15 @@ public void handleAnimations(T animatable, long instanceId, AnimationState an if (currentTick == null) currentTick = animatable instanceof LivingEntity livingEntity - ? (double) livingEntity.tickCount - : RenderUtils.getCurrentTick(); + ? (double) livingEntity.tickCount + : RenderUtils.getCurrentTick(); if (animatableManager.getFirstTickTime() == -1) animatableManager.startedAt(currentTick + mc.getTimer().getGameTimeDeltaTicks()); double currentFrameTime = currentTick - animatableManager.getFirstTickTime(); boolean isReRender = !animatableManager.isFirstTick() && currentFrameTime == animatableManager - .getLastUpdateTime(); + .getLastUpdateTime(); if (isReRender && instanceId == this.lastRenderedInstance) return; @@ -187,12 +186,12 @@ public void handleAnimations(T animatable, long instanceId, AnimationState an if (!processor.getRegisteredBones().isEmpty()) processor.tickAnimation( - animatable, - this, - animatableManager, - this.animTime, - animationState, - crashIfBoneMissing() + animatable, + this, + animatableManager, + this.animTime, + animationState, + crashIfBoneMissing() ); setCustomAnimations(animatable, instanceId, animationState); @@ -210,12 +209,15 @@ public void applyMolangQueries(T animatable, double animTime) { if (animatable instanceof Entity entity) { parser.setMemoizedValue( - MolangQueries.DISTANCE_FROM_CAMERA, - () -> mc.gameRenderer.getMainCamera().getPosition().distanceTo(entity.position()) + MolangQueries.DISTANCE_FROM_CAMERA, + () -> mc.gameRenderer.getMainCamera().getPosition().distanceTo(entity.position()) ); parser.setMemoizedValue(MolangQueries.IS_ON_GROUND, () -> RenderUtils.booleanToFloat(entity.onGround())); parser.setMemoizedValue(MolangQueries.IS_IN_WATER, () -> RenderUtils.booleanToFloat(entity.isInWater())); - parser.setMemoizedValue(MolangQueries.IS_IN_WATER_OR_RAIN, () -> RenderUtils.booleanToFloat(entity.isInWaterOrRain())); + parser.setMemoizedValue( + MolangQueries.IS_IN_WATER_OR_RAIN, + () -> RenderUtils.booleanToFloat(entity.isInWaterOrRain()) + ); parser.setMemoizedValue(MolangQueries.IS_ON_FIRE, () -> RenderUtils.booleanToFloat(entity.isOnFire())); if (entity instanceof LivingEntity livingEntity) { diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DyeableGeoArmorRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DyeableGeoArmorRenderer.java index 5b3b6554a..57d05b5b5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DyeableGeoArmorRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DyeableGeoArmorRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -10,11 +8,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.objects.ObjectArraySet; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.core.object.Color; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.util.FastColor; import net.minecraft.world.item.Item; @@ -24,12 +17,19 @@ import java.util.Collection; import java.util.Set; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.core.object.Color; + /** * A dyeable armour renderer for AzureLib armor models. */ public abstract class DyeableGeoArmorRenderer extends GeoArmorRenderer { protected final Set dyeableBones = new ObjectArraySet<>(); + protected BakedGeoModel lastModel = null; protected DyeableGeoArmorRenderer(GeoModel model) { @@ -38,28 +38,28 @@ protected DyeableGeoArmorRenderer(GeoModel model) { @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - @Nullable MultiBufferSource bufferSource, - @Nullable VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + @Nullable MultiBufferSource bufferSource, + @Nullable VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { super.preRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); if (!isReRender) @@ -68,12 +68,12 @@ public void preRender( @Override public void renderCubesOfBone( - PoseStack poseStack, - GeoBone bone, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.dyeableBones.contains(bone)) { final Color color = getColorForBone(bone); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DynamicGeoEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DynamicGeoEntityRenderer.java index 4372ce219..1d08ec5f0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DynamicGeoEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/DynamicGeoEntityRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -11,10 +9,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRendererProvider; @@ -27,6 +21,11 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Extended special-entity renderer for more advanced or dynamic models.
* Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider @@ -35,7 +34,7 @@ public abstract class DynamicGeoEntityRenderer extends GeoEntityRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; @@ -67,11 +66,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -82,14 +81,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -99,17 +98,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -123,10 +122,10 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.animatable.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.animatable.position().toVector3f()) ); } @@ -134,14 +133,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -151,49 +150,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -205,30 +204,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -239,23 +238,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -266,13 +265,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -280,23 +279,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java index 3274835d7..d72974d89 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRenderer.java @@ -1,28 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; -import mod.azure.azurelib.core.object.Color; import net.minecraft.client.Minecraft; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.ModelLayers; @@ -43,6 +27,21 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; +import mod.azure.azurelib.core.object.Color; + /** * Base {@link GeoRenderer} for rendering in-world armor specifically.
* All custom armor added to be rendered in-world by AzureLib should use an instance of this class. @@ -50,18 +49,27 @@ * @param * @see GeoItem */ +@Deprecated(forRemoval = true) public class GeoArmorRenderer extends HumanoidModel implements GeoRenderer { protected final GeoRenderLayersContainer renderLayers = new GeoRenderLayersContainer<>(this); protected final GeoModel model; + public BakedGeoModel lastModel = null; + protected T animatable; + protected HumanoidModel baseModel; + protected float scaleWidth = 1; + protected float scaleHeight = 1; + protected Matrix4f entityRenderTranslations = new Matrix4f(); + protected Matrix4f modelRenderTranslations = new Matrix4f(); + protected GeoBone head = null; protected GeoBone body = null; @@ -143,10 +151,10 @@ public long getInstanceId(T animatable) { */ @Override public RenderType getRenderType( - T animatable, - ResourceLocation texture, - @org.jetbrains.annotations.Nullable MultiBufferSource bufferSource, - float partialTick + T animatable, + ResourceLocation texture, + @org.jetbrains.annotations.Nullable MultiBufferSource bufferSource, + float partialTick ) { return RenderType.armorCutoutNoCull(texture); } @@ -280,16 +288,16 @@ public GeoBone getLeftBootBone() { */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - @Nullable MultiBufferSource bufferSource, - @Nullable VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + @Nullable MultiBufferSource bufferSource, + @Nullable VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.entityRenderTranslations = new Matrix4f(poseStack.last().pose()); @@ -298,15 +306,15 @@ public void preRender( applyBaseTransformations(this.baseModel); scaleModelForBaby(poseStack, animatable, partialTick, isReRender); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); if (!(this.currentEntity instanceof GeoAnimatable)) @@ -320,34 +328,37 @@ public void preRender( */ @Override public Color getRenderColor(T animatable, float partialTick, int packedLight) { - return this.currentStack.is(ItemTags.DYEABLE) ? Color.ofOpaque( - DyedItemColor.getOrDefault(this.currentStack, -6265536)) : Color.WHITE; + return this.currentStack.is(ItemTags.DYEABLE) + ? Color.ofOpaque( + DyedItemColor.getOrDefault(this.currentStack, -6265536) + ) + : Color.WHITE; } @Override public void renderToBuffer( - @NotNull PoseStack poseStack, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int var5 + @NotNull PoseStack poseStack, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int var5 ) { Minecraft mc = Minecraft.getInstance(); MultiBufferSource bufferSource = Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); if ( - Minecraft.getInstance().levelRenderer.shouldShowEntityOutlines() && mc.shouldEntityAppearGlowing( - this.currentEntity - ) + Minecraft.getInstance().levelRenderer.shouldShowEntityOutlines() && mc.shouldEntityAppearGlowing( + this.currentEntity + ) ) bufferSource = Minecraft.getInstance().levelRenderer.renderBuffers.outlineBufferSource(); float partialTick = mc.getTimer().getGameTimeDeltaTicks(); RenderType renderType = getRenderType( - this.animatable, - getTextureLocation(this.animatable), - bufferSource, - partialTick + this.animatable, + getTextureLocation(this.animatable), + bufferSource, + partialTick ); buffer = ItemRenderer.getArmorFoilBuffer(bufferSource, renderType, this.currentStack.hasFoil()); @@ -361,17 +372,17 @@ public void renderToBuffer( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); poseStack.translate(0, 24 / 16f, 0); @@ -392,17 +403,17 @@ public void actuallyRender( this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); } @@ -412,17 +423,17 @@ public void actuallyRender( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); @@ -431,22 +442,22 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix(RenderUtils.translateMatrix(localMatrix, GeoArmorRendererConstants.ZERO)); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) ); } GeoRenderer.super.renderRecursively( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -480,10 +491,10 @@ protected void grabRelevantBones(BakedGeoModel bakedModel) { * @param baseModel The default (vanilla) model that would have been rendered if this model hadn't replaced it */ public void prepForRender( - @Nullable Entity entity, - ItemStack stack, - @Nullable EquipmentSlot slot, - @Nullable HumanoidModel baseModel + @Nullable Entity entity, + ItemStack stack, + @Nullable EquipmentSlot slot, + @Nullable HumanoidModel baseModel ) { if (entity == null || slot == null || baseModel == null) return; @@ -680,8 +691,8 @@ protected void setBoneVisible(@Nullable GeoBone bone, boolean visible) { public void updateAnimatedTextureFrame(T animatable) { if (this.currentEntity != null) AnimatableTexture.setAndUpdate( - getTextureLocation(animatable), - this.currentEntity.getId() + this.currentEntity.tickCount + getTextureLocation(animatable), + this.currentEntity.getId() + this.currentEntity.tickCount ); } @@ -700,13 +711,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireArmorPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireArmorPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -714,12 +732,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireArmorPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireArmorPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRendererConstants.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRendererConstants.java index e5c912312..6907787ed 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRendererConstants.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoArmorRendererConstants.java @@ -6,6 +6,7 @@ /** * @author Boston Vanseghi */ +@Deprecated(forRemoval = true) public class GeoArmorRendererConstants { public static final String BONE_ARMOR_BODY_NAME = "armorBody"; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java index b5944ab64..7ff2435e0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoBlockRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -11,18 +9,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; @@ -38,10 +24,24 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; + /** * Base {@link GeoRenderer} class for rendering {@link BlockEntity Blocks} specifically.
* All blocks added to be rendered by AzureLib should use an instance of this class. */ +@Deprecated(forRemoval = true) public class GeoBlockRenderer implements GeoRenderer, BlockEntityRenderer { protected final GeoModel model; @@ -128,40 +128,40 @@ public GeoBlockRenderer withScale(float scaleWidth, float scaleHeight) { */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.blockRenderTranslations = new Matrix4f(poseStack.last().pose()); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); } @Override public void render( - T animatable, - float partialTick, - PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight, - int packedOverlay + T animatable, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight, + int packedOverlay ) { this.animatable = animatable; @@ -175,17 +175,17 @@ public void render( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (!isReRender) { AnimationState animationState = new AnimationState(animatable, 0, 0, partialTick, false); @@ -203,17 +203,17 @@ public void actuallyRender( RenderSystem.setShaderTexture(0, getTextureLocation(animatable)); GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -222,17 +222,17 @@ public void actuallyRender( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); @@ -240,32 +240,32 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix( - new Matrix4f(localMatrix), - new Vector3f( - this.animatable.getBlockPos().getX(), - this.animatable.getBlockPos().getY(), - this.animatable.getBlockPos().getZ() - ) + RenderUtils.translateMatrix( + new Matrix4f(localMatrix), + new Vector3f( + this.animatable.getBlockPos().getX(), + this.animatable.getBlockPos().getY(), + this.animatable.getBlockPos().getZ() ) + ) ); } GeoRenderer.super.renderRecursively( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -312,9 +312,9 @@ protected Direction getFacing(T block) { @Override public void updateAnimatedTextureFrame(T animatable) { AnimatableTexture.setAndUpdate( - getTextureLocation(animatable), - animatable.getBlockPos().getX() + animatable.getBlockPos().getY() + animatable.getBlockPos().getZ() - + (int) animatable.getTick(animatable) + getTextureLocation(animatable), + animatable.getBlockPos().getX() + animatable.getBlockPos().getY() + animatable.getBlockPos().getZ() + + (int) animatable.getTick(animatable) ); } @@ -333,13 +333,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireBlockPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireBlockPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -347,12 +354,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireBlockPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireBlockPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java index 98cd65b9c..9558e5ef3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoEntityRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -12,18 +10,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; @@ -47,11 +33,25 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; + /** * Base {@link GeoRenderer} class for rendering {@link Entity Entities} specifically.
* All entities added to be rendered by AzureLib should use an instance of this class.
* This also includes {@link net.minecraft.world.entity.projectile.Projectile Projectiles} */ +@Deprecated(forRemoval = true) public class GeoEntityRenderer extends EntityRenderer implements GeoRenderer { protected final List> renderLayers = new ObjectArrayList<>(); @@ -80,21 +80,21 @@ public GeoEntityRenderer(EntityRendererProvider.Context renderManager, GeoModel< * duplicated here for flexible usage */ private static void renderLeashPiece( - VertexConsumer buffer, - Matrix4f positionMatrix, - float xDif, - float yDif, - float zDif, - int entityBlockLight, - int holderBlockLight, - int entitySkyLight, - int holderSkyLight, - float width, - float yOffset, - float xOffset, - float zOffset, - int segment, - boolean isLeashKnot + VertexConsumer buffer, + Matrix4f positionMatrix, + float xDif, + float yDif, + float zDif, + int entityBlockLight, + int holderBlockLight, + int entitySkyLight, + int holderSkyLight, + float width, + float yOffset, + float xOffset, + float zOffset, + int segment, + boolean isLeashKnot ) { float piecePosPercent = segment / 24f; int lerpBlockLight = (int) Mth.lerp(piecePosPercent, entityBlockLight, holderBlockLight); @@ -106,20 +106,20 @@ private static void renderLeashPiece( float blue = 0.3f * knotColourMod; float x = xDif * piecePosPercent; float y = yDif > 0.0f - ? yDif * piecePosPercent * piecePosPercent - : yDif - yDif * (1.0f - piecePosPercent) * (1.0f - piecePosPercent); + ? yDif * piecePosPercent * piecePosPercent + : yDif - yDif * (1.0f - piecePosPercent) * (1.0f - piecePosPercent); float z = zDif * piecePosPercent; buffer.addVertex(positionMatrix, x - xOffset, y + yOffset, z + zOffset) - .setColor(red, green, blue, 1) - .setLight( - packedLight - ); + .setColor(red, green, blue, 1) + .setLight( + packedLight + ); buffer.addVertex(positionMatrix, x + xOffset, y + width - yOffset, z - zOffset) - .setColor(red, green, blue, 1) - .setLight( - packedLight - ); + .setColor(red, green, blue, 1) + .setLight( + packedLight + ); } /** @@ -197,40 +197,40 @@ public GeoEntityRenderer withScale(float scaleWidth, float scaleHeight) { */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.entityRenderTranslations = new Matrix4f(poseStack.last().pose()); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); } @Override public void render( - T entity, - float entityYaw, - float partialTick, - PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight + T entity, + float entityYaw, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight ) { this.animatable = entity; @@ -244,17 +244,17 @@ public void render( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); @@ -262,19 +262,19 @@ public void actuallyRender( boolean shouldSit = animatable.isPassenger() && (animatable.getVehicle() != null); float lerpBodyRot = livingEntity == null - ? 0 - : Mth.rotLerp( + ? 0 + : Mth.rotLerp( partialTick, livingEntity.yBodyRotO, livingEntity.yBodyRot - ); + ); float lerpHeadRot = livingEntity == null - ? 0 - : Mth.rotLerp( + ? 0 + : Mth.rotLerp( partialTick, livingEntity.yHeadRotO, livingEntity.yHeadRot - ); + ); float netHeadYaw = lerpHeadRot - lerpBodyRot; if (shouldSit && animatable.getVehicle() instanceof LivingEntity livingentity) { @@ -296,9 +296,9 @@ public void actuallyRender( float eyePosOffset = livingEntity.getEyeHeight(Pose.STANDING) - 0.1F; poseStack.translate( - -bedDirection.getStepX() * eyePosOffset, - 0, - -bedDirection.getStepZ() * eyePosOffset + -bedDirection.getStepX() * eyePosOffset, + 0, + -bedDirection.getStepZ() * eyePosOffset ); } } @@ -313,9 +313,9 @@ public void actuallyRender( if (!shouldSit && animatable.isAlive() && livingEntity != null) { limbSwingAmount = Mth.lerp( - partialTick, - livingEntity.walkAnimation.speedOld, - livingEntity.walkAnimation.speed() + partialTick, + livingEntity.walkAnimation.speedOld, + livingEntity.walkAnimation.speed() ); limbSwing = livingEntity.walkAnimation.position() - livingEntity.walkAnimation.speed() * (1 - partialTick); @@ -332,24 +332,24 @@ public void actuallyRender( Vec3 velocity = animatable.getDeltaMovement(); float avgVelocity = (float) (Math.abs(velocity.x) + Math.abs(velocity.z) / 2f); AnimationState animationState = new AnimationState( - animatable, - limbSwing, - limbSwingAmount, - partialTick, - avgVelocity >= motionThreshold && limbSwingAmount != 0 + animatable, + limbSwing, + limbSwingAmount, + partialTick, + avgVelocity >= motionThreshold && limbSwingAmount != 0 ); long instanceId = getInstanceId(animatable); animationState.setData(DataTickets.TICK, animatable.getTick(animatable)); animationState.setData(DataTickets.ENTITY, animatable); animationState.setData( - DataTickets.ENTITY_MODEL_DATA, - new EntityModelData( - shouldSit, - livingEntity != null && livingEntity.isBaby(), - -netHeadYaw, - -headPitch - ) + DataTickets.ENTITY_MODEL_DATA, + new EntityModelData( + shouldSit, + livingEntity != null && livingEntity.isBaby(), + -netHeadYaw, + -headPitch + ) ); this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); this.model.handleAnimations(animatable, instanceId, animationState); @@ -359,17 +359,17 @@ public void actuallyRender( if (!animatable.isInvisibleTo(Minecraft.getInstance().player)) GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -380,27 +380,27 @@ public void actuallyRender( */ @Override public void applyRenderLayers( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { if (!animatable.isSpectator()) GeoRenderer.super.applyRenderLayers( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay ); } @@ -410,15 +410,15 @@ public void applyRenderLayers( */ @Override public void renderFinal( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { super.render(animatable, 0, partialTick, poseStack, bufferSource, packedLight); @@ -435,17 +435,17 @@ public void renderFinal( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -459,10 +459,10 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.animatable.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.animatable.position().toVector3f()) ); } @@ -475,54 +475,62 @@ public void renderRecursively( if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); } /** - * Applies rotation transformations to the renderer prior to render time to account for various entity states, default scale of 1 + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * default scale of 1 */ protected void applyRotations( - T animatable, - PoseStack poseStack, - float ageInTicks, - float rotationYaw, - float partialTick + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick ) { applyRotations(animatable, poseStack, ageInTicks, rotationYaw, partialTick, 1); } /** - * Applies rotation transformations to the renderer prior to render time to account for various entity states, scalable + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * scalable */ - protected void applyRotations(T animatable, PoseStack poseStack, float ageInTicks, float rotationYaw, - float partialTick, float nativeScale) { + protected void applyRotations( + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick, + float nativeScale + ) { if (isShaking(animatable)) - rotationYaw += (float)(Math.cos(animatable.tickCount * 3.25d) * Math.PI * 0.4d); + rotationYaw += (float) (Math.cos(animatable.tickCount * 3.25d) * Math.PI * 0.4d); if (!animatable.hasPose(Pose.SLEEPING)) poseStack.mulPose(Axis.YP.rotationDegrees(180f - rotationYaw)); @@ -531,20 +539,23 @@ protected void applyRotations(T animatable, PoseStack poseStack, float ageInTick if (livingEntity.deathTime > 0) { float deathRotation = (livingEntity.deathTime + partialTick - 1f) / 20f * 1.6f; - poseStack.mulPose(Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable))); - } - else if (livingEntity.isAutoSpinAttack()) { + poseStack.mulPose( + Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable)) + ); + } else if (livingEntity.isAutoSpinAttack()) { poseStack.mulPose(Axis.XP.rotationDegrees(-90f - livingEntity.getXRot())); poseStack.mulPose(Axis.YP.rotationDegrees((livingEntity.tickCount + partialTick) * -75f)); - } - else if (animatable.hasPose(Pose.SLEEPING)) { + } else if (animatable.hasPose(Pose.SLEEPING)) { Direction bedOrientation = livingEntity.getBedOrientation(); - poseStack.mulPose(Axis.YP.rotationDegrees(bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw)); + poseStack.mulPose( + Axis.YP.rotationDegrees( + bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw + ) + ); poseStack.mulPose(Axis.ZP.rotationDegrees(getDeathMaxRotation(animatable))); poseStack.mulPose(Axis.YP.rotationDegrees(270f)); - } - else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { + } else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { poseStack.translate(0, (animatable.getBbHeight() + 0.1f) / nativeScale, 0); poseStack.mulPose(Axis.ZP.rotationDegrees(180f)); } @@ -576,8 +587,8 @@ public boolean shouldShowName(T animatable) { return false; if ( - animatable instanceof Mob && (!animatable.shouldShowName() && (!animatable.hasCustomName() - || animatable != this.entityRenderDispatcher.crosshairPickEntity)) + animatable instanceof Mob && (!animatable.shouldShowName() && (!animatable.hasCustomName() + || animatable != this.entityRenderDispatcher.crosshairPickEntity)) ) return false; @@ -587,7 +598,7 @@ public boolean shouldShowName(T animatable) { if (entityTeam == null) return Minecraft.renderNames() && animatable != minecraft.getCameraEntity() && visibleToClient - && !animatable.isVehicle(); + && !animatable.isVehicle(); var playerTeam = minecraft.player.getTeam(); @@ -595,12 +606,12 @@ public boolean shouldShowName(T animatable) { case ALWAYS -> visibleToClient; case NEVER -> false; case HIDE_FOR_OTHER_TEAMS -> playerTeam == null - ? visibleToClient - : entityTeam.isAlliedTo( + ? visibleToClient + : entityTeam.isAlliedTo( playerTeam - ) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); + ) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); case HIDE_FOR_OWN_TEAM -> - playerTeam == null ? visibleToClient : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; + playerTeam == null ? visibleToClient : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; }; } @@ -623,11 +634,11 @@ public int getPackedOverlay(T animatable, float u, float partialTick) { * duplicated here for flexible usage */ public void renderLeash( - M mob, - float partialTick, - PoseStack poseStack, - MultiBufferSource bufferSource, - E leashHolder + M mob, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + E leashHolder ) { double lerpBodyAngle = (Mth.lerp(partialTick, mob.yBodyRotO, mob.yBodyRot) * Mth.DEG_TO_RAD) + Mth.HALF_PI; Vec3 leashOffset = mob.getLeashOffset(); @@ -648,11 +659,11 @@ public void renderLeash( BlockPos holderEyePos = BlockPos.containing(leashHolder.getEyePosition(partialTick)); int entityBlockLight = getBlockLightLevel((T) mob, entityEyePos); int holderBlockLight = leashHolder.isOnFire() - ? 15 - : leashHolder.level() + ? 15 + : leashHolder.level() .getBrightness( - LightLayer.BLOCK, - holderEyePos + LightLayer.BLOCK, + holderEyePos ); int entitySkyLight = mob.level().getBrightness(LightLayer.SKY, entityEyePos); int holderSkyLight = mob.level().getBrightness(LightLayer.SKY, holderEyePos); @@ -664,41 +675,41 @@ public void renderLeash( for (int segment = 0; segment <= 24; ++segment) { GeoEntityRenderer.renderLeashPiece( - vertexConsumer, - posMatrix, - xDif, - yDif, - zDif, - entityBlockLight, - holderBlockLight, - entitySkyLight, - holderSkyLight, - 0.025f, - 0.025f, - xOffset, - zOffset, - segment, - false + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.025f, + xOffset, + zOffset, + segment, + false ); } for (int segment = 24; segment >= 0; --segment) { GeoEntityRenderer.renderLeashPiece( - vertexConsumer, - posMatrix, - xDif, - yDif, - zDif, - entityBlockLight, - holderBlockLight, - entitySkyLight, - holderSkyLight, - 0.025f, - 0.0f, - xOffset, - zOffset, - segment, - true + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.0f, + xOffset, + zOffset, + segment, + true ); } @@ -719,8 +730,8 @@ public boolean isShaking(T entity) { @Override public void updateAnimatedTextureFrame(T animatable) { AnimatableTexture.setAndUpdate( - getTextureLocation(animatable), - animatable.getId() + (int) animatable.getTick(animatable) + getTextureLocation(animatable), + animatable.getId() + (int) animatable.getTick(animatable) ); } @@ -739,13 +750,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -753,12 +771,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireEntityPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java index 804a4d79b..e8c47d0b8 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoItemRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -11,19 +9,6 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; import net.minecraft.client.Minecraft; import net.minecraft.client.model.geom.EntityModelSet; import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; @@ -41,10 +26,25 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; + /** * Base {@link GeoRenderer} class for rendering {@link Item Items} specifically.
* All items added to be rendered by AzureLib should use an instance of this class. */ +@Deprecated(forRemoval = true) public class GeoItemRenderer extends BlockEntityWithoutLevelRenderer implements GeoRenderer { protected final GeoRenderLayersContainer renderLayers = new GeoRenderLayersContainer<>(this); @@ -69,9 +69,9 @@ public class GeoItemRenderer extends BlockEntity public GeoItemRenderer(GeoModel model) { this( - Minecraft.getInstance().getBlockEntityRenderDispatcher(), - Minecraft.getInstance().getEntityModels(), - model + Minecraft.getInstance().getBlockEntityRenderDispatcher(), + Minecraft.getInstance().getEntityModels(), + model ); } @@ -174,43 +174,43 @@ public GeoItemRenderer withScale(float scaleWidth, float scaleHeight) { */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.itemRenderTranslations = new Matrix4f(poseStack.last().pose()); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); if (!isReRender) - poseStack.translate(0.5f, this.useNewOffset() ? 0.0f :0.51f, 0.5f); + poseStack.translate(0.5f, this.useNewOffset() ? 0.0f : 0.51f, 0.5f); } @Override public void renderByItem( - ItemStack stack, - ItemDisplayContext transformType, - PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight, - int packedOverlay + ItemStack stack, + ItemDisplayContext transformType, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight, + int packedOverlay ) { this.animatable = (T) stack.getItem(); this.currentItemStack = stack; @@ -220,27 +220,27 @@ public void renderByItem( renderInGui(transformType, poseStack, bufferSource, packedLight, packedOverlay); } else { RenderType renderType = getRenderType( - this.animatable, - getTextureLocation(this.animatable), - bufferSource, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() + this.animatable, + getTextureLocation(this.animatable), + bufferSource, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() ); VertexConsumer buffer = ItemRenderer.getFoilBufferDirect( - bufferSource, - renderType, - false, - this.currentItemStack != null && this.currentItemStack.hasFoil() + bufferSource, + renderType, + false, + this.currentItemStack != null && this.currentItemStack.hasFoil() ); defaultRender( - poseStack, - this.animatable, - bufferSource, - renderType, - buffer, - 0, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), - packedLight + poseStack, + this.animatable, + bufferSource, + renderType, + buffer, + 0, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), + packedLight ); } } @@ -251,45 +251,44 @@ public void renderByItem( * Just includes some additional required transformations and settings. */ protected void renderInGui( - ItemDisplayContext transformType, - PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight, - int packedOverlay + ItemDisplayContext transformType, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight, + int packedOverlay ) { if (this.useEntityGuiLighting) { Lighting.setupForEntityInInventory(); - } - else { + } else { Lighting.setupForFlatItems(); } MultiBufferSource.BufferSource defaultBufferSource = - bufferSource instanceof MultiBufferSource.BufferSource bufferSource2 - ? bufferSource2 - : Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); + bufferSource instanceof MultiBufferSource.BufferSource bufferSource2 + ? bufferSource2 + : Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); RenderType renderType = getRenderType( - this.animatable, - getTextureLocation(this.animatable), - defaultBufferSource, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() + this.animatable, + getTextureLocation(this.animatable), + defaultBufferSource, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks() ); VertexConsumer buffer = ItemRenderer.getFoilBufferDirect( - bufferSource, - renderType, - true, - this.currentItemStack != null && this.currentItemStack.hasFoil() + bufferSource, + renderType, + true, + this.currentItemStack != null && this.currentItemStack.hasFoil() ); poseStack.pushPose(); defaultRender( - poseStack, - this.animatable, - defaultBufferSource, - renderType, - buffer, - 0, - Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), - packedLight + poseStack, + this.animatable, + defaultBufferSource, + renderType, + buffer, + 0, + Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(), + packedLight ); defaultBufferSource.endBatch(); RenderSystem.enableDepthTest(); @@ -304,17 +303,17 @@ protected void renderInGui( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (!isReRender) { AnimationState animationState = new AnimationState<>(animatable, 0, 0, partialTick, false); @@ -324,8 +323,8 @@ public void actuallyRender( animationState.setData(DataTickets.ITEM_RENDER_PERSPECTIVE, this.renderPerspective); animationState.setData(DataTickets.ITEMSTACK, this.currentItemStack); animatable.getAnimatableInstanceCache() - .getManagerForId(instanceId) - .setData(DataTickets.ITEM_RENDER_PERSPECTIVE, this.renderPerspective); + .getManagerForId(instanceId) + .setData(DataTickets.ITEM_RENDER_PERSPECTIVE, this.renderPerspective); this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); this.model.handleAnimations(animatable, instanceId, animationState); } @@ -333,17 +332,17 @@ public void actuallyRender( this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -352,17 +351,17 @@ public void actuallyRender( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); @@ -370,22 +369,22 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); } GeoRenderer.super.renderRecursively( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -403,17 +402,17 @@ public Vec3 getRenderOffset(Item entity, float f) { @Override public void updateAnimatedTextureFrame(T animatable) { AnimatableTexture.setAndUpdate( - getTextureLocation(animatable), - Item.getId(animatable) + (int) animatable.getTick(animatable) + getTextureLocation(animatable), + Item.getId(animatable) + (int) animatable.getTick(animatable) ); } /** * Determines whether to apply the y offset for a model due to the change in BlockBench 4.11. * - * @return {@code false} by default, meaning the Y-offset will be {@code 0.51f}. Override this - * method or change the return value to {@code true} to use the new Y-offset of {@code 0.0f} - * for anything created in 4.11+ of Blockbench. + * @return {@code false} by default, meaning the Y-offset will be {@code 0.51f}. Override this method or change the + * return value to {@code true} to use the new Y-offset of {@code 0.0f} for anything created in 4.11+ of + * Blockbench. */ public boolean useNewOffset() { return false; @@ -434,13 +433,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireItemPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireItemPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -448,12 +454,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireItemPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireItemPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java index d752a3ec1..d0934ad7b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoObjectRenderer.java @@ -1,14 +1,23 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4f; + +import java.util.List; + import mod.azure.azurelib.common.api.client.model.GeoModel; import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayersContainer; @@ -20,16 +29,6 @@ import mod.azure.azurelib.common.platform.Services; import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimationState; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.entity.EntityRenderer; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; -import org.joml.Matrix4f; - -import java.util.List; /** * Base {@link GeoRenderer} class for rendering anything that isn't already handled by the other builtin GeoRenderer @@ -39,6 +38,7 @@ *
* It is strongly recommended you override {@link GeoRenderer#getInstanceId} if using this renderer */ +@Deprecated(forRemoval = true) public class GeoObjectRenderer implements GeoRenderer { protected final GeoRenderLayersContainer renderLayers = new GeoRenderLayersContainer<>(this); @@ -130,12 +130,12 @@ public GeoObjectRenderer withScale(float scaleWidth, float scaleHeight) { * @param packedLight The light level at the given render position for rendering */ public void render( - PoseStack poseStack, - T animatable, - @Nullable MultiBufferSource bufferSource, - @Nullable RenderType renderType, - @Nullable VertexConsumer buffer, - int packedLight + PoseStack poseStack, + T animatable, + @Nullable MultiBufferSource bufferSource, + @Nullable RenderType renderType, + @Nullable VertexConsumer buffer, + int packedLight ) { this.animatable = animatable; Minecraft mc = Minecraft.getInstance(); @@ -143,7 +143,16 @@ public void render( if (buffer == null) bufferSource = Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); - defaultRender(poseStack, animatable, bufferSource, renderType, buffer, 0, mc.getTimer().getGameTimeDeltaTicks(), packedLight); + defaultRender( + poseStack, + animatable, + bufferSource, + renderType, + buffer, + 0, + mc.getTimer().getGameTimeDeltaTicks(), + packedLight + ); } /** @@ -153,29 +162,29 @@ public void render( */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.objectRenderTranslations = new Matrix4f(poseStack.last().pose()); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); poseStack.translate(0.5f, 0.51f, 0.5f); @@ -188,17 +197,17 @@ public void preRender( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); @@ -213,17 +222,17 @@ public void actuallyRender( this.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); } @@ -233,17 +242,17 @@ public void actuallyRender( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { if (bone.isTrackingMatrices()) { Matrix4f poseState = new Matrix4f(poseStack.last().pose()); @@ -251,22 +260,22 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset().toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset().toVector3f()) ); } GeoRenderer.super.renderRecursively( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -301,13 +310,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireObjectPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireObjectPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -315,12 +331,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireObjectPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireObjectPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java index f7d06daf8..8ccc0e5e7 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/GeoReplacedEntityRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer; @@ -13,18 +11,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; @@ -48,10 +34,26 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; + /** * An alternate to {@link GeoEntityRenderer}, used specifically for replacing existing non-AzureLib entities with * AzureLib rendering dynamically, without the need for an additional entity class + * + * @deprecated */ +@Deprecated(forRemoval = true) public class GeoReplacedEntityRenderer extends EntityRenderer implements GeoRenderer { protected final GeoModel model; @@ -83,21 +85,21 @@ public GeoReplacedEntityRenderer(EntityRendererProvider.Context renderManager, G * duplicated here for flexible usage */ private static void renderLeashPiece( - VertexConsumer buffer, - Matrix4f positionMatrix, - float xDif, - float yDif, - float zDif, - int entityBlockLight, - int holderBlockLight, - int entitySkyLight, - int holderSkyLight, - float width, - float yOffset, - float xOffset, - float zOffset, - int segment, - boolean isLeashKnot + VertexConsumer buffer, + Matrix4f positionMatrix, + float xDif, + float yDif, + float zDif, + int entityBlockLight, + int holderBlockLight, + int entitySkyLight, + int holderSkyLight, + float width, + float yOffset, + float xOffset, + float zOffset, + int segment, + boolean isLeashKnot ) { float piecePosPercent = segment / 24f; int lerpBlockLight = (int) Mth.lerp(piecePosPercent, entityBlockLight, holderBlockLight); @@ -109,16 +111,16 @@ private static void renderLeashPiece( float blue = 0.3f * knotColourMod; float x = xDif * piecePosPercent; float y = yDif > 0.0f - ? yDif * piecePosPercent * piecePosPercent - : yDif - yDif * (1.0f - piecePosPercent) * (1.0f - piecePosPercent); + ? yDif * piecePosPercent * piecePosPercent + : yDif - yDif * (1.0f - piecePosPercent) * (1.0f - piecePosPercent); float z = zDif * piecePosPercent; buffer.addVertex(positionMatrix, x - xOffset, y + yOffset, z + zOffset) - .setColor(red, green, blue, 1) - .setLight(packedLight); + .setColor(red, green, blue, 1) + .setLight(packedLight); buffer.addVertex(positionMatrix, x + xOffset, y + width - yOffset, z - zOffset) - .setColor(red, green, blue, 1) - .setLight(packedLight); + .setColor(red, green, blue, 1) + .setLight(packedLight); } /** @@ -207,40 +209,40 @@ public GeoReplacedEntityRenderer withScale(float scaleWidth, float scaleHe */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.entityRenderTranslations = new Matrix4f(poseStack.last().pose()); scaleModelForRender( - this.scaleWidth, - this.scaleHeight, - poseStack, - animatable, - model, - isReRender, - partialTick, - packedLight, - packedOverlay + this.scaleWidth, + this.scaleHeight, + poseStack, + animatable, + model, + isReRender, + partialTick, + packedLight, + packedOverlay ); } @Override public void render( - E entity, - float entityYaw, - float partialTick, - PoseStack poseStack, - MultiBufferSource bufferSource, - int packedLight + E entity, + float entityYaw, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + int packedLight ) { this.currentEntity = entity; @@ -254,17 +256,17 @@ public void render( */ @Override public void actuallyRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); @@ -272,11 +274,11 @@ public void actuallyRender( boolean shouldSit = this.currentEntity.isPassenger() && (this.currentEntity.getVehicle() != null); float lerpBodyRot = livingEntity == null - ? 0 - : Mth.rotLerp(partialTick, livingEntity.yBodyRotO, livingEntity.yBodyRot); + ? 0 + : Mth.rotLerp(partialTick, livingEntity.yBodyRotO, livingEntity.yBodyRot); float lerpHeadRot = livingEntity == null - ? 0 - : Mth.rotLerp(partialTick, livingEntity.yHeadRotO, livingEntity.yHeadRot); + ? 0 + : Mth.rotLerp(partialTick, livingEntity.yHeadRotO, livingEntity.yHeadRot); float netHeadYaw = lerpHeadRot - lerpBodyRot; if (shouldSit && this.currentEntity.getVehicle() instanceof LivingEntity livingentity) { @@ -298,9 +300,9 @@ public void actuallyRender( float eyePosOffset = livingEntity.getEyeHeight(Pose.STANDING) - 0.1F; poseStack.translate( - -bedDirection.getStepX() * eyePosOffset, - 0, - -bedDirection.getStepZ() * eyePosOffset + -bedDirection.getStepX() * eyePosOffset, + 0, + -bedDirection.getStepZ() * eyePosOffset ); } } @@ -315,9 +317,9 @@ public void actuallyRender( if (!shouldSit && this.currentEntity.isAlive() && livingEntity != null) { limbSwingAmount = Mth.lerp( - partialTick, - livingEntity.walkAnimation.speedOld, - livingEntity.walkAnimation.speed() + partialTick, + livingEntity.walkAnimation.speedOld, + livingEntity.walkAnimation.speed() ); limbSwing = livingEntity.walkAnimation.position() - livingEntity.walkAnimation.speed() * (1 - partialTick); @@ -343,20 +345,24 @@ public void actuallyRender( if (!isReRender) { AnimationState animationState = new AnimationState( - animatable, - limbSwing, - limbSwingAmount, - partialTick, - isMoving + animatable, + limbSwing, + limbSwingAmount, + partialTick, + isMoving ); long instanceId = getInstanceId(animatable); animationState.setData(DataTickets.TICK, animatable.getTick(this.currentEntity)); animationState.setData(DataTickets.ENTITY, this.currentEntity); animationState.setData( - DataTickets.ENTITY_MODEL_DATA, - new EntityModelData(shouldSit, livingEntity != null && livingEntity.isBaby(), -netHeadYaw, - -headPitch) + DataTickets.ENTITY_MODEL_DATA, + new EntityModelData( + shouldSit, + livingEntity != null && livingEntity.isBaby(), + -netHeadYaw, + -headPitch + ) ); this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); this.model.handleAnimations(animatable, instanceId, animationState); @@ -370,17 +376,17 @@ public void actuallyRender( assert Minecraft.getInstance().player != null; if (!this.currentEntity.isInvisibleTo(Minecraft.getInstance().player)) GeoRenderer.super.actuallyRender( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -391,27 +397,27 @@ public void actuallyRender( */ @Override public void applyRenderLayers( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { if (!this.currentEntity.isSpectator()) GeoRenderer.super.applyRenderLayers( - poseStack, - animatable, - model, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay ); } @@ -421,15 +427,15 @@ public void applyRenderLayers( */ @Override public void renderFinal( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { super.render(this.currentEntity, 0, partialTick, poseStack, bufferSource, packedLight); @@ -446,17 +452,17 @@ public void renderFinal( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -470,10 +476,10 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.currentEntity, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.currentEntity, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) ); } @@ -486,54 +492,62 @@ public void renderRecursively( if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); } /** - * Applies rotation transformations to the renderer prior to render time to account for various entity states, default scale of 1 + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * default scale of 1 */ protected void applyRotations( - T animatable, - PoseStack poseStack, - float ageInTicks, - float rotationYaw, - float partialTick + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick ) { applyRotations(animatable, poseStack, ageInTicks, rotationYaw, partialTick, 1); } /** - * Applies rotation transformations to the renderer prior to render time to account for various entity states, scalable + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * scalable */ - protected void applyRotations(T animatable, PoseStack poseStack, float ageInTicks, float rotationYaw, - float partialTick, float nativeScale) { + protected void applyRotations( + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick, + float nativeScale + ) { if (isShaking(animatable)) - rotationYaw += (float)(Math.cos(this.currentEntity.tickCount * 3.25d) * Math.PI * 0.4d); + rotationYaw += (float) (Math.cos(this.currentEntity.tickCount * 3.25d) * Math.PI * 0.4d); if (!this.currentEntity.hasPose(Pose.SLEEPING)) poseStack.mulPose(Axis.YP.rotationDegrees(180f - rotationYaw)); @@ -542,20 +556,23 @@ protected void applyRotations(T animatable, PoseStack poseStack, float ageInTick if (livingEntity.deathTime > 0) { float deathRotation = (livingEntity.deathTime + partialTick - 1f) / 20f * 1.6f; - poseStack.mulPose(Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable))); - } - else if (livingEntity.isAutoSpinAttack()) { + poseStack.mulPose( + Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * getDeathMaxRotation(animatable)) + ); + } else if (livingEntity.isAutoSpinAttack()) { poseStack.mulPose(Axis.XP.rotationDegrees(-90f - livingEntity.getXRot())); poseStack.mulPose(Axis.YP.rotationDegrees((livingEntity.tickCount + partialTick) * -75f)); - } - else if (livingEntity.hasPose(Pose.SLEEPING)) { + } else if (livingEntity.hasPose(Pose.SLEEPING)) { Direction bedOrientation = livingEntity.getBedOrientation(); - poseStack.mulPose(Axis.YP.rotationDegrees(bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw)); + poseStack.mulPose( + Axis.YP.rotationDegrees( + bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw + ) + ); poseStack.mulPose(Axis.ZP.rotationDegrees(getDeathMaxRotation(animatable))); poseStack.mulPose(Axis.YP.rotationDegrees(270f)); - } - else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { + } else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { poseStack.translate(0, (livingEntity.getBbHeight() + 0.1f) / nativeScale, 0); poseStack.mulPose(Axis.ZP.rotationDegrees(180f)); } @@ -587,8 +604,8 @@ public boolean shouldShowName(@NotNull E entity) { return false; if ( - entity instanceof Mob && (!entity.shouldShowName() && (!entity.hasCustomName() - || entity != this.entityRenderDispatcher.crosshairPickEntity)) + entity instanceof Mob && (!entity.shouldShowName() && (!entity.hasCustomName() + || entity != this.entityRenderDispatcher.crosshairPickEntity)) ) return false; @@ -599,7 +616,7 @@ public boolean shouldShowName(@NotNull E entity) { if (entityTeam == null) return Minecraft.renderNames() && entity != minecraft.getCameraEntity() && visibleToClient && !entity - .isVehicle(); + .isVehicle(); var playerTeam = minecraft.player.getTeam(); @@ -607,11 +624,11 @@ public boolean shouldShowName(@NotNull E entity) { case ALWAYS -> visibleToClient; case NEVER -> false; case HIDE_FOR_OTHER_TEAMS -> playerTeam == null - ? visibleToClient - : entityTeam.isAlliedTo(playerTeam) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); + ? visibleToClient + : entityTeam.isAlliedTo(playerTeam) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); case HIDE_FOR_OWN_TEAM -> playerTeam == null - ? visibleToClient - : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; + ? visibleToClient + : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; }; } @@ -634,11 +651,11 @@ public int getPackedOverlay(T animatable, float u, float partialTick) { * duplicated here for flexible usage */ public void renderLeash( - M mob, - float partialTick, - PoseStack poseStack, - MultiBufferSource bufferSource, - H leashHolder + M mob, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + H leashHolder ) { double lerpBodyAngle = (Mth.lerp(partialTick, mob.yBodyRotO, mob.yBodyRot) * Mth.DEG_TO_RAD) + Mth.HALF_PI; Vec3 leashOffset = mob.getLeashOffset(); @@ -659,8 +676,8 @@ public void renderLeash( BlockPos holderEyePos = BlockPos.containing(leashHolder.getEyePosition(partialTick)); int entityBlockLight = getBlockLightLevel((E) mob, entityEyePos); int holderBlockLight = leashHolder.isOnFire() - ? 15 - : leashHolder.level().getBrightness(LightLayer.BLOCK, holderEyePos); + ? 15 + : leashHolder.level().getBrightness(LightLayer.BLOCK, holderEyePos); int entitySkyLight = mob.level().getBrightness(LightLayer.SKY, entityEyePos); int holderSkyLight = mob.level().getBrightness(LightLayer.SKY, holderEyePos); @@ -671,41 +688,41 @@ public void renderLeash( for (int segment = 0; segment <= 24; ++segment) { renderLeashPiece( - vertexConsumer, - posMatrix, - xDif, - yDif, - zDif, - entityBlockLight, - holderBlockLight, - entitySkyLight, - holderSkyLight, - 0.025f, - 0.025f, - xOffset, - zOffset, - segment, - false + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.025f, + xOffset, + zOffset, + segment, + false ); } for (int segment = 24; segment >= 0; --segment) { renderLeashPiece( - vertexConsumer, - posMatrix, - xDif, - yDif, - zDif, - entityBlockLight, - holderBlockLight, - entitySkyLight, - holderSkyLight, - 0.025f, - 0.0f, - xOffset, - zOffset, - segment, - true + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.0f, + xOffset, + zOffset, + segment, + true ); } @@ -726,8 +743,8 @@ public boolean isShaking(T entity) { @Override public void updateAnimatedTextureFrame(T animatable) { AnimatableTexture.setAndUpdate( - getTextureLocation(animatable), - this.currentEntity.getId() + (int) animatable.getTick(this.currentEntity) + getTextureLocation(animatable), + this.currentEntity.getId() + (int) animatable.getTick(this.currentEntity) ); } @@ -746,13 +763,20 @@ public void fireCompileRenderLayersEvent() { */ @Override public boolean firePreRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireReplacedEntityPreRender(this, poseStack, model, bufferSource, partialTick, packedLight); + return Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireReplacedEntityPreRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } /** @@ -760,12 +784,19 @@ public boolean firePreRenderEvent( */ @Override public void firePostRenderEvent( - PoseStack poseStack, - BakedGeoModel model, - MultiBufferSource bufferSource, - float partialTick, - int packedLight + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight ) { - Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireReplacedEntityPostRender(this, poseStack, model, bufferSource, partialTick, packedLight); + Services.GEO_RENDER_PHASE_EVENT_FACTORY.fireReplacedEntityPostRender( + this, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoArmorRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoArmorRenderer.java index ac0cee3c3..e040ed641 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoArmorRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoArmorRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.dynamic; @@ -11,19 +9,10 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRendererConstants; -import mod.azure.azurelib.common.api.client.renderer.GeoBlockRenderer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; -import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -31,6 +20,13 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRendererConstants; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; + /** * Extended special-armor renderer for more advanced or dynamic models.
* Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider @@ -39,7 +35,7 @@ public abstract class DynamicGeoArmorRenderer extends GeoArmorRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; @@ -71,11 +67,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -86,14 +82,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -103,17 +99,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -128,7 +124,7 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix(RenderUtils.translateMatrix(localMatrix, GeoArmorRendererConstants.ZERO)); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) ); } @@ -136,14 +132,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -153,49 +149,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -207,30 +203,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -241,23 +237,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -268,13 +264,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -282,23 +278,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoBlockRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoBlockRenderer.java index ed6d3d180..881e77ee8 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoBlockRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoBlockRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.dynamic; @@ -11,11 +9,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoBlockRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; @@ -27,6 +20,12 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoBlockRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Extended special-block-entity renderer for more advanced or dynamic models.
* Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider @@ -35,7 +34,7 @@ public abstract class DynamicGeoBlockRenderer extends GeoBlockRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; @@ -67,11 +66,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -82,14 +81,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -99,17 +98,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -123,17 +122,17 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix( - new Matrix4f(localMatrix), - new Vector3f( - this.animatable.getBlockPos().getX(), - this.animatable.getBlockPos().getY(), - this.animatable.getBlockPos().getZ() - ) + RenderUtils.translateMatrix( + new Matrix4f(localMatrix), + new Vector3f( + this.animatable.getBlockPos().getX(), + this.animatable.getBlockPos().getY(), + this.animatable.getBlockPos().getZ() ) + ) ); } @@ -141,14 +140,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -158,49 +157,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -212,30 +211,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -246,23 +245,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -273,13 +272,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -287,23 +286,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoItemRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoItemRenderer.java index 3eaf2b2fb..aebd14a1a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoItemRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.dynamic; @@ -11,17 +9,10 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoBlockRenderer; -import mod.azure.azurelib.common.api.client.renderer.GeoItemRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; -import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -29,6 +20,12 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoItemRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Extended special-item renderer for more advanced or dynamic models.
* Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider @@ -37,7 +34,7 @@ public abstract class DynamicGeoItemRenderer extends GeoItemRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; @@ -69,11 +66,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -84,14 +81,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -101,17 +98,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -125,10 +122,10 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.animatable, 1).toVector3f()) ); } @@ -136,14 +133,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -153,49 +150,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -207,30 +204,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -241,23 +238,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -268,13 +265,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -282,23 +279,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoObjectRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoObjectRenderer.java index e45b87984..3c8d8f792 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoObjectRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoObjectRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.dynamic; @@ -11,16 +9,9 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoItemRenderer; -import mod.azure.azurelib.common.api.client.renderer.GeoObjectRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Vector3f; @@ -28,6 +19,12 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoObjectRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Extended special-object renderer for more advanced or dynamic models.
* Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider @@ -36,7 +33,7 @@ public abstract class DynamicGeoObjectRenderer extends GeoObjectRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; @@ -68,11 +65,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -83,14 +80,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -100,17 +97,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -124,7 +121,7 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset().toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset().toVector3f()) ); } @@ -132,14 +129,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -149,49 +146,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -203,30 +200,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -237,23 +234,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -264,13 +261,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -278,23 +275,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoReplacedEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoReplacedEntityRenderer.java index a0c8cf76b..d78998761 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoReplacedEntityRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/dynamic/DynamicGeoReplacedEntityRenderer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.dynamic; @@ -11,12 +9,6 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoEntityRenderer; -import mod.azure.azurelib.common.api.client.renderer.GeoReplacedEntityRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRendererProvider; @@ -29,19 +21,29 @@ import java.util.Map; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoReplacedEntityRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Extended special-entity renderer for more advanced or dynamic models.
* Because of the extra performance cost of this renderer, it is advised to avoid using it unnecessarily, and consider * whether the benefits are worth the cost for your needs. */ -public abstract class DynamicGeoReplacedEntityRenderer extends GeoReplacedEntityRenderer { +public abstract class DynamicGeoReplacedEntityRenderer extends GeoReplacedEntityRenderer { protected static final Map TEXTURE_DIMENSIONS_CACHE = - new Object2ObjectOpenHashMap<>(); + new Object2ObjectOpenHashMap<>(); protected ResourceLocation textureOverride = null; - protected DynamicGeoReplacedEntityRenderer(EntityRendererProvider.Context renderManager, GeoModel model, T animatable) { + protected DynamicGeoReplacedEntityRenderer( + EntityRendererProvider.Context renderManager, + GeoModel model, + T animatable + ) { super(renderManager, model, animatable); } @@ -69,11 +71,11 @@ protected ResourceLocation getTextureOverrideForBone(GeoBone bone, T animatable, */ @Nullable protected RenderType getRenderTypeOverrideForBone( - GeoBone bone, - T animatable, - ResourceLocation texturePath, - MultiBufferSource bufferSource, - float partialTick + GeoBone bone, + T animatable, + ResourceLocation texturePath, + MultiBufferSource bufferSource, + float partialTick ) { return null; } @@ -84,14 +86,14 @@ protected RenderType getRenderTypeOverrideForBone( * @return Whether the renderer should skip rendering the {@link GeoCube cubes} of the given GeoBone or not */ protected boolean boneRenderOverride( - PoseStack poseStack, - GeoBone bone, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + GeoBone bone, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { return false; } @@ -101,17 +103,17 @@ protected boolean boneRenderOverride( */ @Override public void renderRecursively( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { poseStack.pushPose(); RenderUtils.translateMatrixToBone(poseStack, bone); @@ -125,10 +127,10 @@ public void renderRecursively( bone.setModelSpaceMatrix(RenderUtils.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations)); bone.setLocalSpaceMatrix( - RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.currentEntity, 1).toVector3f()) + RenderUtils.translateMatrix(localMatrix, getRenderOffset(this.currentEntity, 1).toVector3f()) ); bone.setWorldSpaceMatrix( - RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) + RenderUtils.translateMatrix(new Matrix4f(localMatrix), this.currentEntity.position().toVector3f()) ); } @@ -136,14 +138,14 @@ public void renderRecursively( this.textureOverride = getTextureOverrideForBone(bone, this.animatable, partialTick); ResourceLocation texture = this.textureOverride == null - ? getTextureLocation(this.animatable) - : this.textureOverride; + ? getTextureLocation(this.animatable) + : this.textureOverride; RenderType renderTypeOverride = getRenderTypeOverrideForBone( - bone, - this.animatable, - texture, - bufferSource, - partialTick + bone, + this.animatable, + texture, + bufferSource, + partialTick ); if (texture != null && renderTypeOverride == null) @@ -153,49 +155,49 @@ public void renderRecursively( buffer = bufferSource.getBuffer(renderTypeOverride); if ( - !boneRenderOverride( - poseStack, - bone, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay, - colour - ) + !boneRenderOverride( + poseStack, + bone, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + colour + ) ) super.renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (renderTypeOverride != null) buffer = bufferSource.getBuffer( - getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) + getRenderType(this.animatable, getTextureLocation(this.animatable), bufferSource, partialTick) ); if (!isReRender) applyRenderLayersForBone( - poseStack, - animatable, - bone, - renderType, - bufferSource, - buffer, - partialTick, - packedLight, - packedOverlay - ); - - super.renderChildBones( poseStack, animatable, bone, renderType, bufferSource, buffer, - isReRender, partialTick, packedLight, - packedOverlay, - colour + packedOverlay + ); + + super.renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); poseStack.popPose(); @@ -207,30 +209,30 @@ public void renderRecursively( */ @Override public void postRender( - PoseStack poseStack, - T animatable, - BakedGeoModel model, - MultiBufferSource bufferSource, - VertexConsumer buffer, - boolean isReRender, - float partialTick, - int packedLight, - int packedOverlay, - int colour + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour ) { this.textureOverride = null; super.postRender( - poseStack, - animatable, - model, - bufferSource, - buffer, - isReRender, - partialTick, - packedLight, - packedOverlay, - colour + poseStack, + animatable, + model, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour ); } @@ -241,23 +243,23 @@ public void postRender( */ @Override public void createVerticesOfQuad( - GeoQuad quad, - Matrix4f poseState, - Vector3f normal, - VertexConsumer buffer, - int packedLight, - int packedOverlay, - int colour + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour ) { if (this.textureOverride == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -268,13 +270,13 @@ public void createVerticesOfQuad( if (boneTextureSize == null || entityTextureSize == null) { super.createVerticesOfQuad( - quad, - poseState, - normal, - buffer, - packedLight, - packedOverlay, - colour + quad, + poseState, + normal, + buffer, + packedLight, + packedOverlay, + colour ); return; @@ -282,23 +284,23 @@ public void createVerticesOfQuad( for (GeoVertex vertex : quad.vertices()) { Vector4f vector4f = poseState.transform( - new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) + new Vector4f(vertex.position().x(), vertex.position().y(), vertex.position().z(), 1.0f) ); float texU = (vertex.texU() * entityTextureSize.firstInt()) / boneTextureSize.firstInt(); float texV = (vertex.texV() * entityTextureSize.secondInt()) / boneTextureSize.secondInt(); buffer.addVertex( - vector4f.x(), - vector4f.y(), - vector4f.z(), - -1, - texU, - texV, - packedOverlay, - packedLight, - normal.x(), - normal.y(), - normal.z() + vector4f.x(), + vector4f.y(), + vector4f.z(), + -1, + texU, + texV, + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java index 1ca7d5200..aeab5141b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/AutoGlowingGeoLayer.java @@ -1,27 +1,26 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; + import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; import mod.azure.azurelib.common.internal.common.cache.texture.AutoGlowingTexture; import mod.azure.azurelib.core.animatable.GeoAnimatable; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.resources.ResourceLocation; /** * {@link GeoRenderLayer} for rendering the auto-generated glowlayer functionality implemented by AzureLib using the * _glowing appendixed texture files. */ +@Deprecated(forRemoval = true) public class AutoGlowingGeoLayer extends GeoRenderLayer { public AutoGlowingGeoLayer(GeoRenderer renderer) { @@ -42,22 +41,31 @@ protected RenderType getRenderType(T animatable) { */ @Override public void render( - PoseStack poseStack, - T animatable, - BakedGeoModel bakedModel, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { renderType = getRenderType(animatable); if (renderType != null) { - getRenderer().reRender(bakedModel, poseStack, bufferSource, animatable, renderType, - bufferSource.getBuffer(renderType), partialTick, 15728640, packedOverlay, - getRenderer().getRenderColor(animatable, partialTick, packedLight).argbInt()); + getRenderer().reRender( + bakedModel, + poseStack, + bufferSource, + animatable, + renderType, + bufferSource.getBuffer(renderType), + partialTick, + 15728640, + packedOverlay, + getRenderer().getRenderColor(animatable, partialTick, packedLight).argbInt() + ); } } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java index 63ab564dd..21340862c 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BlockAndItemGeoLayer.java @@ -1,18 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; @@ -25,10 +19,16 @@ import java.util.function.BiFunction; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * {@link GeoRenderLayer} for rendering {@link net.minecraft.world.level.block.state.BlockState BlockStates} or * {@link net.minecraft.world.item.ItemStack ItemStacks} on a given {@link GeoAnimatable} */ +@Deprecated(forRemoval = true) public class BlockAndItemGeoLayer extends GeoRenderLayer { protected final BiFunction stackForBone; @@ -40,9 +40,9 @@ public BlockAndItemGeoLayer(GeoRenderer renderer) { } public BlockAndItemGeoLayer( - GeoRenderer renderer, - BiFunction stackForBone, - BiFunction blockForBone + GeoRenderer renderer, + BiFunction stackForBone, + BiFunction blockForBone ) { super(renderer); @@ -87,15 +87,15 @@ protected ItemDisplayContext getTransformTypeForStack(GeoBone bone, ItemStack st */ @Override public void renderForBone( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { ItemStack stack = getStackForBone(bone, animatable); BlockState blockState = getBlockForBone(bone, animatable); @@ -108,26 +108,26 @@ public void renderForBone( if (stack != null) renderStackForBone( - poseStack, - bone, - stack, - animatable, - bufferSource, - partialTick, - packedLight, - packedOverlay + poseStack, + bone, + stack, + animatable, + bufferSource, + partialTick, + packedLight, + packedOverlay ); if (blockState != null) renderBlockForBone( - poseStack, - bone, - blockState, - animatable, - bufferSource, - partialTick, - packedLight, - packedOverlay + poseStack, + bone, + blockState, + animatable, + bufferSource, + partialTick, + packedLight, + packedOverlay ); poseStack.popPose(); @@ -137,43 +137,43 @@ public void renderForBone( * Render the given {@link ItemStack} for the provided {@link GeoBone}. */ protected void renderStackForBone( - PoseStack poseStack, - GeoBone bone, - ItemStack stack, - T animatable, - MultiBufferSource bufferSource, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + GeoBone bone, + ItemStack stack, + T animatable, + MultiBufferSource bufferSource, + float partialTick, + int packedLight, + int packedOverlay ) { if (animatable instanceof LivingEntity livingEntity) { Minecraft.getInstance() - .getItemRenderer() - .renderStatic( - livingEntity, - stack, - getTransformTypeForStack(bone, stack, animatable), - false, - poseStack, - bufferSource, - livingEntity.level(), - packedLight, - packedOverlay, - livingEntity.getId() - ); + .getItemRenderer() + .renderStatic( + livingEntity, + stack, + getTransformTypeForStack(bone, stack, animatable), + false, + poseStack, + bufferSource, + livingEntity.level(), + packedLight, + packedOverlay, + livingEntity.getId() + ); } else { Minecraft.getInstance() - .getItemRenderer() - .renderStatic( - stack, - getTransformTypeForStack(bone, stack, animatable), - packedLight, - packedOverlay, - poseStack, - bufferSource, - Minecraft.getInstance().level, - (int) this.renderer.getInstanceId(animatable) - ); + .getItemRenderer() + .renderStatic( + stack, + getTransformTypeForStack(bone, stack, animatable), + packedLight, + packedOverlay, + poseStack, + bufferSource, + Minecraft.getInstance().level, + (int) this.renderer.getInstanceId(animatable) + ); } } @@ -181,21 +181,21 @@ protected void renderStackForBone( * Render the given {@link BlockState} for the provided {@link GeoBone}. */ protected void renderBlockForBone( - PoseStack poseStack, - GeoBone bone, - BlockState state, - T animatable, - MultiBufferSource bufferSource, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + GeoBone bone, + BlockState state, + T animatable, + MultiBufferSource bufferSource, + float partialTick, + int packedLight, + int packedOverlay ) { poseStack.pushPose(); poseStack.translate(-0.25f, -0.25f, -0.25f); poseStack.scale(0.5f, 0.5f, 0.5f); Minecraft.getInstance() - .getBlockRenderer() - .renderSingleBlock(state, poseStack, bufferSource, packedLight, OverlayTexture.NO_OVERLAY); + .getBlockRenderer() + .renderSingleBlock(state, poseStack, bufferSource, packedLight, OverlayTexture.NO_OVERLAY); poseStack.popPose(); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java index b4e4a5c3a..957c9a74c 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/BoneFilterGeoLayer.java @@ -1,21 +1,20 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import org.apache.logging.log4j.util.TriConsumer; + import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; import mod.azure.azurelib.core.animatable.GeoAnimatable; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import org.apache.logging.log4j.util.TriConsumer; /** * {@link GeoRenderLayer} for auto-applying some form of modification to bones of a model prior to rendering.
@@ -23,13 +22,13 @@ *
* NOTE: Despite this layer existing, it is much more efficient to use {@link FastBoneFilterGeoLayer} instead */ +@Deprecated(forRemoval = true) public class BoneFilterGeoLayer extends GeoRenderLayer { protected final TriConsumer checkAndApply; public BoneFilterGeoLayer(GeoRenderer renderer) { - this(renderer, (bone, animatable, partialTick) -> { - }); + this(renderer, (bone, animatable, partialTick) -> {}); } public BoneFilterGeoLayer(GeoRenderer renderer, TriConsumer checkAndApply) { @@ -48,15 +47,15 @@ protected void checkAndApply(GeoBone bone, T animatable, float partialTick) { @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel bakedModel, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { for (GeoBone bone : bakedModel.getTopLevelBones()) { checkChildBones(bone, animatable, partialTick); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java index fcac8d97b..e126cab01 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/FastBoneFilterGeoLayer.java @@ -1,18 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import org.apache.logging.log4j.util.TriConsumer; @@ -20,11 +14,17 @@ import java.util.List; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * A more efficient version of {@link BoneFilterGeoLayer}.
* This version requires you provide the list of bones to filter up-front, so that the bone hierarchy doesn't need to be * traversed. */ +@Deprecated(forRemoval = true) public class FastBoneFilterGeoLayer extends BoneFilterGeoLayer { protected final Supplier> boneSupplier; @@ -34,14 +34,13 @@ public FastBoneFilterGeoLayer(GeoRenderer renderer) { } public FastBoneFilterGeoLayer(GeoRenderer renderer, Supplier> boneSupplier) { - this(renderer, boneSupplier, (bone, animatable, partialTick) -> { - }); + this(renderer, boneSupplier, (bone, animatable, partialTick) -> {}); } public FastBoneFilterGeoLayer( - GeoRenderer renderer, - Supplier> boneSupplier, - TriConsumer checkAndApply + GeoRenderer renderer, + Supplier> boneSupplier, + TriConsumer checkAndApply ) { super(renderer, checkAndApply); @@ -58,20 +57,20 @@ protected List getAffectedBones() { @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel bakedModel, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { for (String boneName : getAffectedBones()) { this.renderer.getGeoModel() - .getBone(boneName) - .ifPresent(bone -> checkAndApply(bone, animatable, partialTick)); + .getBone(boneName) + .ifPresent(bone -> checkAndApply(bone, animatable, partialTick)); } } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java index 249da8ffb..b0b496b60 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayer.java @@ -1,28 +1,29 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; + import mod.azure.azurelib.common.api.client.model.GeoModel; import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; import mod.azure.azurelib.core.animatable.GeoAnimatable; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.resources.ResourceLocation; /** * Render layer base class for rendering additional layers of effects or textures over an existing model at runtime.
* Contains the base boilerplate and helper code for various render layer features */ +@Deprecated(forRemoval = true) public abstract class GeoRenderLayer { + protected final GeoRenderer renderer; public GeoRenderLayer(GeoRenderer entityRendererIn) { @@ -37,8 +38,7 @@ public GeoModel getGeoModel() { } /** - * Gets the {@link BakedGeoModel} instance that is currently being used. - * This can be directly used for re-rendering + * Gets the {@link BakedGeoModel} instance that is currently being used. This can be directly used for re-rendering */ public BakedGeoModel getDefaultBakedModel(T animatable) { return getGeoModel().getBakedModel(getGeoModel().getModelResource(animatable)); @@ -60,32 +60,59 @@ protected ResourceLocation getTextureResource(T animatable) { } /** - * This method is called by the {@link GeoRenderer} before rendering, immediately after {@link GeoRenderer#preRender} has been called.
+ * This method is called by the {@link GeoRenderer} before rendering, immediately after + * {@link GeoRenderer#preRender} has been called.
* This allows for RenderLayers to perform pre-render manipulations such as hiding or showing bones */ - public void preRender(PoseStack poseStack, T animatable, BakedGeoModel bakedModel, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, - int packedLight, int packedOverlay) {} + public void preRender( + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) {} /** * This is the method that is actually called by the render for your render layer to function.
* This is called after the animatable has been rendered, but before supplementary rendering like nametags. */ - public void render(PoseStack poseStack, T animatable, BakedGeoModel bakedModel, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, - int packedLight, int packedOverlay) {} + public void render( + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) {} /** * This method is called by the {@link GeoRenderer} for each bone being rendered.
* This is a more expensive call, particularly if being used to render something on a different buffer.
- * It does however have the benefit of having the matrix translations and other transformations already applied from render-time.
+ * It does however have the benefit of having the matrix translations and other transformations already applied from + * render-time.
* It's recommended to avoid using this unless necessary.
*
* The {@link GeoBone} in question has already been rendered by this stage.
*
- * If you do use it, and you render something that changes the {@link VertexConsumer buffer}, you need to reset it back to the previous buffer - * using {@link MultiBufferSource#getBuffer} before ending the method + * If you do use it, and you render something that changes the {@link VertexConsumer buffer}, you need to + * reset it back to the previous buffer using {@link MultiBufferSource#getBuffer} before ending the method */ - public void renderForBone(PoseStack poseStack, T animatable, GeoBone bone, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) {} -} \ No newline at end of file + public void renderForBone( + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) {} +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java index f37b94b61..0f0902f0b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/GeoRenderLayersContainer.java @@ -1,22 +1,22 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import java.util.List; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Base interface for a container for {@link GeoRenderLayer GeoRenderLayers}
* Each renderer should contain an instance of this, for holding its layers and handling events. */ +@Deprecated(forRemoval = true) public class GeoRenderLayersContainer { private final GeoRenderer renderer; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java index 61de3514c..6089eebef 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/client/renderer/layer/ItemArmorGeoLayer.java @@ -1,23 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.client.renderer.layer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; -import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.Minecraft; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.SkullModelBase; @@ -43,19 +32,30 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.cache.object.GeoBone; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + /** * Builtin class for handling dynamic armor rendering on AzureLib entities.
* Supports both {@link GeoItem AzureLib} and {@link net.minecraft.world.item.ArmorItem Vanilla} armor models.
* Unlike a traditional armor renderer, this renderer renders per-bone, giving much more flexible armor rendering. */ +@Deprecated(forRemoval = true) public class ItemArmorGeoLayer extends GeoRenderLayer { protected static final HumanoidModel INNER_ARMOR_MODEL = new HumanoidModel<>( - Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR) + Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR) ); protected static final HumanoidModel OUTER_ARMOR_MODEL = new HumanoidModel<>( - Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR) + Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR) ); @Nullable @@ -102,11 +102,11 @@ protected EquipmentSlot getEquipmentSlotForBone(GeoBone bone, ItemStack stack, T */ @NotNull protected ModelPart getModelPartForBone( - GeoBone bone, - EquipmentSlot slot, - ItemStack stack, - T animatable, - HumanoidModel baseModel + GeoBone bone, + EquipmentSlot slot, + ItemStack stack, + T animatable, + HumanoidModel baseModel ) { return baseModel.body; } @@ -127,15 +127,15 @@ protected ItemStack getArmorItemForBone(GeoBone bone, T animatable) { */ @Override public void preRender( - PoseStack poseStack, - T animatable, - BakedGeoModel bakedModel, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + BakedGeoModel bakedModel, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { this.mainHandStack = animatable.getItemBySlot(EquipmentSlot.MAINHAND); this.offhandStack = animatable.getItemBySlot(EquipmentSlot.OFFHAND); @@ -159,15 +159,15 @@ public void preRender( */ @Override public void renderForBone( - PoseStack poseStack, - T animatable, - GeoBone bone, - RenderType renderType, - MultiBufferSource bufferSource, - VertexConsumer buffer, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay ) { ItemStack armorStack = getArmorItemForBone(bone, animatable); @@ -175,8 +175,8 @@ public void renderForBone( return; if ( - armorStack.getItem() instanceof BlockItem blockItem && blockItem - .getBlock() instanceof AbstractSkullBlock skullBlock + armorStack.getItem() instanceof BlockItem blockItem && blockItem + .getBlock() instanceof AbstractSkullBlock skullBlock ) { renderSkullAsArmor(poseStack, bone, armorStack, skullBlock, bufferSource, packedLight); } else { @@ -192,21 +192,28 @@ public void renderForBone( prepModelPartForRender(poseStack, bone, modelPart); geoArmorRenderer.prepForRender(animatable, armorStack, slot, model); geoArmorRenderer.applyBoneVisibilityByPart(slot, modelPart, model); - geoArmorRenderer.renderToBuffer(poseStack, null, packedLight, packedOverlay, armorStack.is( - ItemTags.DYEABLE) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(armorStack, -6265536)) : -1); + geoArmorRenderer.renderToBuffer( + poseStack, + null, + packedLight, + packedOverlay, + armorStack.is( + ItemTags.DYEABLE + ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(armorStack, -6265536)) : -1 + ); } else if (armorStack.getItem() instanceof ArmorItem) { prepModelPartForRender(poseStack, bone, modelPart); renderVanillaArmorPiece( - poseStack, - animatable, - bone, - slot, - armorStack, - modelPart, - bufferSource, - partialTick, - packedLight, - packedOverlay + poseStack, + animatable, + bone, + slot, + armorStack, + modelPart, + bufferSource, + partialTick, + packedLight, + packedOverlay ); } @@ -219,23 +226,32 @@ public void renderForBone( * Renders an individual armor piece base on the given {@link GeoBone} and {@link ItemStack} */ protected void renderVanillaArmorPiece( - PoseStack poseStack, - T animatable, - GeoBone bone, - EquipmentSlot slot, - ItemStack armorStack, - ModelPart modelPart, - MultiBufferSource bufferSource, - float partialTick, - int packedLight, - int packedOverlay + PoseStack poseStack, + T animatable, + GeoBone bone, + EquipmentSlot slot, + ItemStack armorStack, + ModelPart modelPart, + MultiBufferSource bufferSource, + float partialTick, + int packedLight, + int packedOverlay ) { Holder material = ((ArmorItem) armorStack.getItem()).getMaterial(); for (ArmorMaterial.Layer layer : material.value().layers()) { int color = armorStack.is(ItemTags.DYEABLE) ? DyedItemColor.getOrDefault(armorStack, -6265536) : 0xFFFFFF; - VertexConsumer buffer = getVanillaArmorBuffer(bufferSource, animatable, armorStack, slot, bone, layer, - packedLight, packedOverlay, false); + VertexConsumer buffer = getVanillaArmorBuffer( + bufferSource, + animatable, + armorStack, + slot, + bone, + layer, + packedLight, + packedOverlay, + false + ); modelPart.render(poseStack, buffer, packedLight, packedOverlay); } @@ -243,21 +259,51 @@ protected void renderVanillaArmorPiece( ArmorTrim trim = armorStack.get(DataComponents.TRIM); if (trim != null) { - TextureAtlasSprite sprite = Minecraft.getInstance().getModelManager().getAtlas( - Sheets.ARMOR_TRIMS_SHEET).getSprite( - slot == EquipmentSlot.LEGS ? trim.innerTexture(material) : trim.outerTexture(material)); + TextureAtlasSprite sprite = Minecraft.getInstance() + .getModelManager() + .getAtlas( + Sheets.ARMOR_TRIMS_SHEET + ) + .getSprite( + slot == EquipmentSlot.LEGS ? trim.innerTexture(material) : trim.outerTexture(material) + ); VertexConsumer buffer = sprite.wrap( - bufferSource.getBuffer(Sheets.armorTrimsSheet(trim.pattern().value().decal()))); + bufferSource.getBuffer(Sheets.armorTrimsSheet(trim.pattern().value().decal())) + ); modelPart.render(poseStack, buffer, packedLight, packedOverlay); } if (armorStack.hasFoil()) - modelPart.render(poseStack, - getVanillaArmorBuffer(bufferSource, animatable, armorStack, slot, bone, null, packedLight, - packedOverlay, true), packedLight, packedOverlay, 1); + modelPart.render( + poseStack, + getVanillaArmorBuffer( + bufferSource, + animatable, + armorStack, + slot, + bone, + null, + packedLight, + packedOverlay, + true + ), + packedLight, + packedOverlay, + 1 + ); } - protected VertexConsumer getVanillaArmorBuffer(MultiBufferSource bufferSource, T animatable, ItemStack stack, EquipmentSlot slot, GeoBone bone, @Nullable ArmorMaterial.Layer layer, int packedLight, int packedOverlay, boolean forGlint) { + protected VertexConsumer getVanillaArmorBuffer( + MultiBufferSource bufferSource, + T animatable, + ItemStack stack, + EquipmentSlot slot, + GeoBone bone, + @Nullable ArmorMaterial.Layer layer, + int packedLight, + int packedOverlay, + boolean forGlint + ) { if (forGlint) return bufferSource.getBuffer(RenderType.armorEntityGlint()); @@ -279,16 +325,18 @@ protected HumanoidModel getModelForItem(GeoBone bone, EquipmentSlot slot, Ite * Render a given {@link AbstractSkullBlock} as a worn armor piece in relation to a given {@link GeoBone} */ protected void renderSkullAsArmor( - PoseStack poseStack, - GeoBone bone, - ItemStack stack, - AbstractSkullBlock skullBlock, - MultiBufferSource bufferSource, - int packedLight + PoseStack poseStack, + GeoBone bone, + ItemStack stack, + AbstractSkullBlock skullBlock, + MultiBufferSource bufferSource, + int packedLight ) { SkullBlock.Type type = skullBlock.getType(); - SkullModelBase model = SkullBlockRenderer.createSkullRenderers(Minecraft.getInstance().getEntityModels()).get( - type); + SkullModelBase model = SkullBlockRenderer.createSkullRenderers(Minecraft.getInstance().getEntityModels()) + .get( + type + ); RenderType renderType = SkullBlockRenderer.getRenderType(type, stack.get(DataComponents.PROFILE)); poseStack.pushPose(); @@ -321,9 +369,9 @@ protected void prepModelPartForRender(PoseStack poseStack, GeoBone bone, ModelPa float scaleZ = (float) (armorBoneSizeZ / actualArmorSizeZ); sourcePart.setPos( - -(bone.getPivotX() - ((bone.getPivotX() * scaleX) - bone.getPivotX()) / scaleX), - -(bone.getPivotY() - ((bone.getPivotY() * scaleY) - bone.getPivotY()) / scaleY), - (bone.getPivotZ() - ((bone.getPivotZ() * scaleZ) - bone.getPivotZ()) / scaleZ) + -(bone.getPivotX() - ((bone.getPivotX() * scaleX) - bone.getPivotX()) / scaleX), + -(bone.getPivotY() - ((bone.getPivotY() * scaleY) - bone.getPivotY()) / scaleY), + (bone.getPivotZ() - ((bone.getPivotZ() * scaleZ) - bone.getPivotZ()) / scaleZ) ); sourcePart.xRot = -bone.getRotX(); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/ai/pathing/AzureNavigation.java b/common/src/main/java/mod/azure/azurelib/common/api/common/ai/pathing/AzureNavigation.java index 1f35492af..6c38cbc5a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/ai/pathing/AzureNavigation.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/ai/pathing/AzureNavigation.java @@ -1,6 +1,5 @@ package mod.azure.azurelib.common.api.common.ai.pathing; -import mod.azure.azurelib.common.internal.common.ai.pathing.AzurePathFinder; import net.minecraft.core.BlockPos; import net.minecraft.tags.BlockTags; import net.minecraft.util.Mth; @@ -16,6 +15,8 @@ import java.util.Objects; +import mod.azure.azurelib.common.internal.common.ai.pathing.AzurePathFinder; + /* * Credit to Bob Mowzie and pau101 for most of the code, code source for the base class can be found here: * https://github.com/BobMowzie/MowziesMobs/blob/master/src/main/java/com/bobmowzie/mowziesmobs/server/ai/ @@ -24,6 +25,7 @@ public class AzureNavigation extends GroundPathNavigation { static final float EPSILON = 1.0E-8F; + @Nullable protected BlockPos pathToPosition; @@ -40,8 +42,8 @@ public AzureNavigation(Mob entity, Level world) { /** * Forces the entity to stop its current pathfinding by clearing both the {@code path} and {@code pathToPosition}. - * Unlike the normal {@code stop()} method, this ensures that {@code pathToPosition} is cleared as well, - * preventing potential pathfinding issues caused by lingering path data. + * Unlike the normal {@code stop()} method, this ensures that {@code pathToPosition} is cleared as well, preventing + * potential pathfinding issues caused by lingering path data. *

* Special thanks to JayZX535 for contributing this method. */ @@ -79,8 +81,12 @@ protected void followThePath() { } final Vec3 base = entityPos.add(-this.mob.getBbWidth() * 0.5F, 0.0F, -this.mob.getBbWidth() * 0.5F); final Vec3 max = base.add(this.mob.getBbWidth(), this.mob.getBbHeight(), this.mob.getBbWidth()); - if (this.tryShortcut(path, new Vec3(this.mob.getX(), this.mob.getY(), this.mob.getZ()), pathLength, base, max)) { - if (this.isAt(path, 0.5F) || this.atElevationChange(path) && this.isAt(path, this.mob.getBbWidth() * 0.5F)) { + if ( + this.tryShortcut(path, new Vec3(this.mob.getX(), this.mob.getY(), this.mob.getZ()), pathLength, base, max) + ) { + if ( + this.isAt(path, 0.5F) || this.atElevationChange(path) && this.isAt(path, this.mob.getBbWidth() * 0.5F) + ) { path.setNextNodeIndex(path.getNextNodeIndex() + 1); } } @@ -116,35 +122,35 @@ public void tick() { if (this.isDone()) { if (this.pathToPosition != null) { if ( - this.pathToPosition.closerToCenterThan(this.mob.position(), this.mob.getBbWidth()) || this.mob - .getY() > (double) this.pathToPosition.getY() && BlockPos.containing( - this.pathToPosition.getX(), - this.mob.getY(), - this.pathToPosition.getZ() + this.pathToPosition.closerToCenterThan(this.mob.position(), this.mob.getBbWidth()) || this.mob + .getY() > (double) this.pathToPosition.getY() && BlockPos.containing( + this.pathToPosition.getX(), + this.mob.getY(), + this.pathToPosition.getZ() ).closerToCenterThan(this.mob.position(), this.mob.getBbWidth()) ) { this.pathToPosition = null; } else { this.mob.getMoveControl() - .setWantedPosition( - this.pathToPosition.getX(), - this.pathToPosition.getY(), - this.pathToPosition.getZ(), - this.speedModifier - ); + .setWantedPosition( + this.pathToPosition.getX(), + this.pathToPosition.getY(), + this.pathToPosition.getZ(), + this.speedModifier + ); } } return; } if (this.getTargetPos() != null) this.mob.getLookControl() - .setLookAt(this.getTargetPos().getX(), this.getTargetPos().getY(), this.getTargetPos().getZ()); + .setLookAt(this.getTargetPos().getX(), this.getTargetPos().getY(), this.getTargetPos().getZ()); } private boolean isAt(Path path, float threshold) { final Vec3 pathPos = path.getNextEntityPos(this.mob); return Mth.abs((float) (this.mob.getX() - pathPos.x)) < threshold && Mth.abs( - (float) (this.mob.getZ() - pathPos.z) + (float) (this.mob.getZ() - pathPos.z) ) < threshold && Math.abs(this.mob.getY() - pathPos.y) < 1.0D; } @@ -161,7 +167,7 @@ private boolean atElevationChange(Path path) { } private boolean tryShortcut(Path path, Vec3 entityPos, int pathLength, Vec3 base, Vec3 max) { - for (int i = pathLength; --i > path.getNextNodeIndex(); ) { + for (int i = pathLength; --i > path.getNextNodeIndex();) { final Vec3 vec = path.getEntityPosAtNode(this.mob, i).subtract(entityPos); if (this.sweep(vec, base, max)) { path.setNextNodeIndex(i); @@ -176,7 +182,8 @@ private boolean tryShortcut(Path path, Vec3 entityPos, int pathLength, Vec3 base private boolean sweep(Vec3 vec, Vec3 base, Vec3 max) { float t = 0.0F; float max_t = (float) vec.length(); - if (max_t < EPSILON) return true; + if (max_t < EPSILON) + return true; final float[] tr = new float[3]; final int[] ldi = new int[3]; final int[] tri = new int[3]; @@ -200,9 +207,7 @@ private boolean sweep(Vec3 vec, Vec3 base, Vec3 max) { final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); do { // stepForward - int axis = (tNext[0] < tNext[1]) ? - ((tNext[0] < tNext[2]) ? 0 : 2) : - ((tNext[1] < tNext[2]) ? 1 : 2); + int axis = (tNext[0] < tNext[1]) ? ((tNext[0] < tNext[2]) ? 0 : 2) : ((tNext[1] < tNext[2]) ? 1 : 2); float dt = tNext[axis] - t; t = tNext[axis]; ldi[axis] += step[axis]; @@ -225,14 +230,23 @@ private boolean sweep(Vec3 vec, Vec3 base, Vec3 max) { for (int z = z0; z != z1; z += stepz) { for (int y = y0; y != y1; y += stepy) { BlockState block = this.level.getBlockState(pos.set(x, y, z)); - if (!block.isPathfindable(PathComputationType.LAND)) return false; + if (!block.isPathfindable(PathComputationType.LAND)) + return false; } - PathType below = this.nodeEvaluator.getPathType(new PathfindingContext(mob.level(), mob), x, y0 - 1, z); - if (below == PathType.WATER || below == PathType.LAVA || below == PathType.OPEN) return false; + PathType below = this.nodeEvaluator.getPathType( + new PathfindingContext(mob.level(), mob), + x, + y0 - 1, + z + ); + if (below == PathType.WATER || below == PathType.LAVA || below == PathType.OPEN) + return false; PathType in = this.nodeEvaluator.getPathType(new PathfindingContext(mob.level(), mob), x, y0, z); float priority = this.mob.getPathfindingMalus(in); - if (priority < 0.0F || priority >= 8.0F) return false; - if (in == PathType.DAMAGE_FIRE || in == PathType.DANGER_FIRE || in == PathType.DAMAGE_OTHER) return false; + if (priority < 0.0F || priority >= 8.0F) + return false; + if (in == PathType.DAMAGE_FIRE || in == PathType.DANGER_FIRE || in == PathType.DAMAGE_OTHER) + return false; } } } while (t <= max_t); @@ -249,10 +263,14 @@ static int trailEdgeToInt(float coord, int step) { static float element(Vec3 v, int i) { switch (i) { - case 0: return (float) v.x; - case 1: return (float) v.y; - case 2: return (float) v.z; - default: return 0.0F; + case 0: + return (float) v.x; + case 1: + return (float) v.y; + case 2: + return (float) v.z; + default: + return 0.0F; } } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java index 9e39dc7be..b754f09a2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoBlockEntity.java @@ -1,12 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.common.animatable; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.Nullable; + import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; @@ -16,14 +20,11 @@ import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.AnimationController; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import org.jetbrains.annotations.Nullable; /** * The {@link GeoAnimatable} interface specific to {@link BlockEntity BlockEntities} + * + * @deprecated */ public interface GeoBlockEntity extends GeoAnimatable { @@ -53,8 +54,8 @@ default void setAnimData(SerializableDataTicket dataTicket, D data) { if (level == null) { AzureLib.LOGGER.error( - "Attempting to set animation data for BlockEntity too early! Must wait until after the BlockEntity has been set in the world. ({})", - blockEntity.getClass() + "Attempting to set animation data for BlockEntity too early! Must wait until after the BlockEntity has been set in the world. ({})", + blockEntity.getClass() ); return; @@ -66,9 +67,9 @@ default void setAnimData(SerializableDataTicket dataTicket, D data) { BlockPos pos = blockEntity.getBlockPos(); BlockEntityAnimDataSyncPacket blockEntityAnimDataSyncPacket = new BlockEntityAnimDataSyncPacket<>( - pos, - dataTicket, - data + pos, + dataTicket, + data ); Services.NETWORK.sendToEntitiesTrackingChunk(blockEntityAnimDataSyncPacket, (ServerLevel) level, pos); } @@ -89,8 +90,8 @@ default void triggerAnim(@Nullable String controllerName, String animName) { if (level == null) { AzureLib.LOGGER.error( - "Attempting to trigger an animation for a BlockEntity too early! Must wait until after the BlockEntity has been set in the world. ({})", - blockEntity.getClass() + "Attempting to trigger an animation for a BlockEntity too early! Must wait until after the BlockEntity has been set in the world. ({})", + blockEntity.getClass() ); return; @@ -102,9 +103,9 @@ default void triggerAnim(@Nullable String controllerName, String animName) { BlockPos pos = blockEntity.getBlockPos(); BlockEntityAnimTriggerPacket blockEntityAnimTriggerPacket = new BlockEntityAnimTriggerPacket( - pos, - controllerName, - animName + pos, + controllerName, + animName ); Services.NETWORK.sendToEntitiesTrackingChunk(blockEntityAnimTriggerPacket, (ServerLevel) level, pos); } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java index 3f5b2ea01..b2c393978 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoEntity.java @@ -1,12 +1,13 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.common.animatable; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; + import mod.azure.azurelib.common.api.client.renderer.GeoReplacedEntityRenderer; import mod.azure.azurelib.common.internal.client.util.RenderUtils; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; @@ -16,14 +17,14 @@ import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.AnimationController; -import net.minecraft.world.entity.Entity; -import org.jetbrains.annotations.Nullable; /** * The {@link GeoAnimatable} interface specific to {@link net.minecraft.world.entity.Entity Entities}. This also applies * to Projectiles and other Entity subclasses.
* NOTE: This cannot be used for entities using the {@link GeoReplacedEntityRenderer} as you aren't * extending {@code Entity}. Use {@link GeoReplacedEntity} instead. + * + * @deprecated */ public interface GeoEntity extends GeoAnimatable { @@ -54,10 +55,10 @@ default void setAnimData(SerializableDataTicket dataTicket, D data) { getAnimatableInstanceCache().getManagerForId(entity.getId()).setData(dataTicket, data); } else { EntityAnimDataSyncPacket entityAnimDataSyncPacket = new EntityAnimDataSyncPacket<>( - entity.getId(), - false, - dataTicket, - data + entity.getId(), + false, + dataTicket, + data ); Services.NETWORK.sendToTrackingEntityAndSelf(entityAnimDataSyncPacket, entity); } @@ -79,10 +80,10 @@ default void triggerAnim(@Nullable String controllerName, String animName) { getAnimatableInstanceCache().getManagerForId(entity.getId()).tryTriggerAnimation(controllerName, animName); } else { EntityAnimTriggerPacket entityAnimTriggerPacket = new EntityAnimTriggerPacket( - entity.getId(), - false, - controllerName, - animName + entity.getId(), + false, + controllerName, + animName ); Services.NETWORK.sendToTrackingEntityAndSelf(entityAnimTriggerPacket, entity); } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java index 96a0c192d..0bd150817 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoItem.java @@ -1,24 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.common.animatable; import com.google.common.base.Suppliers; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; -import mod.azure.azurelib.common.internal.common.cache.AnimatableIdCache; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; -import mod.azure.azurelib.core.animatable.instance.SingletonAnimatableInstanceCache; -import mod.azure.azurelib.core.animation.AnimatableManager; -import mod.azure.azurelib.core.animation.ContextAwareAnimatableManager; import net.minecraft.core.component.PatchedDataComponentMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.item.ItemDisplayContext; @@ -31,9 +18,23 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; +import mod.azure.azurelib.common.internal.common.cache.AnimatableIdCache; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; +import mod.azure.azurelib.core.animatable.instance.SingletonAnimatableInstanceCache; +import mod.azure.azurelib.core.animation.AnimatableManager; +import mod.azure.azurelib.core.animation.ContextAwareAnimatableManager; + /** * The {@link GeoAnimatable GeoAnimatable} interface specific to {@link net.minecraft.world.item.Item Items}. This also * applies to armor, as they are just items too. + * + * @deprecated */ public interface GeoItem extends SingletonGeoAnimatable { @@ -69,9 +70,9 @@ static void registerSyncedAnimatable(GeoAnimatable animatable) { */ static long getId(ItemStack stack) { return Optional.ofNullable(stack.getComponentsPatch().get(AzureLib.STACK_ANIMATABLE_ID_COMPONENT.get())) - .filter(Optional::isPresent) - .map(Optional::get) - .orElse(Long.MAX_VALUE); + .filter(Optional::isPresent) + .map(Optional::get) + .orElse(Long.MAX_VALUE); } /** @@ -142,31 +143,31 @@ public ContextBasedAnimatableInstanceCache(GeoAnimatable animatable) { public AnimatableManager getManagerForId(long uniqueId) { if (!this.managers.containsKey(uniqueId)) this.managers.put( - uniqueId, - new ContextAwareAnimatableManager(this.animatable) { - - @Override - protected Map> buildContextOptions( - GeoAnimatable animatable - ) { - Map> map = new EnumMap<>( - ItemDisplayContext.class - ); - - for (ItemDisplayContext context : ItemDisplayContext.values()) { - map.put(context, new AnimatableManager<>(animatable)); - } - - return map; + uniqueId, + new ContextAwareAnimatableManager(this.animatable) { + + @Override + protected Map> buildContextOptions( + GeoAnimatable animatable + ) { + Map> map = new EnumMap<>( + ItemDisplayContext.class + ); + + for (ItemDisplayContext context : ItemDisplayContext.values()) { + map.put(context, new AnimatableManager<>(animatable)); } - @Override - public ItemDisplayContext getCurrentContext() { - ItemDisplayContext context = getData(DataTickets.ITEM_RENDER_PERSPECTIVE); + return map; + } - return context == null ? ItemDisplayContext.NONE : context; - } + @Override + public ItemDisplayContext getCurrentContext() { + ItemDisplayContext context = getData(DataTickets.ITEM_RENDER_PERSPECTIVE); + + return context == null ? ItemDisplayContext.NONE : context; } + } ); return this.managers.get(uniqueId); diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java index da12b83f9..beb5b5436 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/animatable/GeoReplacedEntity.java @@ -1,12 +1,17 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.api.common.animatable; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Supplier; + import mod.azure.azurelib.common.internal.client.RenderProvider; import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; @@ -16,17 +21,14 @@ import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.AnimationController; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; -import java.util.function.Supplier; /** * The {@link GeoAnimatable} interface specific to {@link Entity Entities}. This interface is specifically for * entities replacing the rendering of other, existing entities. + * + * @deprecated */ +@Deprecated(forRemoval = true) public interface GeoReplacedEntity extends SingletonGeoAnimatable { /** @@ -62,10 +64,10 @@ default void setAnimData(Entity relatedEntity, SerializableDataTicket dat getAnimatableInstanceCache().getManagerForId(relatedEntity.getId()).setData(dataTicket, data); } else { EntityAnimDataSyncPacket entityAnimDataSyncPacket = new EntityAnimDataSyncPacket<>( - relatedEntity.getId(), - true, - dataTicket, - data + relatedEntity.getId(), + true, + dataTicket, + data ); Services.NETWORK.sendToTrackingEntityAndSelf(entityAnimDataSyncPacket, relatedEntity); } @@ -84,13 +86,13 @@ default void setAnimData(Entity relatedEntity, SerializableDataTicket dat default void triggerAnim(Entity relatedEntity, @Nullable String controllerName, String animName) { if (relatedEntity.level().isClientSide()) { getAnimatableInstanceCache().getManagerForId(relatedEntity.getId()) - .tryTriggerAnimation(controllerName, animName); + .tryTriggerAnimation(controllerName, animName); } else { EntityAnimTriggerPacket entityAnimTriggerPacket = new EntityAnimTriggerPacket( - relatedEntity.getId(), - true, - controllerName, - animName + relatedEntity.getId(), + true, + controllerName, + animName ); Services.NETWORK.sendToTrackingEntityAndSelf(entityAnimTriggerPacket, relatedEntity); } @@ -111,8 +113,7 @@ default double getTick(Object entity) { // These methods aren't used for GeoReplacedEntity @Override - default void createRenderer(Consumer consumer) { - } + default void createRenderer(Consumer consumer) {} // These methods aren't used for GeoReplacedEntity @Override diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/config/Config.java b/common/src/main/java/mod/azure/azurelib/common/api/common/config/Config.java index a9b9d6fa6..9c566c853 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/config/Config.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/config/Config.java @@ -1,18 +1,16 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.api.common.config; -import mod.azure.azurelib.common.internal.common.config.Configurable; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import mod.azure.azurelib.common.internal.common.config.Configurable; + /** * Config marker annotation. Every registered config class must have this annotation. Inside this class you should * define all configurable fields (cannot be {@code STATIC})!. All configurable fields must be annotated with @@ -54,6 +52,5 @@ */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) - @interface NoAutoSync { - } + @interface NoAutoSync {} } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/config/TestingConfig.java b/common/src/main/java/mod/azure/azurelib/common/api/common/config/TestingConfig.java index a314b7d0a..ea0f090d0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/config/TestingConfig.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/config/TestingConfig.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.api.common.config; -import mod.azure.azurelib.common.internal.client.config.IValidationHandler; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.Configurable; -import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; import net.minecraft.network.chat.Component; import java.util.Arrays; import java.util.regex.Pattern; +import mod.azure.azurelib.common.internal.client.config.IValidationHandler; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.Configurable; +import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; + @Config(id = AzureLib.MOD_ID) public final class TestingConfig { @@ -50,22 +49,22 @@ public final class TestingConfig { @Configurable @Configurable.FixedSize - public boolean[] boolArray = {false, false, true, false}; + public boolean[] boolArray = { false, false, true, false }; @Configurable @Configurable.Range(min = 50, max = 160) - public int[] intArray = {153, 123, 54}; + public int[] intArray = { 153, 123, 54 }; @Configurable - public long[] longArray = {13, 56, 133}; + public long[] longArray = { 13, 56, 133 }; @Configurable @Configurable.DecimalRange(min = 500.0F) - public float[] floatArray = {135.32F, 1561.23F}; + public float[] floatArray = { 135.32F, 1561.23F }; @Configurable @Configurable.ValueUpdateCallback(method = "onUpdate") - public String[] stringArray = {"minecraft:test"}; + public String[] stringArray = { "minecraft:test" }; @Configurable public TestEnum testEnum = TestEnum.C; @@ -76,7 +75,7 @@ public final class TestingConfig { public void onUpdate(String[] value, IValidationHandler handler) { AzureLib.LOGGER.debug(() -> Arrays.toString(value)); handler.setValidationResult( - ValidationResult.warn(Component.translatable("config.azurelib.option.genericwarning")) + ValidationResult.warn(Component.translatable("config.azurelib.option.genericwarning")) ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/entities/AzureVibrationUser.java b/common/src/main/java/mod/azure/azurelib/common/api/common/entities/AzureVibrationUser.java index c753d3047..ef691115d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/entities/AzureVibrationUser.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/entities/AzureVibrationUser.java @@ -79,14 +79,14 @@ public boolean isValidVibration(Holder gameEvent, @NotNull Context co @Override public boolean canReceiveVibration( - @NotNull ServerLevel serverLevel, - @NotNull BlockPos blockPos, - @NotNull Holder gameEvent, - GameEvent.@NotNull Context context + @NotNull ServerLevel serverLevel, + @NotNull BlockPos blockPos, + @NotNull Holder gameEvent, + GameEvent.@NotNull Context context ) { if ( - mob.isNoAi() || mob.isDeadOrDying() || !mob.level().getWorldBorder().isWithinBounds(blockPos) || mob - .isRemoved() + mob.isNoAi() || mob.isDeadOrDying() || !mob.level().getWorldBorder().isWithinBounds(blockPos) || mob + .isRemoved() ) return false; var entity = context.sourceEntity(); @@ -95,12 +95,12 @@ public boolean canReceiveVibration( @Override public void onReceiveVibration( - @NotNull ServerLevel serverLevel, - @NotNull BlockPos blockPos, - @NotNull Holder gameEvent, - @Nullable Entity entity, - @Nullable Entity entity2, - float f + @NotNull ServerLevel serverLevel, + @NotNull BlockPos blockPos, + @NotNull Holder gameEvent, + @Nullable Entity entity, + @Nullable Entity entity2, + float f ) { // Do nothing. } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/helper/CommonUtils.java b/common/src/main/java/mod/azure/azurelib/common/api/common/helper/CommonUtils.java index 1b1eef033..58ab7105e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/helper/CommonUtils.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/helper/CommonUtils.java @@ -1,10 +1,5 @@ package mod.azure.azurelib.common.api.common.helper; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; -import mod.azure.azurelib.common.internal.common.registry.AzureBlocksRegistry; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.common.platform.services.IPlatformHelper; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.particles.ParticleOptions; @@ -13,14 +8,12 @@ import net.minecraft.world.entity.AreaEffectCloud; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.projectile.Projectile; -import net.minecraft.world.entity.projectile.ProjectileUtil; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; +import mod.azure.azurelib.common.internal.common.registry.AzureBlocksRegistry; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; + public record CommonUtils() { /** @@ -36,26 +29,26 @@ public record CommonUtils() { * @param effectTime How long the effect should be applied for? */ public static void summonAoE( - LivingEntity entity, - ParticleOptions particle, - int yOffset, - int duration, - float radius, - boolean hasEffect, - @Nullable Holder effect, - int effectTime + LivingEntity entity, + ParticleOptions particle, + int yOffset, + int duration, + float radius, + boolean hasEffect, + @Nullable Holder effect, + int effectTime ) { var areaEffectCloudEntity = new AreaEffectCloud( - entity.level(), - entity.getX(), - entity.getY() + yOffset, - entity.getZ() + entity.level(), + entity.getX(), + entity.getY() + yOffset, + entity.getZ() ); areaEffectCloudEntity.setRadius(radius); areaEffectCloudEntity.setDuration(duration); areaEffectCloudEntity.setParticle(particle); areaEffectCloudEntity.setRadiusPerTick( - -areaEffectCloudEntity.getRadius() / areaEffectCloudEntity.getDuration() + -areaEffectCloudEntity.getRadius() / areaEffectCloudEntity.getDuration() ); if (hasEffect && effect != null && !entity.hasEffect(effect)) areaEffectCloudEntity.addEffect(new MobEffectInstance(effect, effectTime, 0)); @@ -63,8 +56,8 @@ public static void summonAoE( } /** - * Spawns or refreshes a light source at the position of the firing entity. This method should - * only be called on the server side to place a temporary light-block. + * Spawns or refreshes a light source at the position of the firing entity. This method should only be called on the + * server side to place a temporary light-block. * * @param entity The entity (e.g., player or mob) using the weapon. * @param isInWaterBlock If true, the light-block will refresh faster when in water. @@ -82,7 +75,8 @@ public static void spawnLightSource(Entity entity, boolean isInWaterBlock) { tickingLightEntity.refresh(isInWaterBlock ? 20 : 0); } else { // Otherwise, place a new ticking light block - entity.level().setBlockAndUpdate(lightBlockPos, AzureBlocksRegistry.TICKING_LIGHT_BLOCK.get().defaultBlockState()); + entity.level() + .setBlockAndUpdate(lightBlockPos, AzureBlocksRegistry.TICKING_LIGHT_BLOCK.get().defaultBlockState()); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/interfaces/AzureTicker.java b/common/src/main/java/mod/azure/azurelib/common/api/common/interfaces/AzureTicker.java index e1accbce5..5aaf91afe 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/interfaces/AzureTicker.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/interfaces/AzureTicker.java @@ -1,7 +1,5 @@ package mod.azure.azurelib.common.api.common.interfaces; -import mod.azure.azurelib.common.api.common.entities.AzureVibrationUser; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.VibrationParticleOption; import net.minecraft.server.level.ServerLevel; @@ -12,6 +10,9 @@ import net.minecraft.world.level.gameevent.vibrations.VibrationSystem.Listener; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem.User; +import mod.azure.azurelib.common.api.common.entities.AzureVibrationUser; +import mod.azure.azurelib.common.platform.Services; + /** * Custom class for use with {@link AzureVibrationUser} */ @@ -45,15 +46,15 @@ private static void trySelectAndScheduleVibration(ServerLevel serverLevel, Data data.setTravelTimeInTicks(user.calculateTravelTimeInTicks(vibrationInfo.distance())); if (Services.PLATFORM.isDevelopmentEnvironment()) serverLevel.sendParticles( - new VibrationParticleOption(user.getPositionSource(), data.getTravelTimeInTicks()), - vec3.x, - vec3.y, - vec3.z, - 1, - 0.0, - 0.0, - 0.0, - 0.0 + new VibrationParticleOption(user.getPositionSource(), data.getTravelTimeInTicks()), + vec3.x, + vec3.y, + vec3.z, + 1, + 0.0, + 0.0, + 0.0, + 0.0 ); user.onDataChanged(); data.getSelectionStrategy().startOver(); @@ -61,10 +62,10 @@ private static void trySelectAndScheduleVibration(ServerLevel serverLevel, Data } private static boolean receiveVibration( - ServerLevel serverLevel, - Data data, - User user, - VibrationInfo vibrationInfo + ServerLevel serverLevel, + Data data, + User user, + VibrationInfo vibrationInfo ) { var blockPos = BlockPos.containing(vibrationInfo.pos()); var blockPos2 = user.getPositionSource().getPosition(serverLevel).map(BlockPos::containing).orElse(blockPos); @@ -72,12 +73,12 @@ private static boolean receiveVibration( return false; } user.onReceiveVibration( - serverLevel, - blockPos, - vibrationInfo.gameEvent(), - vibrationInfo.getEntity(serverLevel).orElse(null), - vibrationInfo.getProjectileOwner(serverLevel).orElse(null), - Listener.distanceBetweenInBlocks(blockPos, blockPos2) + serverLevel, + blockPos, + vibrationInfo.gameEvent(), + vibrationInfo.getEntity(serverLevel).orElse(null), + vibrationInfo.getProjectileOwner(serverLevel).orElse(null), + Listener.distanceBetweenInBlocks(blockPos, blockPos2) ); data.setCurrentVibration(null); return true; diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonArmorMaterialRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonArmorMaterialRegistryInterface.java deleted file mode 100644 index 0922c338f..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonArmorMaterialRegistryInterface.java +++ /dev/null @@ -1,55 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import mod.azure.azurelib.common.platform.Services; -import net.minecraft.core.Holder; -import net.minecraft.world.item.ArmorMaterial; - -import java.util.function.Supplier; - -/** - * Example of using this Interface to create a new Item: - *

- * The following code demonstrates how to register a new armor material in the game: - *

- *
{@code
- * public static final Holder TEST_ARMOR_MATERIAL = CommonArmorMaterialRegistryInterface.registerArmorMaterial("modid", "materialname", YOURCLASS::dummyArmorMaterial);
- *
- * private static ArmorMaterial dummyArmorMaterial() {
- *     ArmorMaterial diamond = ArmorMaterials.DIAMOND.value();
- *     return new ArmorMaterial(
- *         diamond.defense(),
- *         diamond.enchantmentValue(),
- *         diamond.equipSound(),
- *         diamond.repairIngredient(),
- *         List.of(), // If your Material has other layers like Player Armors inner/outer
- *         diamond.toughness(),
- *         diamond.knockbackResistance()
- *     );
- * }
- * }
- *

- * In this example: - *

- *
    - *
  • registerArmorMaterial is a method to register a new armor material with the specified mod ID and material name.
  • - *
  • dummyArmorMaterial creates a new instance of ArmorMaterial using the properties of the existing ArmorMaterials.DIAMOND.
  • - *
- *

- * The {@link net.minecraft.world.item.ArmorMaterial ArmorMaterial} class represents the material properties for an armor item. - *

- */ -public interface CommonArmorMaterialRegistryInterface { - - /** - * Registers a new Armor Material. - * - * @param modID The mod ID. - * @param matName The name of the material. - * @param armorMaterial A supplier for the armor material. - * @param The type of the armor material. - * @return A holder for the registered armor material. - */ - static Holder registerArmorMaterial(String modID, String matName, Supplier armorMaterial) { - return Services.COMMON_REGISTRY.registerArmorMaterial(modID, matName, armorMaterial); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockEntityRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockEntityRegistryInterface.java index 9ccbaf53f..ac2b878d4 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockEntityRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockEntityRegistryInterface.java @@ -1,29 +1,40 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new Block Entity: *

* The following code demonstrates how to register a new block entity type in the game: *

+ * *
{@code
- * public static final Supplier> TEST_BLOCKENTITY = CommonBlockEntityRegistryInterface.registerBlockEntity("modid", "blockentityname", () -> BlockEntityType.Builder.of(TestBlockEntity::new, TEST_BLOCK.get()).build(null));
+ *
+ * public static final Supplier> TEST_BLOCKENTITY = CommonBlockEntityRegistryInterface
+ *     .registerBlockEntity(
+ *         "modid",
+ *         "blockentityname",
+ *         () -> BlockEntityType.Builder.of(TestBlockEntity::new, TEST_BLOCK.get()).build(null)
+ *     );
  * }
*

* In this example: *

*
    - *
  • registerBlockEntity is a method to register a new block entity with the specified mod ID and block entity name.
  • - *
  • TestBlockEntity::new is a reference to the constructor of the TestBlockEntity class.
  • + *
  • registerBlockEntity is a method to register a new block entity with the specified mod ID and block + * entity name.
  • + *
  • TestBlockEntity::new is a reference to the constructor of the TestBlockEntity + * class.
  • *
  • TEST_BLOCK.get() is a reference to the block associated with this block entity.
  • *
*

- * The {@link net.minecraft.world.level.block.entity.BlockEntityType BlockEntityType} class represents a block entity type in the game. + * The {@link net.minecraft.world.level.block.entity.BlockEntityType BlockEntityType} class represents a block entity + * type in the game. *

*/ public interface CommonBlockEntityRegistryInterface { @@ -37,7 +48,11 @@ public interface CommonBlockEntityRegistryInterface { * @param The type of the block entity. * @return A supplier for the registered block entity type. */ - static Supplier> registerBlockEntity(String modID, String blockEntityName, Supplier> blockEntity) { + static Supplier> registerBlockEntity( + String modID, + String blockEntityName, + Supplier> blockEntity + ) { return Services.COMMON_REGISTRY.registerBlockEntity(modID, blockEntityName, blockEntity); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockRegistryInterface.java index 129e1e181..06a8a5c98 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockRegistryInterface.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonBlockRegistryInterface.java @@ -1,17 +1,24 @@ package mod.azure.azurelib.common.api.common.registry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.world.level.block.Block; import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.Services; + /** * Example of using this Interface to create a new Block: *

* The following code demonstrates how to register a new block in the game: *

+ * *
{@code
- * public static final Supplier TEST_BLOCK = CommonBlockRegistryInterface.registerBlock("modid", "blockname", TestBlock::new);
+ *
+ * public static final Supplier TEST_BLOCK = CommonBlockRegistryInterface.registerBlock(
+ *     "modid",
+ *     "blockname",
+ *     TestBlock::new
+ * );
  * }
*

* In this example: @@ -38,4 +45,4 @@ public interface CommonBlockRegistryInterface { static Supplier registerBlock(String modID, String blockName, Supplier block) { return Services.COMMON_REGISTRY.registerBlock(modID, blockName, block); } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonCreativeTabRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonCreativeTabRegistryInterface.java deleted file mode 100644 index 76edcdeb9..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonCreativeTabRegistryInterface.java +++ /dev/null @@ -1,30 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -/** - * Example of using this Interface to create a new Creative Tab: - *

- * The following code demonstrates how to register a new creative mode tab in the game: - *

- *
{@code
- * public static final Supplier EXAMPLEMOD_TAB = Services.COMMON_REGISTRY.registerCreativeModeTab(
- *         AzureLib.MOD_ID,
- *         "examplemod_items",
- *         () -> Services.COMMON_REGISTRY.newCreativeTabBuilder()
- *             .title(Component.translatable("itemGroup." + AzureLib.MOD_ID + ".examplemod_items"))
- *             .icon(() -> new ItemStack(Items.ITEM_FRAME))
- *             .displayItems((enabledFeatures, entries) -> entries.accept(Items.ITEM_FRAME))
- *             .build());
- * }
- *

- * In this example: - *

- *
    - *
  • registerCreativeModeTab is a method to register a new creative mode tab with the specified mod ID and tab name.
  • - *
  • The newCreativeTabBuilder method is used to build the creative tab with a title, icon, and displayed items.
  • - *
- *

- * The {@link net.minecraft.world.item.CreativeModeTab CreativeModeTab} class represents a tab in the creative inventory menu. - *

- */ -public interface CommonCreativeTabRegistryInterface { -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonEntityRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonEntityRegistryInterface.java deleted file mode 100644 index 2b965cc2f..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonEntityRegistryInterface.java +++ /dev/null @@ -1,49 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import mod.azure.azurelib.common.platform.Services; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.MobCategory; - -import java.util.function.Supplier; - -/** - * Example of using this Interface to create a new Entity: - *

- * The following code demonstrates how to register a new entity type in the game: - *

- *
{@code
- * public static final Supplier> TEST = CommonEntityRegistryInterface.registerEntity("modid", "entityname", TestEntity::new, MobCategory.CREATURE, 0.7f, 1.3f);
- * }
- *

- * In this example: - *

- *
    - *
  • registerEntity is a method to register a new entity with the specified mod ID, entity name, factory method, dimensions, and spawn egg colors.
  • - *
  • TestEntity::new is a reference to the constructor of the TestEntity class.
  • - *
  • 0.7f and 1.3f represent the width and height of the entity, respectively.
  • - *
  • 0x1F1F1F and 0x0D0D0D represent the primary and secondary colors of the entity's spawn egg.
  • - *
- *

- * The {@link net.minecraft.world.entity.EntityType EntityType} class represents an entity type in the game. - *

- */ -public interface CommonEntityRegistryInterface { - - /** - * Registers a new entity type. - * - * @param modID The mod ID. - * @param entityName The name of the entity. - * @param entity The factory method for creating instances of the entity. - * @param width The width of the entity. - * @param height The height of the entity. - * @param The type of the entity. - * @return A supplier for the registered entity type. - */ - static Supplier> registerEntity(String modID, String entityName, EntityType.EntityFactory entity, MobCategory mobCategory, float width, float height) { - return Services.COMMON_REGISTRY.registerEntity(modID, entityName, - () -> EntityType.Builder.of(entity, mobCategory).sized(width, height).build(entityName)); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonFluidRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonFluidRegistryInterface.java deleted file mode 100644 index 159754ec0..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonFluidRegistryInterface.java +++ /dev/null @@ -1,42 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import mod.azure.azurelib.common.platform.Services; -import net.minecraft.world.level.material.Fluid; - -import java.util.function.Supplier; - -/** - * Example of using this Interface to create a new Fluid: - *

- * The following code demonstrates how to register a new Fluid in the game: - *

- *
{@code
- * public static final Supplier TEST_FLUID = CommonFluidRegistryInterface.registerFluid("modid", "fluidName", () -> new CustomFluid());
- * }
- *

- * In this example: - *

- *
    - *
  • registerFluid is a method to register a new fluid with the specified mod ID and fluid name.
  • - *
  • Fluid is the base class for all fluids in the game.
  • - *
  • CustomFluid is a user-defined class extending Fluid.
  • - *
- *

- * The {@link net.minecraft.world.level.material.Fluid Fluid} class represents a fluid in the game. - *

- */ -public interface CommonFluidRegistryInterface { - - /** - * Registers a new fluid. - * - * @param modID The mod ID. - * @param itemName The name of the fluid. - * @param fluid A supplier that provides an instance of the fluid. - * @param The type of the fluid extending from {@link Fluid}. - * @return A supplier that provides the registered fluid. - */ - static Supplier registerFluid(String modID, String itemName, Supplier fluid) { - return Services.COMMON_REGISTRY.registerFluid(modID, itemName, fluid); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonItemRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonItemRegistryInterface.java deleted file mode 100644 index 991d2798f..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonItemRegistryInterface.java +++ /dev/null @@ -1,46 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import mod.azure.azurelib.common.platform.Services; -import net.minecraft.world.item.Item; - -import java.util.function.Supplier; - -/** - * Example of using this Interface to create a new Item: - *

- * The following code demonstrates how to register a new item and a spawn egg in the game: - *

- *
{@code
- * public static final Supplier TEST_ITEM = CommonItemRegistryInterface.registerItem("modid", "itemname", () -> new Item(new Item.Properties()));
- * public static final Supplier TEST_SPAWN_EGG = CommonItemRegistryInterface.registerItem("modid", "entityname_spawn_egg", Services.COMMON_REGISTRY.makeSpawnEggFor(TESTENTITY, 0x1F1F1F, 0x0D0D0D, new Item.Properties()));
- * }
- *

- * In this example: - *

- *
    - *
  • registerItem is a method to register a new item with the specified mod ID and item name.
  • - *
  • Item is used to create a new item instance with default properties.
  • - *
  • makeSpawnEggFor is a method to create a spawn egg for the specified entity with primary and secondary colors.
  • - *
- *

- * The {@link net.minecraft.world.item.Item Item} class represents an item in the game. - *

- *

- * The {@link net.minecraft.world.item.SpawnEggItem SpawnEggItem} class represents a spawn egg in the game. - *

- */ -public interface CommonItemRegistryInterface { - - /** - * Registers a new Item. - * - * @param modID The mod ID. - * @param itemName The name of the item. - * @param item A supplier for the item. - * @param The type of the item. - * @return A supplier for the registered item. - */ - static Supplier registerItem(String modID, String itemName, Supplier item) { - return Services.COMMON_REGISTRY.registerItem(modID, itemName, item); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonMenuTypesRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonMenuTypesRegistryInterface.java deleted file mode 100644 index 2abc3a70a..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonMenuTypesRegistryInterface.java +++ /dev/null @@ -1,41 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import mod.azure.azurelib.common.platform.Services; -import net.minecraft.world.inventory.MenuType; - -import java.util.function.Supplier; - -/** - * Example of using this Interface to create a new MenuType: - *

- * The following code demonstrates how to register a new screen type in the game: - *

- *
{@code
- * public static final Supplier> TEST = CommonMenuTypesRegistryInterface.registerScreen("modid", "screenname", () -> new MenuType<>(CustomScreenHandler::new, FeatureFlags.VANILLA_SET));
- * }
- *

- * In this example: - *

- *
    - *
  • registerScreen is a method to register a new screen type with the specified mod ID and screen name.
  • - *
  • MenuType is used to create a new screen type instance.
  • - *
- *

- * The {@link net.minecraft.world.inventory.MenuType MenuType} class represents a type of screen in the game. - *

- */ -public interface CommonMenuTypesRegistryInterface { - - /** - * Registers a new screen type. - * - * @param modID The mod ID. - * @param screenName The name of the screen. - * @param item A supplier for the screen type. - * @param The type of the screen type. - * @return A supplier for the registered screen type. - */ - static > Supplier registerScreen(String modID, String screenName, Supplier item) { - return Services.COMMON_REGISTRY.registerScreen(modID, screenName, item); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonParticleRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonParticleRegistryInterface.java deleted file mode 100644 index 46ea086f9..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonParticleRegistryInterface.java +++ /dev/null @@ -1,41 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import mod.azure.azurelib.common.platform.Services; -import net.minecraft.core.particles.ParticleType; - -import java.util.function.Supplier; - -/** - * Example of using this Interface to create a new Particle: - *

- * The following code demonstrates how to register a new particle type in the game: - *

- *
{@code
- * public static final Supplier TEST = CommonParticleRegistryInterface.registerParticle("modid", "particlename", () -> new SimpleParticleType(true));
- * }
- *

- * In this example: - *

- *
    - *
  • registerParticle is a method to register a new particle with the specified mod ID and particle name.
  • - *
  • SimpleParticleType is used to create a new particle type instance.
  • - *
- *

- * The {@link net.minecraft.core.particles.SimpleParticleType SimpleParticleType} class represents a basic particle type in the game. - *

- */ -public interface CommonParticleRegistryInterface { - - /** - * Registers a new Particle. - * - * @param modID The mod ID. - * @param particleName The ID of the particle. - * @param particle A supplier for the particle type. - * @param The type of the particle type. - * @return A supplier for the registered particle type. - */ - static > Supplier registerParticle(String modID, String particleName, Supplier particle) { - return Services.COMMON_REGISTRY.registerParticle(modID, particleName, particle); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonSoundRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonSoundRegistryInterface.java deleted file mode 100644 index a3c4ca6bd..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonSoundRegistryInterface.java +++ /dev/null @@ -1,42 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import mod.azure.azurelib.common.platform.Services; -import net.minecraft.sounds.SoundEvent; - -import java.util.function.Supplier; - -/** - * Example of using this Interface to create a new SoundEvent: - *

- * The following code demonstrates how to register a new sound event in the game: - *

- *
{@code
- * public static Supplier TEST_SOUND = CommonSoundRegistryInterface.registerSound("modid", "test_sound", () -> SoundEvent.createVariableRangeEvent(
- *             ResourceLocation.fromNamespaceAndPath("modid", "test_sound")));
- * }
- *

- * In this example: - *

- *
    - *
  • registerSound is a method to register a new sound event with the specified mod ID and sound name.
  • - *
  • SoundEvent is used to create a new sound event instance.
  • - *
- *

- * The {@link net.minecraft.sounds.SoundEvent SoundEvent} class represents a sound event in the game. - *

- */ -public interface CommonSoundRegistryInterface { - - /** - * Registers a new sound event. - * - * @param modID The mod ID. - * @param soundName The name of the sound event. - * @param sound A supplier for the sound event. - * @param The type of the sound event. - * @return A supplier for the registered sound event. - */ - static Supplier registerSound(String modID, String soundName, Supplier sound) { - return Services.COMMON_REGISTRY.registerSound(modID, soundName, sound); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStatusEffectRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStatusEffectRegistryInterface.java deleted file mode 100644 index 5f8fecf17..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStatusEffectRegistryInterface.java +++ /dev/null @@ -1,49 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import mod.azure.azurelib.common.platform.Services; -import net.minecraft.core.Holder; -import net.minecraft.world.effect.MobEffect; - -import java.util.function.Supplier; - -/** - * Example of using this Interface to create a new Status Effect: - *

- * The following code demonstrates how to register a new Status Effect in the game: - *

- *
{@code
- * public static final Holder TEST_EFFECT = CommonStatusEffectRegistryInterface.registerStatusEffect("modid", "effectName", () -> new CustomMobEffect(
- *             MobEffectCategory.HARMFUL, Color.BLACK.getColor()));
- * }
- *

- * In this example: - *

- *
    - *
  • registerStatusEffect is a method to register a new status effect with the specified mod ID and effect name.
  • - *
  • MobEffect is the base class for all status effects in the game.
  • - *
  • CustomMobEffect is a user-defined class extending MobEffect.
  • - *
  • MobEffectCategory.HARMFUL specifies the category of the status effect.
  • - *
  • Color.BLACK.getColor() specifies the color of the status effect.
  • - *
- *

- * The {@link net.minecraft.world.effect.MobEffect MobEffect} class represents a status effect in the game. - *

- *

- * The {@link net.minecraft.world.effect.MobEffectCategory MobEffectCategory} class represents the category of a status effect in the game. - *

- */ -public interface CommonStatusEffectRegistryInterface { - - /** - * Registers a new Status Effect. - * - * @param modID The mod ID. - * @param effectName The name of the Status Effect. - * @param statusEffect A supplier that provides an instance of the Status Effect. - * @param The type of the status effect extending from {@link net.minecraft.world.effect.MobEffect}. - * @return A holder that provides the registered status effect. - */ - static Holder registerStatusEffect(String modID, String effectName, Supplier statusEffect) { - return Services.COMMON_REGISTRY.registerStatusEffect(modID, effectName, statusEffect); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStructureRegistryInterface.java b/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStructureRegistryInterface.java deleted file mode 100644 index 41e439d24..000000000 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/registry/CommonStructureRegistryInterface.java +++ /dev/null @@ -1,42 +0,0 @@ -package mod.azure.azurelib.common.api.common.registry; - -import com.mojang.serialization.MapCodec; -import mod.azure.azurelib.common.platform.Services; -import net.minecraft.world.level.levelgen.structure.Structure; -import net.minecraft.world.level.levelgen.structure.StructureType; - -import java.util.function.Supplier; - -/** - * Example of using this Interface to create a new Structure: - *

- * The following code demonstrates how to register a new structure in the game: - *

- *
{@code
- * public static final Supplier> TEST = CommonStructureRegistryInterface.registerStructure("modid", "structurename", CustomStructure.CODEC);
- * }
- *

- * In this example: - *

- *
    - *
  • registerStructure is a method to register a new structure type with the specified mod ID and structure name.
  • - *
  • "modid" is the identifier for your mod.
  • - *
  • "structurename" is the name you want to give to your new structure.
  • - *
  • CustomStructure.CODEC is the codec for your custom structure type.
  • - *
- */ -public interface CommonStructureRegistryInterface { - - /** - * Registers a new structure. - * - * @param modID The mod ID. - * @param structureName The name of the structure. - * @param structure A codec for the structure type. - * @param The type of the structure. - * @return A supplier for the registered structure type. - */ - static Supplier> registerStructure(String modID, String structureName, MapCodec structure) { - return Services.COMMON_REGISTRY.registerStructure(modID, structureName, structure); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/common/api/common/tags/AzureTags.java b/common/src/main/java/mod/azure/azurelib/common/api/common/tags/AzureTags.java index bba97f5d7..e065f31ba 100644 --- a/common/src/main/java/mod/azure/azurelib/common/api/common/tags/AzureTags.java +++ b/common/src/main/java/mod/azure/azurelib/common/api/common/tags/AzureTags.java @@ -1,10 +1,11 @@ package mod.azure.azurelib.common.api.common.tags; -import mod.azure.azurelib.common.internal.common.AzureLib; import net.minecraft.core.registries.Registries; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; +import mod.azure.azurelib.common.internal.common.AzureLib; + public final class AzureTags { public static final TagKey GUNS = TagKey.create(Registries.ITEM, AzureLib.modResource("guns")); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/AzureLibClient.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/AzureLibClient.java index 819fc6cb3..2e3140066 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/AzureLibClient.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/AzureLibClient.java @@ -1,10 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ - package mod.azure.azurelib.common.internal.client; +package mod.azure.azurelib.common.internal.client; + +import net.minecraft.client.gui.screens.Screen; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; import mod.azure.azurelib.common.api.common.config.Config; import mod.azure.azurelib.common.internal.client.config.screen.ConfigGroupScreen; @@ -12,11 +16,6 @@ import mod.azure.azurelib.common.internal.common.config.ConfigHolder; import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import net.minecraft.client.gui.screens.Screen; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Map; public final class AzureLibClient { @@ -51,8 +50,8 @@ public static Screen getConfigScreen(Class configClass, Screen previous) { @Nullable public static Screen getConfigScreen(String configId, Screen previous) { return ConfigHolderRegistry.getConfig(configId) - .map(holder -> getConfigScreenForHolder(holder, previous)) - .orElse(null); + .map(holder -> getConfigScreenForHolder(holder, previous)) + .orElse(null); } /** diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java index 5c0352309..607605054 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/RenderProvider.java @@ -1,13 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ - package mod.azure.azurelib.common.internal.client; +package mod.azure.azurelib.common.internal.client; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.mixins.ItemRendererAccessor; import net.minecraft.client.Minecraft; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.Model; @@ -17,14 +13,19 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.mixins.ItemRendererAccessor; + /** * Internal interface for safely providing a custom renderer instances at runtime.
* This can be safely instantiated as a new anonymous class inside your {@link Item} class + * + * @deprecated */ +@Deprecated(forRemoval = true) public interface RenderProvider { - RenderProvider DEFAULT = new RenderProvider() { - }; + RenderProvider DEFAULT = new RenderProvider() {}; static RenderProvider of(ItemStack itemStack) { return of(itemStack.getItem()); @@ -43,16 +44,16 @@ default BlockEntityWithoutLevelRenderer getCustomRenderer() { } default Model getGenericArmorModel( - LivingEntity livingEntity, - ItemStack itemStack, - EquipmentSlot equipmentSlot, - HumanoidModel original + LivingEntity livingEntity, + ItemStack itemStack, + EquipmentSlot equipmentSlot, + HumanoidModel original ) { HumanoidModel replacement = getHumanoidArmorModel( - livingEntity, - itemStack, - equipmentSlot, - original + livingEntity, + itemStack, + equipmentSlot, + original ); if (replacement != original) { @@ -64,10 +65,10 @@ default Model getGenericArmorModel( } default HumanoidModel getHumanoidArmorModel( - LivingEntity livingEntity, - ItemStack itemStack, - EquipmentSlot equipmentSlot, - HumanoidModel original + LivingEntity livingEntity, + ItemStack itemStack, + EquipmentSlot equipmentSlot, + HumanoidModel original ) { return original; } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/ClientErrors.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/ClientErrors.java index 8dcdbc1f9..4504ff1f3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/ClientErrors.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/ClientErrors.java @@ -1,22 +1,21 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config; -import mod.azure.azurelib.common.internal.common.config.value.DecimalValue; -import mod.azure.azurelib.common.internal.common.config.value.IntegerValue; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import java.util.regex.Pattern; +import mod.azure.azurelib.common.internal.common.config.value.DecimalValue; +import mod.azure.azurelib.common.internal.common.config.value.IntegerValue; + public final class ClientErrors { public static final MutableComponent CHAR_VALUE_EMPTY = Component.translatable( - "text.azurelib.error.character_value_empty" + "text.azurelib.error.character_value_empty" ); private static final String KEY_NAN = "text.azurelib.error.nan"; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapter.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapter.java index f3e63dcb1..e671f4811 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapter.java @@ -1,21 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config; -import mod.azure.azurelib.common.internal.client.config.screen.ArrayConfigScreen; -import mod.azure.azurelib.common.internal.client.config.screen.ConfigScreen; -import mod.azure.azurelib.common.internal.client.config.widget.BooleanWidget; -import mod.azure.azurelib.common.internal.client.config.widget.ColorWidget; -import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; -import mod.azure.azurelib.common.internal.client.config.widget.EnumWidget; -import mod.azure.azurelib.common.internal.common.config.ConfigUtils; -import mod.azure.azurelib.common.internal.common.config.Configurable; -import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; -import mod.azure.azurelib.common.internal.common.config.value.*; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; @@ -30,30 +18,41 @@ import java.util.function.BiConsumer; import java.util.regex.Pattern; +import mod.azure.azurelib.common.internal.client.config.screen.ArrayConfigScreen; +import mod.azure.azurelib.common.internal.client.config.screen.ConfigScreen; +import mod.azure.azurelib.common.internal.client.config.widget.BooleanWidget; +import mod.azure.azurelib.common.internal.client.config.widget.ColorWidget; +import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; +import mod.azure.azurelib.common.internal.client.config.widget.EnumWidget; +import mod.azure.azurelib.common.internal.common.config.ConfigUtils; +import mod.azure.azurelib.common.internal.common.config.Configurable; +import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; +import mod.azure.azurelib.common.internal.common.config.value.*; + @FunctionalInterface public interface DisplayAdapter { static DisplayAdapter booleanValue() { return (value, field, container) -> container.addConfigWidget( - (x, y, width, height, configId) -> new BooleanWidget( - getValueX(x, width), - y, - getValueWidth(width), - 20, - (BooleanValue) value - ) + (x, y, width, height, configId) -> new BooleanWidget( + getValueX(x, width), + y, + getValueWidth(width), + 20, + (BooleanValue) value + ) ); } static DisplayAdapter characterValue() { return (value, field, container) -> container.addConfigWidget((x, y, width, height, configId) -> { EditBox widget = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); CharValue charValue = (CharValue) value; char character = charValue.get(); @@ -76,12 +75,12 @@ static DisplayAdapter characterValue() { static DisplayAdapter integerValue() { return (value, field, container) -> container.addConfigWidget((x, y, width, height, configId) -> { EditBox tfw = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); IntValue intValue = (IntValue) value; int num = intValue.get(); @@ -115,12 +114,12 @@ static DisplayAdapter integerValue() { static DisplayAdapter longValue() { return (value, field, container) -> container.addConfigWidget((x, y, width, height, configId) -> { EditBox tfw = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); LongValue longValue = (LongValue) value; long num = longValue.get(); @@ -154,12 +153,12 @@ static DisplayAdapter longValue() { static DisplayAdapter floatValue() { return (value, field, container) -> container.addConfigWidget((x, y, width, height, configId) -> { EditBox tfw = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); FloatValue floatValue = (FloatValue) value; DecimalFormat format = ConfigUtils.getDecimalFormat(field); @@ -194,12 +193,12 @@ static DisplayAdapter floatValue() { static DisplayAdapter doubleValue() { return (value, field, container) -> container.addConfigWidget((x, y, width, height, configId) -> { EditBox tfw = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); DoubleValue doubleValue = (DoubleValue) value; DecimalFormat format = ConfigUtils.getDecimalFormat(field); @@ -237,12 +236,12 @@ static DisplayAdapter stringValue() { StringValue strValue = (StringValue) value; EditBox widget = container.addConfigWidget((x, y, width, height, configId) -> { EditBox tfw = new EditBox( - Minecraft.getInstance().font, - getValueX(x, width), - y, - getValueWidth(width), - 20, - CommonComponents.EMPTY + Minecraft.getInstance().font, + getValueX(x, width), + y, + getValueWidth(width), + 20, + CommonComponents.EMPTY ); String val = strValue.get(); tfw.setValue(val); @@ -252,8 +251,8 @@ static DisplayAdapter stringValue() { if (!pattern.matcher(str).matches()) { String errDescriptor = strValue.getErrorDescriptor(); MutableComponent error = errDescriptor != null - ? Component.translatable(errDescriptor, str, pattern) - : ClientErrors.invalidText(str, pattern); + ? Component.translatable(errDescriptor, str, pattern) + : ClientErrors.invalidText(str, pattern); container.setValidationResult(ValidationResult.error(error)); return; } @@ -287,16 +286,16 @@ static DisplayAdapter booleanArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { boolean[] arr = arrayValue.get(); return new BooleanValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Boolean.TYPE, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Boolean.TYPE, setCallback, i)) ); }); screen.addElement(() -> { @@ -313,9 +312,9 @@ static DisplayAdapter booleanArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } @@ -331,16 +330,16 @@ static DisplayAdapter integerArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { int[] arr = arrayValue.get(); return new IntValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Integer.TYPE, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Integer.TYPE, setCallback, i)) ); }); screen.addElement(() -> { @@ -357,9 +356,9 @@ static DisplayAdapter integerArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } @@ -375,16 +374,16 @@ static DisplayAdapter longArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { long[] arr = arrayValue.get(); return new LongValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Long.TYPE, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Long.TYPE, setCallback, i)) ); }); screen.addElement(() -> { @@ -401,9 +400,9 @@ static DisplayAdapter longArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } @@ -419,16 +418,16 @@ static DisplayAdapter floatArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { float[] arr = arrayValue.get(); return new FloatValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Float.TYPE, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Float.TYPE, setCallback, i)) ); }); screen.addElement(() -> { @@ -445,9 +444,9 @@ static DisplayAdapter floatArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } @@ -463,16 +462,16 @@ static DisplayAdapter doubleArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { double[] arr = arrayValue.get(); return new DoubleValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Double.TYPE, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, Double.TYPE, setCallback, i)) ); }); screen.addElement(() -> { @@ -489,9 +488,9 @@ static DisplayAdapter doubleArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } @@ -507,16 +506,16 @@ static DisplayAdapter stringArrayValue() { Minecraft client = Minecraft.getInstance(); Screen usedScreen = client.screen; ArrayConfigScreen screen = new ArrayConfigScreen<>( - value.getId(), - configId, - arrayValue, - usedScreen + value.getId(), + configId, + arrayValue, + usedScreen ); screen.fetchSize(() -> arrayValue.get().length); screen.valueFactory((id, i) -> { String[] arr = arrayValue.get(); return new StringValue( - ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, String.class, setCallback, i)) + ValueData.of(id, arr[i], ArrayConfigScreen.callbackCtx(field, String.class, setCallback, i)) ); }); screen.addElement(() -> { @@ -533,21 +532,21 @@ static DisplayAdapter stringArrayValue() { client.setScreen(screen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } static DisplayAdapter enumValue() { return (value, field, container) -> container.addConfigWidget( - (x, y, width, height, configId) -> new EnumWidget<>( - getValueX(x, width), - y, - getValueWidth(width), - 20, - (EnumValue) value - ) + (x, y, width, height, configId) -> new EnumWidget<>( + getValueX(x, width), + y, + getValueWidth(width), + 20, + (EnumValue) value + ) ); } @@ -559,17 +558,17 @@ static DisplayAdapter objectValue() { Minecraft client = Minecraft.getInstance(); Screen currentScreen = client.screen; Screen nestedConfigScreen = new ConfigScreen( - container.getComponentName(), - configId, - valueMap, - currentScreen + container.getComponentName(), + configId, + valueMap, + currentScreen ); client.setScreen(nestedConfigScreen); }; return Button.builder(ConfigEntryWidget.EDIT, pressable) - .pos(getValueX(x, width), y) - .size(getValueWidth(width), 20) - .build(); + .pos(getValueX(x, width), y) + .size(getValueWidth(width), 20) + .build(); }); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapterManager.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapterManager.java index a8fc773c4..32e8963e4 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapterManager.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/DisplayAdapterManager.java @@ -1,17 +1,15 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeMatcher; - import java.util.Comparator; import java.util.HashMap; import java.util.Map; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeMatcher; + public final class DisplayAdapterManager { private static final Map ADAPTER_MAP = new HashMap<>(); @@ -40,12 +38,12 @@ private DisplayAdapterManager() { public static DisplayAdapter forType(Class type) { return ADAPTER_MAP.entrySet() - .stream() - .filter(entry -> entry.getKey().test(type)) - .sorted(Comparator.comparingInt(value -> value.getKey().priority())) - .map(Map.Entry::getValue) - .findFirst() - .orElse(null); + .stream() + .filter(entry -> entry.getKey().test(type)) + .sorted(Comparator.comparingInt(value -> value.getKey().priority())) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null); } public static void registerDisplayAdapter(TypeMatcher matcher, DisplayAdapter adapter) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/IValidationHandler.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/IValidationHandler.java index 61b1a65c5..4a97eaac7 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/IValidationHandler.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/IValidationHandler.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/WidgetAdder.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/WidgetAdder.java index f02760a48..779c284f1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/WidgetAdder.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/WidgetAdder.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/AbstractConfigScreen.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/AbstractConfigScreen.java index ea9840708..8e829c7fa 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/AbstractConfigScreen.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/AbstractConfigScreen.java @@ -1,21 +1,11 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.screen; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; -import mod.azure.azurelib.common.internal.client.config.IValidationHandler; -import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; -import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.config.value.ObjectValue; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; @@ -34,6 +24,15 @@ import java.util.Collection; import java.util.List; +import mod.azure.azurelib.common.internal.client.config.IValidationHandler; +import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; +import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; +import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.config.value.ObjectValue; + public abstract class AbstractConfigScreen extends Screen { public static final int HEADER_HEIGHT = 35; @@ -57,14 +56,14 @@ protected AbstractConfigScreen(Component title, Screen previous, String configId } public static void renderScrollbar( - GuiGraphics graphics, - int x, - int y, - int width, - int height, - int index, - int valueCount, - int paging + GuiGraphics graphics, + int x, + int y, + int width, + int height, + int index, + int valueCount, + int paging ) { if (valueCount <= paging) return; @@ -89,12 +88,26 @@ public void onClose() { protected void addFooter() { int centerY = this.height - FOOTER_HEIGHT + (FOOTER_HEIGHT - 20) / 2; addRenderableWidget( - Button.builder(ConfigEntryWidget.BACK, this::buttonBackClicked).pos(20, centerY).size(50, 20).build()); + Button.builder(ConfigEntryWidget.BACK, this::buttonBackClicked).pos(20, centerY).size(50, 20).build() + ); + addRenderableWidget( + Button.builder(ConfigEntryWidget.REVERT_DEFAULTS, this::buttonRevertToDefaultClicked) + .pos( + 75, + centerY + ) + .size(120, 20) + .build() + ); addRenderableWidget( - Button.builder(ConfigEntryWidget.REVERT_DEFAULTS, this::buttonRevertToDefaultClicked).pos(75, - centerY).size(120, 20).build()); - addRenderableWidget(Button.builder(ConfigEntryWidget.REVERT_CHANGES, this::buttonRevertChangesClicked).pos(200, - centerY).size(120, 20).build()); + Button.builder(ConfigEntryWidget.REVERT_CHANGES, this::buttonRevertChangesClicked) + .pos( + 200, + centerY + ) + .size(120, 20) + .build() + ); } protected void correctScrollingIndex(int count) { @@ -118,9 +131,9 @@ private void buttonBackClicked(Button button) { private void buttonRevertToDefaultClicked(Button button) { DialogScreen dialog = new DialogScreen( - ConfigEntryWidget.REVERT_DEFAULTS, - new Component[]{ConfigEntryWidget.REVERT_DEFAULTS_DIALOG_TEXT}, - this + ConfigEntryWidget.REVERT_DEFAULTS, + new Component[] { ConfigEntryWidget.REVERT_DEFAULTS_DIALOG_TEXT }, + this ); dialog.onConfirmed(screen -> { AzureLib.LOGGER.info(MARKER, "Reverting config {} to default values", this.configId); @@ -135,9 +148,9 @@ private void buttonRevertToDefaultClicked(Button button) { private void buttonRevertChangesClicked(Button button) { DialogScreen dialog = new DialogScreen( - ConfigEntryWidget.REVERT_CHANGES, - new Component[]{ConfigEntryWidget.REVERT_CHANGES_DIALOG_TEXT}, - this + ConfigEntryWidget.REVERT_CHANGES, + new Component[] { ConfigEntryWidget.REVERT_CHANGES_DIALOG_TEXT }, + this ); dialog.onConfirmed(screen -> { ConfigHolderRegistry.getConfig(this.configId).ifPresent(ConfigIO::reloadClientValues); @@ -172,11 +185,11 @@ private void saveConfig(boolean force) { } public void renderNotification( - NotificationSeverity severity, - GuiGraphics graphics, - List texts, - int mouseX, - int mouseY + NotificationSeverity severity, + GuiGraphics graphics, + List texts, + int mouseX, + int mouseY ) { if (!texts.isEmpty()) { int maxTextWidth = 0; @@ -213,24 +226,87 @@ public void renderNotification( int fadeMax = severity.fadeMax; int zIndex = 400; Matrix4f matrix4f = stack.last().pose(); - graphics.fillGradient(startX - 3, startY - 4, startX + maxTextWidth + 3, startY - 3, zIndex, background, - background); - graphics.fillGradient(startX - 3, startY + heightOffset + 3, startX + maxTextWidth + 3, - startY + heightOffset + 4, zIndex, background, background); - graphics.fillGradient(startX - 3, startY - 3, startX + maxTextWidth + 3, startY + heightOffset + 3, zIndex, - background, background); - graphics.fillGradient(startX - 4, startY - 3, startX - 3, startY + heightOffset + 3, zIndex, background, - background); - graphics.fillGradient(startX + maxTextWidth + 3, startY - 3, startX + maxTextWidth + 4, - startY + heightOffset + 3, zIndex, background, background); - graphics.fillGradient(startX - 3, startY - 3 + 1, startX - 3 + 1, startY + heightOffset + 3 - 1, zIndex, - fadeMin, fadeMax); - graphics.fillGradient(startX + maxTextWidth + 2, startY - 3 + 1, startX + maxTextWidth + 3, - startY + heightOffset + 3 - 1, zIndex, fadeMin, fadeMax); - graphics.fillGradient(startX - 3, startY - 3, startX + maxTextWidth + 3, startY - 3 + 1, zIndex, fadeMin, - fadeMin); - graphics.fillGradient(startX - 3, startY + heightOffset + 2, startX + maxTextWidth + 3, - startY + heightOffset + 3, zIndex, fadeMax, fadeMax); + graphics.fillGradient( + startX - 3, + startY - 4, + startX + maxTextWidth + 3, + startY - 3, + zIndex, + background, + background + ); + graphics.fillGradient( + startX - 3, + startY + heightOffset + 3, + startX + maxTextWidth + 3, + startY + heightOffset + 4, + zIndex, + background, + background + ); + graphics.fillGradient( + startX - 3, + startY - 3, + startX + maxTextWidth + 3, + startY + heightOffset + 3, + zIndex, + background, + background + ); + graphics.fillGradient( + startX - 4, + startY - 3, + startX - 3, + startY + heightOffset + 3, + zIndex, + background, + background + ); + graphics.fillGradient( + startX + maxTextWidth + 3, + startY - 3, + startX + maxTextWidth + 4, + startY + heightOffset + 3, + zIndex, + background, + background + ); + graphics.fillGradient( + startX - 3, + startY - 3 + 1, + startX - 3 + 1, + startY + heightOffset + 3 - 1, + zIndex, + fadeMin, + fadeMax + ); + graphics.fillGradient( + startX + maxTextWidth + 2, + startY - 3 + 1, + startX + maxTextWidth + 3, + startY + heightOffset + 3 - 1, + zIndex, + fadeMin, + fadeMax + ); + graphics.fillGradient( + startX - 3, + startY - 3, + startX + maxTextWidth + 3, + startY - 3 + 1, + zIndex, + fadeMin, + fadeMin + ); + graphics.fillGradient( + startX - 3, + startY + heightOffset + 2, + startX + maxTextWidth + 3, + startY + heightOffset + 3, + zIndex, + fadeMax, + fadeMax + ); RenderSystem.enableDepthTest(); RenderSystem.enableBlend(); RenderSystem.defaultBlendFunc(); @@ -238,8 +314,10 @@ public void renderNotification( if (!severity.isOkStatus()) { Tesselator tessellator = Tesselator.getInstance(); RenderSystem.setShader(GameRenderer::getPositionColorShader); - BufferBuilder bufferbuilder = tessellator.begin(VertexFormat.Mode.QUADS, - DefaultVertexFormat.POSITION_TEX); + BufferBuilder bufferbuilder = tessellator.begin( + VertexFormat.Mode.QUADS, + DefaultVertexFormat.POSITION_TEX + ); ResourceLocation icon = severity.getIcon(); RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, icon); @@ -252,7 +330,6 @@ public void renderNotification( BufferUploader.drawWithShader(bufferbuilder.buildOrThrow()); } - RenderSystem.disableBlend(); MultiBufferSource.BufferSource bufferSource = Minecraft.getInstance().renderBuffers().bufferSource(); stack.translate(0.0D, 0.0D, zIndex); @@ -261,8 +338,18 @@ public void renderNotification( for (int i = 0; i < texts.size(); i++) { FormattedCharSequence textComponent = texts.get(i); if (textComponent != null) { - this.font.drawInBatch(textComponent, (float) startX + textOffset, (float) startY, -1, true, - matrix4f, bufferSource, Font.DisplayMode.NORMAL, 0, 0xf000f0); + this.font.drawInBatch( + textComponent, + (float) startX + textOffset, + (float) startY, + -1, + true, + matrix4f, + bufferSource, + Font.DisplayMode.NORMAL, + 0, + 0xf000f0 + ); } if (i == 0) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ArrayConfigScreen.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ArrayConfigScreen.java index adf03b1f4..dab0e62c5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ArrayConfigScreen.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ArrayConfigScreen.java @@ -1,20 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.screen; -import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; -import mod.azure.azurelib.common.internal.client.config.DisplayAdapterManager; -import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapters; -import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; -import mod.azure.azurelib.common.internal.common.config.value.ArrayValue; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.Button; @@ -27,6 +16,16 @@ import java.util.function.BiConsumer; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; +import mod.azure.azurelib.common.internal.client.config.DisplayAdapterManager; +import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapters; +import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; +import mod.azure.azurelib.common.internal.common.config.value.ArrayValue; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; + public class ArrayConfigScreen & ArrayValue> extends AbstractConfigScreen { public static final Component ADD_ELEMENT = Component.translatable("text.azurelib.value.add_element"); @@ -45,19 +44,19 @@ public class ArrayConfigScreen & ArrayValue> extends public ArrayConfigScreen(String ownerIdentifier, String configId, C array, Screen previous) { super( - Component.translatable(String.format("config.%s.option.%s", configId, ownerIdentifier)), - previous, - configId + Component.translatable(String.format("config.%s.option.%s", configId, ownerIdentifier)), + previous, + configId ); this.array = array; this.fixedSize = array.isFixedSize(); } public static TypeAdapter.AdapterContext callbackCtx( - Field parent, - Class componentType, - BiConsumer callback, - int index + Field parent, + Class componentType, + BiConsumer callback, + int index ) { return new DummyCallbackAdapter<>(componentType, parent, callback, index); } @@ -101,17 +100,23 @@ protected void init() { ConfigValue dummy = valueFactory.create(array.getId(), i); dummy.processFieldData(owner); ConfigEntryWidget widget = addRenderableWidget( - new ConfigEntryWidget(30, viewportMin + 10 + j * 25 + offset, this.width - 60, 20, dummy, - this.configId) + new ConfigEntryWidget( + 30, + viewportMin + 10 + j * 25 + offset, + this.width - 60, + 20, + dummy, + this.configId + ) ); widget.setDescriptionRenderer( - (graphics, widget1, severity, text) -> renderEntryDescription(graphics, widget1, severity, text) + (graphics, widget1, severity, text) -> renderEntryDescription(graphics, widget1, severity, text) ); if (adapter == null) { AzureLib.LOGGER.error( - MARKER, - "Missing display adapter for {} type, will not be displayed in GUI", - compType.getSimpleName() + MARKER, + "Missing display adapter for {} type, will not be displayed in GUI", + compType.getSimpleName() ); continue; } @@ -120,10 +125,10 @@ protected void init() { initializeGuiValue(dummy, widget); } catch (ClassCastException e) { AzureLib.LOGGER.error( - MARKER, - "Unable to create config field for {} type due to error {}", - compType.getSimpleName(), - e + MARKER, + "Unable to create config field for {} type due to error {}", + compType.getSimpleName(), + e ); } if (!fixedSize) { @@ -142,18 +147,18 @@ protected void init() { } private void renderEntryDescription( - GuiGraphics graphics, - AbstractWidget widget, - NotificationSeverity severity, - List text + GuiGraphics graphics, + AbstractWidget widget, + NotificationSeverity severity, + List text ) { if (!severity.isOkStatus()) { this.renderNotification( - severity, - graphics, - text, - widget.getX() + 5, - widget.getY() + widget.getHeight() + 10 + severity, + graphics, + text, + widget.getX() + 5, + widget.getY() + widget.getHeight() + 10 ); } } @@ -163,11 +168,26 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTi renderBackground(graphics, mouseX, mouseY, partialTicks); // HEADER int titleWidth = this.font.width(this.title); - graphics.drawString(font, this.title, (this.width - titleWidth) / 2, (HEADER_HEIGHT - this.font.lineHeight) / 2, 0xFFFFFF); + graphics.drawString( + font, + this.title, + (this.width - titleWidth) / 2, + (HEADER_HEIGHT - this.font.lineHeight) / 2, + 0xFFFFFF + ); graphics.fill(0, 0, width, HEADER_HEIGHT, 0x99 << 24); graphics.fill(0, height - FOOTER_HEIGHT, width, height, 0x99 << 24); graphics.fill(0, HEADER_HEIGHT, width, height - FOOTER_HEIGHT, 0x55 << 24); - renderScrollbar(graphics, width - 5, HEADER_HEIGHT, 5, height - FOOTER_HEIGHT - HEADER_HEIGHT, index, sizeSupplier.get(), pageSize); + renderScrollbar( + graphics, + width - 5, + HEADER_HEIGHT, + 5, + height - FOOTER_HEIGHT - HEADER_HEIGHT, + index, + sizeSupplier.get(), + pageSize + ); renderables.forEach(renderable -> renderable.render(graphics, mouseX, mouseY, partialTicks)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigGroupScreen.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigGroupScreen.java index 338e675b0..6f44d87db 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigGroupScreen.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigGroupScreen.java @@ -1,14 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.screen; -import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; -import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; -import mod.azure.azurelib.common.internal.common.config.ConfigHolder; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractWidget; @@ -19,6 +14,10 @@ import java.util.List; +import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; +import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; +import mod.azure.azurelib.common.internal.common.config.ConfigHolder; + import static mod.azure.azurelib.common.internal.client.config.screen.AbstractConfigScreen.FOOTER_HEIGHT; import static mod.azure.azurelib.common.internal.client.config.screen.AbstractConfigScreen.HEADER_HEIGHT; @@ -62,22 +61,22 @@ protected void init() { int y = viewportMin + 10 + j * 25 + offset; String configId = value.getConfigId(); this.addRenderableWidget( - new LeftAlignedLabel( - posX, - y, - componentWidth, - 20, - Component.translatable("config.screen." + configId), - this.font - ) + new LeftAlignedLabel( + posX, + y, + componentWidth, + 20, + Component.translatable("config.screen." + configId), + this.font + ) ); this.addRenderableWidget(Button.builder(ConfigEntryWidget.EDIT, btn -> { - ConfigScreen screen = new ConfigScreen(configId, configId, value.getValueMap(), this); - minecraft.setScreen(screen); - }) - .pos(DisplayAdapter.getValueX(posX, componentWidth), y) - .size(DisplayAdapter.getValueWidth(componentWidth), 20) - .build()); + ConfigScreen screen = new ConfigScreen(configId, configId, value.getValueMap(), this); + minecraft.setScreen(screen); + }) + .pos(DisplayAdapter.getValueX(posX, componentWidth), y) + .size(DisplayAdapter.getValueWidth(componentWidth), 20) + .build()); } initFooter(); } @@ -87,21 +86,36 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTi renderBackground(graphics, mouseX, mouseY, partialTicks); // HEADER int titleWidth = this.font.width(this.title); - graphics.drawString(font, this.title, (this.width - titleWidth) / 2, (HEADER_HEIGHT - this.font.lineHeight) / 2, 0xFFFFFF); + graphics.drawString( + font, + this.title, + (this.width - titleWidth) / 2, + (HEADER_HEIGHT - this.font.lineHeight) / 2, + 0xFFFFFF + ); graphics.fill(0, 0, width, HEADER_HEIGHT, 0x99 << 24); graphics.fill(0, height - FOOTER_HEIGHT, width, height, 0x99 << 24); graphics.fill(0, HEADER_HEIGHT, width, height - FOOTER_HEIGHT, 0x55 << 24); - AbstractConfigScreen.renderScrollbar(graphics, width - 5, HEADER_HEIGHT, 5, height - FOOTER_HEIGHT - HEADER_HEIGHT, index, configHolders.size(), pageSize); + AbstractConfigScreen.renderScrollbar( + graphics, + width - 5, + HEADER_HEIGHT, + 5, + height - FOOTER_HEIGHT - HEADER_HEIGHT, + index, + configHolders.size(), + pageSize + ); renderables.forEach(renderable -> renderable.render(graphics, mouseX, mouseY, partialTicks)); } protected void initFooter() { int centerY = this.height - FOOTER_HEIGHT + (FOOTER_HEIGHT - 20) / 2; addRenderableWidget( - Button.builder(ConfigEntryWidget.BACK, btn -> minecraft.setScreen(last)) - .pos(20, centerY) - .size(50, 20) - .build() + Button.builder(ConfigEntryWidget.BACK, btn -> minecraft.setScreen(last)) + .pos(20, centerY) + .size(50, 20) + .build() ); } @@ -133,17 +147,16 @@ public LeftAlignedLabel(int x, int y, int width, int height, Component label, Fo } @Override - public void updateWidgetNarration(NarrationElementOutput narrationElementOutput) { - } + public void updateWidgetNarration(NarrationElementOutput narrationElementOutput) {} @Override public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { graphics.drawString( - font, - this.getMessage(), - this.getX(), - this.getY() + (this.height - this.font.lineHeight) / 2, - 0xAAAAAA + font, + this.getMessage(), + this.getX(), + this.getY() + (this.height - this.font.lineHeight) / 2, + 0xAAAAAA ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigScreen.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigScreen.java index 3c2d195af..3182833a9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigScreen.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/ConfigScreen.java @@ -1,18 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.screen; -import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; -import mod.azure.azurelib.common.internal.client.config.DisplayAdapterManager; -import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.screens.Screen; @@ -25,15 +16,23 @@ import java.util.List; import java.util.Map; +import mod.azure.azurelib.common.internal.client.config.DisplayAdapter; +import mod.azure.azurelib.common.internal.client.config.DisplayAdapterManager; +import mod.azure.azurelib.common.internal.client.config.widget.ConfigEntryWidget; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; + public class ConfigScreen extends AbstractConfigScreen { private final Map> valueMap; public ConfigScreen( - String ownerIdentifier, - String configId, - Map> valueMap, - Screen previous + String ownerIdentifier, + String configId, + Map> valueMap, + Screen previous ) { this(Component.translatable("config.screen." + ownerIdentifier), configId, valueMap, previous); } @@ -45,7 +44,6 @@ public ConfigScreen(Component screenTitle, String configId, Map value = values.get(i); - ConfigEntryWidget widget = addRenderableWidget(new ConfigEntryWidget(30, viewportMin + 10 + j * 25 + offset, this.width - 60, 20, value, this.configId)); - widget.setDescriptionRenderer((graphics, widget1, severity, text) -> renderEntryDescription(graphics, widget1, severity, text)); + ConfigEntryWidget widget = addRenderableWidget( + new ConfigEntryWidget(30, viewportMin + 10 + j * 25 + offset, this.width - 60, 20, value, this.configId) + ); + widget.setDescriptionRenderer( + (graphics, widget1, severity, text) -> renderEntryDescription(graphics, widget1, severity, text) + ); TypeAdapter.AdapterContext context = value.getSerializationContext(); Field field = context.getOwner(); DisplayAdapter adapter = DisplayAdapterManager.forType(field.getType()); if (adapter == null) { AzureLib.LOGGER.error( - MARKER, - "Missing display adapter for {} type, will not be displayed in GUI", - field.getType().getSimpleName() + MARKER, + "Missing display adapter for {} type, will not be displayed in GUI", + field.getType().getSimpleName() ); continue; } @@ -79,10 +81,10 @@ protected void init() { initializeGuiValue(value, widget); } catch (ClassCastException e) { AzureLib.LOGGER.error( - MARKER, - "Unable to create config field for {} type due to error {}", - field.getType().getSimpleName(), - e + MARKER, + "Unable to create config field for {} type due to error {}", + field.getType().getSimpleName(), + e ); } } @@ -90,10 +92,10 @@ protected void init() { } private void renderEntryDescription( - GuiGraphics graphics, - AbstractWidget widget, - NotificationSeverity severity, - List text + GuiGraphics graphics, + AbstractWidget widget, + NotificationSeverity severity, + List text ) { int x = widget.getX() + 5; int y = widget.getY() + widget.getHeight() + 10; @@ -109,12 +111,28 @@ public void render(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float renderBackground(graphics, mouseX, mouseY, partialTicks); // HEADER int titleWidth = this.font.width(this.title); - graphics.drawString(font, this.title, (this.width - titleWidth) / 2, (HEADER_HEIGHT - this.font.lineHeight) / 2, 0xFFFFFF, true); + graphics.drawString( + font, + this.title, + (this.width - titleWidth) / 2, + (HEADER_HEIGHT - this.font.lineHeight) / 2, + 0xFFFFFF, + true + ); graphics.setColor(1.0F, 1.0F, 1.0F, 1.0F); graphics.fill(0, 0, width, HEADER_HEIGHT, 0x99 << 24); graphics.fill(0, height - FOOTER_HEIGHT, width, height, 0x99 << 24); graphics.fill(0, HEADER_HEIGHT, width, height - FOOTER_HEIGHT, 0x55 << 24); - renderScrollbar(graphics, width - 5, HEADER_HEIGHT, 5, height - FOOTER_HEIGHT - HEADER_HEIGHT, index, valueMap.size(), pageSize); + renderScrollbar( + graphics, + width - 5, + HEADER_HEIGHT, + 5, + height - FOOTER_HEIGHT - HEADER_HEIGHT, + index, + valueMap.size(), + pageSize + ); renderables.forEach(renderable -> renderable.render(graphics, mouseX, mouseY, partialTicks)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/DialogScreen.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/DialogScreen.java index 84f01b6f7..2696559ef 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/DialogScreen.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/screen/DialogScreen.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.screen; @@ -20,14 +18,23 @@ public class DialogScreen extends Screen { public static final Component TEXT_CONFIRM = Component.translatable("text.azurelib.screen.dialog.confirm"); public static final Component TEXT_CANCEL = Component.translatable("text.azurelib.screen.dialog.cancel"); + protected final Component[] text; + private final Screen background; + protected int dialogWidth; + protected int dialogHeight; + protected int dialogLeft; + protected int dialogTop; + private DialogRespondEvent onCancel; + private DialogRespondEvent onConfirm; + private List splitText = new ArrayList<>(); public DialogScreen(Component title, Component[] text, Screen background) { @@ -53,9 +60,9 @@ public void setDimensions(int dialogWidth, int dialogHeight) { this.dialogLeft = (this.width - this.dialogWidth) / 2; this.dialogTop = (this.height - this.dialogHeight) / 2; this.splitText = Arrays.stream(this.text) - .map(line -> this.font.split(line, this.dialogWidth - 10)) - .flatMap(Collection::stream) - .toList(); + .map(line -> this.font.split(line, this.dialogWidth - 10)) + .flatMap(Collection::stream) + .toList(); } @Override @@ -71,8 +78,22 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTi this.background.render(graphics, mouseX, mouseY, partialTicks); graphics.pose().pushPose(); graphics.pose().translate(0, 0, 400); - graphics.fillGradient(this.dialogLeft - 1, this.dialogTop - 1, this.dialogLeft + this.dialogWidth + 1, this.dialogTop + this.dialogHeight + 1, 0xFFFFFFFF, 0xFFFFFFFF); - graphics.fillGradient(this.dialogLeft, this.dialogTop, this.dialogLeft + this.dialogWidth, this.dialogTop + this.dialogHeight, backgroundColor, backgroundColor); + graphics.fillGradient( + this.dialogLeft - 1, + this.dialogTop - 1, + this.dialogLeft + this.dialogWidth + 1, + this.dialogTop + this.dialogHeight + 1, + 0xFFFFFFFF, + 0xFFFFFFFF + ); + graphics.fillGradient( + this.dialogLeft, + this.dialogTop, + this.dialogLeft + this.dialogWidth, + this.dialogTop + this.dialogHeight, + backgroundColor, + backgroundColor + ); this.renderForeground(graphics, mouseX, mouseY, partialTicks); renderables.forEach(renderable -> renderable.render(graphics, mouseX, mouseY, partialTicks)); graphics.pose().popPose(); @@ -96,22 +117,22 @@ public boolean keyPressed(int keyCode, int scanCode, int modifiers) { protected void renderForeground(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { int headerWidth = this.font.width(this.title); graphics.drawString( - this.font, - this.title, - (int) (this.dialogLeft + (this.dialogWidth - headerWidth) / 2.0F), - this.dialogTop + 5, - 0xFFFFFF, - true + this.font, + this.title, + (int) (this.dialogLeft + (this.dialogWidth - headerWidth) / 2.0F), + this.dialogTop + 5, + 0xFFFFFF, + true ); int line = 0; for (FormattedCharSequence textLine : this.splitText) { graphics.drawString( - this.font, - textLine, - this.dialogLeft + 5, - this.dialogTop + 20 + line * 10, - 0xFFFFFF, - true + this.font, + textLine, + this.dialogLeft + 5, + this.dialogTop + 20 + line * 10, + 0xFFFFFF, + true ); ++line; } @@ -125,11 +146,16 @@ protected void addDefaultDialogButtons() { int componentY = this.dialogTop + this.dialogHeight - 25; this.addRenderableWidget( - Button.builder(TEXT_CANCEL, btn -> cancel()).pos(cancelX, componentY).size(componentWidth, 20).build() + Button.builder(TEXT_CANCEL, btn -> cancel()).pos(cancelX, componentY).size(componentWidth, 20).build() ); this.addRenderableWidget( - Button.builder(TEXT_CONFIRM, btn -> confirm()).pos(confirmX, componentY).size(componentWidth, - 20).build() + Button.builder(TEXT_CONFIRM, btn -> confirm()) + .pos(confirmX, componentY) + .size( + componentWidth, + 20 + ) + .build() ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/BooleanWidget.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/BooleanWidget.java index fe0778033..3e54bfe1c 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/BooleanWidget.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/BooleanWidget.java @@ -1,13 +1,10 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.widget; import com.mojang.blaze3d.systems.RenderSystem; -import mod.azure.azurelib.common.internal.common.config.value.BooleanValue; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; @@ -21,17 +18,22 @@ import net.minecraft.util.Mth; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.internal.common.config.value.BooleanValue; + public class BooleanWidget extends AbstractWidget { public static final Component TRUE = Component.translatable("text.azurelib.value.true") - .withStyle(ChatFormatting.GREEN); + .withStyle(ChatFormatting.GREEN); + public static final Component FALSE = Component.translatable("text.azurelib.value.false") - .withStyle(ChatFormatting.RED); + .withStyle(ChatFormatting.RED); + private static final WidgetSprites SPRITES = new WidgetSprites( - ResourceLocation.parse("widget/button"), - ResourceLocation.parse("widget/button_disabled"), - ResourceLocation.parse("widget/button_highlighted") + ResourceLocation.parse("widget/button"), + ResourceLocation.parse("widget/button_disabled"), + ResourceLocation.parse("widget/button_highlighted") ); + private final BooleanValue value; public BooleanWidget(int x, int y, int w, int h, BooleanValue value) { @@ -47,11 +49,11 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float par RenderSystem.enableBlend(); RenderSystem.enableDepthTest(); graphics.blitSprite( - SPRITES.get(this.active, this.isHoveredOrFocused()), - this.getX(), - this.getY(), - this.getWidth(), - this.getHeight() + SPRITES.get(this.active, this.isHoveredOrFocused()), + this.getX(), + this.getY(), + this.getWidth(), + this.getHeight() ); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); int i = this.active ? 0xffffff : 0xa0a0a0; @@ -68,8 +70,7 @@ public void onClick(double x, double y) { } @Override - protected void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) { - } + protected void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) {} private void readState() { boolean value = this.value.get(); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ColorWidget.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ColorWidget.java index 0f2aa1842..dc8689969 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ColorWidget.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ColorWidget.java @@ -1,13 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.widget; -import mod.azure.azurelib.common.internal.client.config.screen.DialogScreen; -import mod.azure.azurelib.common.internal.common.config.Configurable; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractSliderButton; @@ -26,6 +22,9 @@ import java.util.function.IntSupplier; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.client.config.screen.DialogScreen; +import mod.azure.azurelib.common.internal.common.config.Configurable; + public final class ColorWidget extends AbstractWidget { public static final Component SELECT_COLOR = Component.translatable("text.azurelib.screen.color_dialog"); @@ -41,13 +40,13 @@ public final class ColorWidget extends AbstractWidget { private final Screen lastScreen; public ColorWidget( - int x, - int y, - int width, - int height, - Configurable.Gui.ColorValue colorOptions, - GetSet colorWidget, - Screen lastScreen + int x, + int y, + int width, + int height, + Configurable.Gui.ColorValue colorOptions, + GetSet colorWidget, + Screen lastScreen ) { super(x, y, width, height, CommonComponents.EMPTY); this.argb = colorOptions.isARGB(); @@ -71,19 +70,19 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float par int providedColor = this.colorSupplier.getAsInt(); int color = this.argb ? providedColor : (0xFF << 24) | providedColor; graphics.fill( - this.getX() - 1, - this.getY() - 1, - this.getX() + this.width + 1, - this.getY() + this.height + 1, - borderColor + this.getX() - 1, + this.getY() - 1, + this.getX() + this.width + 1, + this.getY() + this.height + 1, + borderColor ); graphics.fillGradient( - this.getX(), - this.getY(), - this.getX() + this.width, - this.getY() + this.height, - 0xFFFFFFFF, - 0xFF888888 + this.getX(), + this.getY(), + this.getX() + this.width, + this.getY() + this.height, + 0xFFFFFFFF, + 0xFF888888 ); graphics.fill(this.getX(), this.getY(), this.getX() + this.width, this.getY() + this.height, color); } @@ -96,10 +95,10 @@ protected boolean isValidClickButton(int button) { @Override public void onClick(double mouseX, double mouseY) { ColorSelectorDialog dialog = new ColorSelectorDialog( - SELECT_COLOR, - this.lastScreen, - this.argb, - this.colorSupplier + SELECT_COLOR, + this.lastScreen, + this.argb, + this.colorSupplier ); dialog.onConfirmed(screen -> { int color = dialog.getResultColor(); @@ -111,8 +110,7 @@ public void onClick(double mouseX, double mouseY) { } @Override - public void updateWidgetNarration(@NotNull NarrationElementOutput elementOutput) { - } + public void updateWidgetNarration(@NotNull NarrationElementOutput elementOutput) {} public interface GetSet { @@ -145,10 +143,10 @@ private static final class ColorSelectorDialog extends DialogScreen { private final List sliders = new ArrayList<>(); public ColorSelectorDialog( - Component title, - Screen background, - boolean allowTransparency, - IntSupplier colorProvider + Component title, + Screen background, + boolean allowTransparency, + IntSupplier colorProvider ) { super(title, new Component[0], background); this.argb = allowTransparency; @@ -170,71 +168,70 @@ protected void init() { this.setDimensions(width, height); int color = this.colorProvider.getAsInt(); this.sliders.add( - this.addRenderableWidget( - new ColorSlider( - dialogLeft + 5, - dialogTop + 20, - dialogWidth - rightMargin, - 20, - color, - ColorComponent.RED - ) + this.addRenderableWidget( + new ColorSlider( + dialogLeft + 5, + dialogTop + 20, + dialogWidth - rightMargin, + 20, + color, + ColorComponent.RED ) + ) ); this.sliders.add( - this.addRenderableWidget( - new ColorSlider( - dialogLeft + 5, - dialogTop + 45, - dialogWidth - rightMargin, - 20, - color, - ColorComponent.GREEN - ) + this.addRenderableWidget( + new ColorSlider( + dialogLeft + 5, + dialogTop + 45, + dialogWidth - rightMargin, + 20, + color, + ColorComponent.GREEN ) + ) ); this.sliders.add( - this.addRenderableWidget( - new ColorSlider( - dialogLeft + 5, - dialogTop + 70, - dialogWidth - rightMargin, - 20, - color, - ColorComponent.BLUE - ) + this.addRenderableWidget( + new ColorSlider( + dialogLeft + 5, + dialogTop + 70, + dialogWidth - rightMargin, + 20, + color, + ColorComponent.BLUE ) + ) ); if (this.argb) { this.sliders.add( - this.addRenderableWidget( - new ColorSlider( - dialogLeft + 5, - dialogTop + 95, - dialogWidth - rightMargin, - 20, - color, - ColorComponent.ALPHA - ) + this.addRenderableWidget( + new ColorSlider( + dialogLeft + 5, + dialogTop + 95, + dialogWidth - rightMargin, + 20, + color, + ColorComponent.ALPHA ) + ) ); } this.addRenderableWidget( - new ColorDisplay( - dialogLeft + 5 + dialogWidth - rightMargin + 5, - dialogTop + 20, - rightMargin - 15, - rightMargin - 15, - argb, - this::getResultColor - ) + new ColorDisplay( + dialogLeft + 5 + dialogWidth - rightMargin + 5, + dialogTop + 20, + rightMargin - 15, + rightMargin - 15, + argb, + this::getResultColor + ) ); super.addDefaultDialogButtons(); } @Override - protected void addDefaultDialogButtons() { - } + protected void addDefaultDialogButtons() {} public int getResultColor() { int color = 0; @@ -298,26 +295,26 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float par } int borderColor = 0xffa0a0a0; graphics.fill( - this.getX(), - this.getY(), - this.getX() + this.width, - this.getY() + this.height, - borderColor + this.getX(), + this.getY(), + this.getX() + this.width, + this.getY() + this.height, + borderColor ); graphics.fillGradient( - this.getX() + 1, - this.getY() + 1, - this.getX() + this.width - 1, - this.getY() + this.height - 1, - 0xFFFFFFFF, - 0xFF888888 + this.getX() + 1, + this.getY() + 1, + this.getX() + this.width - 1, + this.getY() + this.height - 1, + 0xFFFFFFFF, + 0xFF888888 ); graphics.fill( - this.getX() + 1, - this.getY() + 1, - this.getX() + this.width - 1, - this.getY() + this.height - 1, - color + this.getX() + 1, + this.getY() + 1, + this.getX() + this.width - 1, + this.getY() + this.height - 1, + color ); } @@ -327,8 +324,7 @@ protected boolean isValidClickButton(int button) { } @Override - public void updateWidgetNarration(NarrationElementOutput p_169152_) { - } + public void updateWidgetNarration(NarrationElementOutput p_169152_) {} } private static final class ColorSlider extends AbstractSliderButton { @@ -348,8 +344,7 @@ protected void updateMessage() { } @Override - protected void applyValue() { - } + protected void applyValue() {} int getColor() { return this.colorComponent.getOffsetColor((int) (0xFF * this.value)); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ConfigEntryWidget.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ConfigEntryWidget.java index 2a8e0846e..c0ba37f64 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ConfigEntryWidget.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ConfigEntryWidget.java @@ -1,15 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.widget; -import mod.azure.azurelib.common.internal.client.config.WidgetAdder; -import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; -import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; @@ -26,6 +20,11 @@ import java.util.List; import java.util.stream.Collectors; +import mod.azure.azurelib.common.internal.client.config.WidgetAdder; +import mod.azure.azurelib.common.internal.common.config.validate.NotificationSeverity; +import mod.azure.azurelib.common.internal.common.config.validate.ValidationResult; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; + public class ConfigEntryWidget extends ContainerWidget implements WidgetAdder { public static final Component EDIT = Component.translatable("text.azurelib.value.edit"); @@ -35,13 +34,13 @@ public class ConfigEntryWidget extends ContainerWidget implements WidgetAdder { public static final Component REVERT_DEFAULTS = Component.translatable("text.azurelib.value.revert.default"); public static final Component REVERT_DEFAULTS_DIALOG_TEXT = Component.translatable( - "text.azurelib.value.revert.default.dialog" + "text.azurelib.value.revert.default.dialog" ); public static final Component REVERT_CHANGES = Component.translatable("text.azurelib.value.revert.changes"); public static final Component REVERT_CHANGES_DIALOG_TEXT = Component.translatable( - "text.azurelib.value.revert.changes.dialog" + "text.azurelib.value.revert.changes.dialog" ); private final String configId; @@ -60,8 +59,8 @@ public ConfigEntryWidget(int x, int y, int w, int h, ConfigValue value, Strin super(x, y, w, h, Component.translatable("config." + configId + ".option." + value.getId())); this.configId = configId; this.description = Arrays.stream(value.getDescription()) - .map(text -> Component.literal(text).withStyle(ChatFormatting.GRAY)) - .collect(Collectors.toList()); + .map(text -> Component.literal(text).withStyle(ChatFormatting.GRAY)) + .collect(Collectors.toList()); } public void setDescriptionRenderer(IDescriptionRenderer renderer) { @@ -74,8 +73,7 @@ public Component getComponentName() { } @Override - public void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) { - } + public void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) {} @Override public void renderWidget(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { @@ -85,12 +83,12 @@ public void renderWidget(@NotNull GuiGraphics graphics, int mouseX, int mouseY, } boolean isError = !this.result.isOk(); graphics.drawString( - font, - this.getMessage(), - this.getX(), - (int) (this.getY() + (this.height - font.lineHeight) / 2.0F), - 0xAAAAAA, - true + font, + this.getMessage(), + this.getX(), + (int) (this.getY() + (this.height - font.lineHeight) / 2.0F), + 0xAAAAAA, + true ); super.renderWidget(graphics, mouseX, mouseY, partialTicks); if ((isError || isHovered) && renderer != null) { @@ -100,8 +98,8 @@ public void renderWidget(@NotNull GuiGraphics graphics, int mouseX, int mouseY, MutableComponent textComponent = this.result.text().withStyle(severity.getExtraFormatting()); List desc = isError ? Collections.singletonList(textComponent) : this.description; List split = desc.stream() - .flatMap(text -> font.split(text, this.width / 2).stream()) - .collect(Collectors.toList()); + .flatMap(text -> font.split(text, this.width / 2).stream()) + .collect(Collectors.toList()); renderer.drawDescription(graphics, this, severity, split); } } @@ -123,10 +121,10 @@ public W addConfigWidget(ToWidgetFunction function public interface IDescriptionRenderer { void drawDescription( - GuiGraphics graphics, - AbstractWidget widget, - NotificationSeverity severity, - List text + GuiGraphics graphics, + AbstractWidget widget, + NotificationSeverity severity, + List text ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ContainerWidget.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ContainerWidget.java index 69524172c..37e19641d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ContainerWidget.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/ContainerWidget.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.widget; @@ -75,18 +73,18 @@ public boolean mouseReleased(double p_231048_1_, double p_231048_3_, int p_23104 @Override public boolean mouseDragged( - double p_231045_1_, - double p_231045_3_, - int p_231045_5_, - double p_231045_6_, - double p_231045_8_ + double p_231045_1_, + double p_231045_3_, + int p_231045_5_, + double p_231045_6_, + double p_231045_8_ ) { return ContainerEventHandler.super.mouseDragged( - p_231045_1_, - p_231045_3_, - p_231045_5_, - p_231045_6_, - p_231045_8_ + p_231045_1_, + p_231045_3_, + p_231045_5_, + p_231045_6_, + p_231045_8_ ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/EnumWidget.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/EnumWidget.java index 7a46fac97..c23ecb6f0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/EnumWidget.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/config/widget/EnumWidget.java @@ -1,13 +1,10 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.client.config.widget; import com.mojang.blaze3d.systems.RenderSystem; -import mod.azure.azurelib.common.internal.common.config.value.EnumValue; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; @@ -20,12 +17,14 @@ import net.minecraft.util.Mth; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.internal.common.config.value.EnumValue; + public class EnumWidget> extends AbstractWidget { private static final WidgetSprites SPRITES = new WidgetSprites( - ResourceLocation.parse("widget/button"), - ResourceLocation.parse("widget/button_disabled"), - ResourceLocation.parse("widget/button_highlighted") + ResourceLocation.parse("widget/button"), + ResourceLocation.parse("widget/button_disabled"), + ResourceLocation.parse("widget/button_highlighted") ); private final EnumValue value; @@ -43,11 +42,11 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float par RenderSystem.enableBlend(); RenderSystem.enableDepthTest(); graphics.blitSprite( - SPRITES.get(this.active, this.isHoveredOrFocused()), - this.getX(), - this.getY(), - this.getWidth(), - this.getHeight() + SPRITES.get(this.active, this.isHoveredOrFocused()), + this.getX(), + this.getY(), + this.getWidth(), + this.getHeight() ); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); this.renderString(graphics, minecraft.font, Mth.ceil(this.alpha * 255.0F) << 24); @@ -64,8 +63,7 @@ public void onClick(double p_230982_1_, double p_230982_3_) { } @Override - public void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) { - } + public void updateWidgetNarration(@NotNull NarrationElementOutput narrationElementOutput) {} private void nextValue() { E e = this.value.get(); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/model/data/EntityModelData.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/model/data/EntityModelData.java index 3e2a7ee3d..06a0f02de 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/model/data/EntityModelData.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/model/data/EntityModelData.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.client.model.data; @@ -11,9 +9,8 @@ * Container class for various pieces of data relating to a model's current state. */ public record EntityModelData( - boolean isSitting, - boolean isChild, - float netHeadYaw, - float headPitch -) { -} + boolean isSitting, + boolean isChild, + float netHeadYaw, + float headPitch +) {} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java index 28b4426bb..59a179e04 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/renderer/GeoRenderer.java @@ -1,24 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.client.renderer; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimationState; -import mod.azure.azurelib.core.object.Color; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.OverlayTexture; @@ -31,10 +19,24 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimationState; +import mod.azure.azurelib.core.object.Color; + /** * Base interface for all AzureLib renderers.
+ * + * @deprecated */ public interface GeoRenderer { + /** * Gets the model instance for this renderer */ @@ -61,11 +63,15 @@ default List> getRenderLayers() { /** * Gets the {@link RenderType} to render the given animatable with.
- * Uses the {@link RenderType#entityCutoutNoCull} {@code RenderType} by default.
+ * Uses the {@link RenderType#entityCutoutNoCull} {@code RenderType} by default.
* Override this to change the way a model will render (such as translucent models, etc) */ - default RenderType getRenderType(T animatable, ResourceLocation texture, - @Nullable MultiBufferSource bufferSource, float partialTick) { + default RenderType getRenderType( + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ) { return getGeoModel().getRenderType(animatable, texture); } @@ -79,17 +85,16 @@ default Color getRenderColor(T animatable, float partialTick, int packedLight) { /** * Gets a packed overlay coordinate pair for rendering.
- * Mostly just used for the red tint when an entity is hurt, - * but can be used for other things like the {@link net.minecraft.world.entity.monster.Creeper} - * white tint when exploding. + * Mostly just used for the red tint when an entity is hurt, but can be used for other things like the + * {@link net.minecraft.world.entity.monster.Creeper} white tint when exploding. */ default int getPackedOverlay(T animatable, float u, float partialTick) { return OverlayTexture.NO_OVERLAY; } /** - * Gets the id that represents the current animatable's instance for animation purposes. - * This is mostly useful for things like items, which have a single registered instance for all objects + * Gets the id that represents the current animatable's instance for animation purposes. This is mostly useful for + * things like items, which have a single registered instance for all objects */ default long getInstanceId(T animatable) { return animatable.hashCode(); @@ -99,8 +104,8 @@ default long getInstanceId(T animatable) { * Determines the threshold value before the animatable should be considered moving for animation purposes.
* The default value and usage for this varies depending on the renderer.
*
    - *
  • For entities, it represents the averaged lateral velocity of the object.
  • - *
  • For {@link GeoBlockEntity Tile Entities} and {@link GeoItem Items}, it's currently unused
  • + *
  • For entities, it represents the averaged lateral velocity of the object.
  • + *
  • For {@link GeoBlockEntity Tile Entities} and {@link GeoItem Items}, it's currently unused
  • *
* The lower the value, the more sensitive the {@link AnimationState#isMoving()} check will be.
* Particularly low values may have adverse effects however @@ -111,10 +116,19 @@ default float getMotionAnimThreshold(T animatable) { /** * Initial access point for rendering. It all begins here.
- * All AzureLib renderers should immediately defer their respective default {@code render} calls to this, for consistent handling + * All AzureLib renderers should immediately defer their respective default {@code render} calls to this, for + * consistent handling */ - default void defaultRender(PoseStack poseStack, T animatable, MultiBufferSource bufferSource, @Nullable RenderType renderType, @Nullable VertexConsumer buffer, - float yaw, float partialTick, int packedLight) { + default void defaultRender( + PoseStack poseStack, + T animatable, + MultiBufferSource bufferSource, + @Nullable RenderType renderType, + @Nullable VertexConsumer buffer, + float yaw, + float partialTick, + int packedLight + ) { poseStack.pushPose(); int renderColor = getRenderColor(animatable, partialTick, packedLight).argbInt(); @@ -127,131 +141,389 @@ default void defaultRender(PoseStack poseStack, T animatable, MultiBufferSource if (buffer == null) buffer = bufferSource.getBuffer(renderType); - preRender(poseStack, animatable, model, bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); + preRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + false, + partialTick, + packedLight, + packedOverlay, + renderColor + ); if (firePreRenderEvent(poseStack, model, bufferSource, partialTick, packedLight)) { - preApplyRenderLayers(poseStack, animatable, model, renderType, bufferSource, buffer, packedLight, packedLight, packedOverlay); - actuallyRender(poseStack, animatable, model, renderType, - bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); - applyRenderLayers(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); - postRender(poseStack, animatable, model, bufferSource, buffer, false, partialTick, packedLight, packedOverlay, renderColor); + preApplyRenderLayers( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + packedLight, + packedLight, + packedOverlay + ); + actuallyRender( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + false, + partialTick, + packedLight, + packedOverlay, + renderColor + ); + applyRenderLayers( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); + postRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + false, + partialTick, + packedLight, + packedOverlay, + renderColor + ); firePostRenderEvent(poseStack, model, bufferSource, partialTick, packedLight); } poseStack.popPose(); - renderFinal(poseStack, animatable, model, bufferSource, buffer, partialTick, packedLight, packedOverlay, renderColor); + renderFinal( + poseStack, + animatable, + model, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay, + renderColor + ); doPostRenderCleanup(); } /** * Re-renders the provided {@link BakedGeoModel} using the existing {@link GeoRenderer}.
- * Usually you'd use this for rendering alternate {@link RenderType} layers or for sub-model rendering whilst inside a {@link GeoRenderLayer} or similar + * Usually you'd use this for rendering alternate {@link RenderType} layers or for sub-model rendering whilst inside + * a {@link GeoRenderLayer} or similar */ - default void reRender(BakedGeoModel model, PoseStack poseStack, MultiBufferSource bufferSource, T animatable, - RenderType renderType, VertexConsumer buffer, float partialTick, - int packedLight, int packedOverlay, int colour) { + default void reRender( + BakedGeoModel model, + PoseStack poseStack, + MultiBufferSource bufferSource, + T animatable, + RenderType renderType, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { poseStack.pushPose(); - preRender(poseStack, animatable, model, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); - actuallyRender(poseStack, animatable, model, renderType, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); - postRender(poseStack, animatable, model, bufferSource, buffer, true, partialTick, packedLight, packedOverlay, colour); + preRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + true, + partialTick, + packedLight, + packedOverlay, + colour + ); + actuallyRender( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + true, + partialTick, + packedLight, + packedOverlay, + colour + ); + postRender( + poseStack, + animatable, + model, + bufferSource, + buffer, + true, + partialTick, + packedLight, + packedOverlay, + colour + ); poseStack.popPose(); } /** * The actual render method that sub-type renderers should override to handle their specific rendering tasks.
- * {@link GeoRenderer#preRender} has already been called by this stage, and {@link GeoRenderer#postRender} will be called directly after + * {@link GeoRenderer#preRender} has already been called by this stage, and {@link GeoRenderer#postRender} will be + * called directly after */ - default void actuallyRender(PoseStack poseStack, T animatable, BakedGeoModel model, RenderType renderType, - MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, - int packedLight, int packedOverlay, int colour) { + default void actuallyRender( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { updateAnimatedTextureFrame(animatable); for (GeoBone group : model.getTopLevelBones()) { - renderRecursively(poseStack, animatable, group, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, - packedOverlay, colour); + renderRecursively( + poseStack, + animatable, + group, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour + ); } } /** - * Calls back to the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer for their {@link GeoRenderLayer#preRender pre-render} actions. + * Calls back to the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer for + * their {@link GeoRenderLayer#preRender pre-render} actions. */ - default void preApplyRenderLayers(PoseStack poseStack, T animatable, BakedGeoModel model, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + default void preApplyRenderLayers( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) { for (GeoRenderLayer renderLayer : getRenderLayers()) { - renderLayer.preRender(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + renderLayer.preRender( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); } } /** - * Calls back to the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer for their {@link GeoRenderLayer#renderForBone per-bone} render actions. + * Calls back to the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer for + * their {@link GeoRenderLayer#renderForBone per-bone} render actions. */ - default void applyRenderLayersForBone(PoseStack poseStack, T animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + default void applyRenderLayersForBone( + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) { for (GeoRenderLayer renderLayer : getRenderLayers()) { - renderLayer.renderForBone(poseStack, animatable, bone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + renderLayer.renderForBone( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); } } /** * Render the various {@link GeoRenderLayer RenderLayers} that have been registered to this renderer */ - default void applyRenderLayers(PoseStack poseStack, T animatable, BakedGeoModel model, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + default void applyRenderLayers( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay + ) { for (GeoRenderLayer renderLayer : getRenderLayers()) { - renderLayer.render(poseStack, animatable, model, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); + renderLayer.render( + poseStack, + animatable, + model, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); } } /** - * Called before rendering the model to buffer. Allows for render modifications and preparatory - * work such as scaling and translating.
+ * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
* {@link PoseStack} translations made here are kept until the end of the render process */ - default void preRender(PoseStack poseStack, T animatable, BakedGeoModel model, @Nullable MultiBufferSource bufferSource, @Nullable VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, - int packedOverlay, int colour) {} + default void preRender( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + @Nullable MultiBufferSource bufferSource, + @Nullable VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) {} /** * Called after rendering the model to buffer. Post-render modifications should be performed here.
* {@link PoseStack} transformations will be unused and lost once this method ends */ - default void postRender(PoseStack poseStack, T animatable, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {} + default void postRender( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) {} /** - * Call after all other rendering work has taken place, including reverting the {@link PoseStack}'s state. This method is not called in {@link GeoRenderer#reRender re-render} + * Call after all other rendering work has taken place, including reverting the {@link PoseStack}'s state. This + * method is not called in {@link GeoRenderer#reRender re-render} */ - default void renderFinal(PoseStack poseStack, T animatable, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, - int packedOverlay, int colour) {} + default void renderFinal( + PoseStack poseStack, + T animatable, + BakedGeoModel model, + MultiBufferSource bufferSource, + VertexConsumer buffer, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) {} /** * Called after all render operations are completed and the render pass is considered functionally complete. *

- * Use this method to clean up any leftover persistent objects stored during rendering or any other post-render maintenance tasks as required + * Use this method to clean up any leftover persistent objects stored during rendering or any other post-render + * maintenance tasks as required */ default void doPostRenderCleanup() {} /** * Renders the provided {@link GeoBone} and its associated child bones */ - default void renderRecursively(PoseStack poseStack, T animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, - VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, - int packedOverlay, int colour) { + default void renderRecursively( + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { poseStack.pushPose(); RenderUtils.prepMatrixForBone(poseStack, bone); renderCubesOfBone(poseStack, bone, buffer, packedLight, packedOverlay, colour); if (!isReRender) - applyRenderLayersForBone(poseStack, getAnimatable(), bone, renderType, bufferSource, buffer, partialTick, packedLight, packedOverlay); - - renderChildBones(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour); + applyRenderLayersForBone( + poseStack, + getAnimatable(), + bone, + renderType, + bufferSource, + buffer, + partialTick, + packedLight, + packedOverlay + ); + + renderChildBones( + poseStack, + animatable, + bone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour + ); poseStack.popPose(); } /** * Renders the {@link GeoCube GeoCubes} associated with a given {@link GeoBone} */ - default void renderCubesOfBone(PoseStack poseStack, GeoBone bone, VertexConsumer buffer, int packedLight, - int packedOverlay, int colour) { + default void renderCubesOfBone( + PoseStack poseStack, + GeoBone bone, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour + ) { if (bone.isHidden()) return; @@ -264,15 +536,39 @@ default void renderCubesOfBone(PoseStack poseStack, GeoBone bone, VertexConsumer /** * Render the child bones of a given {@link GeoBone}.
- * Note that this does not render the bone itself. That should be done through {@link GeoRenderer#renderCubesOfBone} separately + * Note that this does not render the bone itself. That should be done through {@link GeoRenderer#renderCubesOfBone} + * separately */ - default void renderChildBones(PoseStack poseStack, T animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, - boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) { + default void renderChildBones( + PoseStack poseStack, + T animatable, + GeoBone bone, + RenderType renderType, + MultiBufferSource bufferSource, + VertexConsumer buffer, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay, + int colour + ) { if (bone.isHidingChildren()) return; for (GeoBone childBone : bone.getChildBones()) { - renderRecursively(poseStack, animatable, childBone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour); + renderRecursively( + poseStack, + animatable, + childBone, + renderType, + bufferSource, + buffer, + isReRender, + partialTick, + packedLight, + packedOverlay, + colour + ); } } @@ -280,8 +576,14 @@ default void renderChildBones(PoseStack poseStack, T animatable, GeoBone bone, R * Renders an individual {@link GeoCube}.
* This tends to be called recursively from something like {@link GeoRenderer#renderCubesOfBone} */ - default void renderCube(PoseStack poseStack, GeoCube cube, VertexConsumer buffer, int packedLight, - int packedOverlay, int colour) { + default void renderCube( + PoseStack poseStack, + GeoCube cube, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour + ) { RenderUtils.translateToPivotPoint(poseStack, cube); RenderUtils.rotateMatrixAroundCube(poseStack, cube); RenderUtils.translateAwayFromPivotPoint(poseStack, cube); @@ -301,16 +603,35 @@ default void renderCube(PoseStack poseStack, GeoCube cube, VertexConsumer buffer } /** - * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for rendering + * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for + * rendering */ - default void createVerticesOfQuad(GeoQuad quad, Matrix4f poseState, Vector3f normal, VertexConsumer buffer, - int packedLight, int packedOverlay, int colour) { + default void createVerticesOfQuad( + GeoQuad quad, + Matrix4f poseState, + Vector3f normal, + VertexConsumer buffer, + int packedLight, + int packedOverlay, + int colour + ) { for (GeoVertex vertex : quad.vertices()) { Vector3f position = vertex.position(); Vector4f vector4f = poseState.transform(new Vector4f(position.x(), position.y(), position.z(), 1.0f)); - buffer.addVertex(vector4f.x(), vector4f.y(), vector4f.z(), colour, vertex.texU(), - vertex.texV(), packedOverlay, packedLight, normal.x(), normal.y(), normal.z()); + buffer.addVertex( + vector4f.x(), + vector4f.y(), + vector4f.z(), + colour, + vertex.texU(), + vertex.texV(), + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() + ); } } @@ -321,28 +642,55 @@ default void createVerticesOfQuad(GeoQuad quad, Matrix4f poseState, Vector3f nor /** * Create and fire the relevant {@code Pre-Render} event hook for this renderer.
+ * * @return Whether the renderer should proceed based on the cancellation state of the event */ - boolean firePreRenderEvent(PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean firePreRenderEvent( + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Create and fire the relevant {@code Post-Render} event hook for this renderer */ - void firePostRenderEvent(PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void firePostRenderEvent( + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** - * Scales the {@link PoseStack} in preparation for rendering the model, excluding when re-rendering the model as part of a {@link GeoRenderLayer} or external render call.
- * Override and call super with modified scale values as needed to further modify the scale of the model (E.G. child entities) + * Scales the {@link PoseStack} in preparation for rendering the model, excluding when re-rendering the model as + * part of a {@link GeoRenderLayer} or external render call.
+ * Override and call super with modified scale values as needed to further modify the scale of the model (E.G. child + * entities) */ - default void scaleModelForRender(float widthScale, float heightScale, PoseStack poseStack, T animatable, BakedGeoModel model, boolean isReRender, float partialTick, int packedLight, int packedOverlay) { + default void scaleModelForRender( + float widthScale, + float heightScale, + PoseStack poseStack, + T animatable, + BakedGeoModel model, + boolean isReRender, + float partialTick, + int packedLight, + int packedOverlay + ) { if (!isReRender && (widthScale != 1 || heightScale != 1)) poseStack.scale(widthScale, heightScale, widthScale); } /** - * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this GeoRenderer.
+ * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
* This should only be called immediately prior to rendering, and only + * * @see AnimatableTexture#setAndUpdate */ void updateAnimatedTextureFrame(T animatable); -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java b/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java index db8446df9..078ddea4e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/client/util/RenderUtils.java @@ -1,10 +1,8 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ - package mod.azure.azurelib.common.internal.client.util; +package mod.azure.azurelib.common.internal.client.util; import com.mojang.blaze3d.Blaze3D; import com.mojang.blaze3d.platform.NativeImage; @@ -12,16 +10,6 @@ import com.mojang.math.Axis; import it.unimi.dsi.fastutil.ints.IntIntImmutablePair; import it.unimi.dsi.fastutil.ints.IntIntPair; -import mod.azure.azurelib.common.api.client.model.GeoModel; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.api.client.renderer.GeoReplacedEntityRenderer; -import mod.azure.azurelib.common.internal.client.RenderProvider; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; -import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import net.minecraft.client.Minecraft; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; @@ -42,10 +30,29 @@ import org.joml.Quaternionf; import org.joml.Vector3f; +import mod.azure.azurelib.common.api.client.model.GeoModel; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.api.client.renderer.GeoReplacedEntityRenderer; +import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; + /** * Helper class for various methods and functions useful while rendering */ -public record RenderUtils() { +public class RenderUtils { + + private static final Matrix4f TRANSLATE_MATRIX_CACHE = new Matrix4f(); + + private static final Quaternionf X_QUATERNION_CACHE = new Quaternionf(); + + private static final Quaternionf Y_QUATERNION_CACHE = new Quaternionf(); + + private static final Quaternionf Z_QUATERNION_CACHE = new Quaternionf(); public static void translateMatrixToBone(PoseStack poseStack, CoreGeoBone bone) { poseStack.translate(-bone.getPosX() / 16f, bone.getPosY() / 16f, bone.getPosZ() / 16f); @@ -65,9 +72,9 @@ public static void rotateMatrixAroundBone(PoseStack poseStack, CoreGeoBone bone) public static void rotateMatrixAroundCube(PoseStack poseStack, GeoCube cube) { Vec3 rotation = cube.rotation(); - poseStack.mulPose(new Quaternionf().rotationXYZ(0, 0, (float) rotation.z())); - poseStack.mulPose(new Quaternionf().rotationXYZ(0, (float) rotation.y(), 0)); - poseStack.mulPose(new Quaternionf().rotationXYZ((float) rotation.x(), 0, 0)); + poseStack.mulPose(Z_QUATERNION_CACHE.rotationXYZ(0, 0, (float) rotation.z())); + poseStack.mulPose(Y_QUATERNION_CACHE.rotationXYZ(0, (float) rotation.y(), 0)); + poseStack.mulPose(X_QUATERNION_CACHE.rotationXYZ((float) rotation.x(), 0, 0)); } public static void scaleMatrixForBone(PoseStack poseStack, CoreGeoBone bone) { @@ -129,7 +136,8 @@ public static void faceRotation(PoseStack poseStack, Entity animatable, float pa * coordinate triplet to a render matrix */ public static Matrix4f translateMatrix(Matrix4f matrix, Vector3f vector) { - return matrix.add(new Matrix4f().m30(vector.x).m31(vector.y).m32(vector.z)); + TRANSLATE_MATRIX_CACHE.m30(vector.x).m31(vector.y).m32(vector.z); + return matrix.add(TRANSLATE_MATRIX_CACHE); } /** @@ -161,8 +169,8 @@ public static IntIntPair getTextureDimensions(ResourceLocation texture) { try { image = originalTexture instanceof DynamicTexture dynamicTexture - ? dynamicTexture.getPixels() - : NativeImage.read(mc.getResourceManager().getResource(texture).get().open()); + ? dynamicTexture.getPixels() + : NativeImage.read(mc.getResourceManager().getResource(texture).get().open()); } catch (Exception e) { AzureLib.LOGGER.error("Failed to read image for id {}", texture); e.printStackTrace(); @@ -265,8 +273,8 @@ public static GeoAnimatable getReplacedAnimatable(EntityType entityType) { EntityRenderer renderer = Minecraft.getInstance().getEntityRenderDispatcher().renderers.get(entityType); return renderer instanceof GeoReplacedEntityRenderer replacedEntityRenderer - ? replacedEntityRenderer.getAnimatable() - : null; + ? replacedEntityRenderer.getAnimatable() + : null; } /** @@ -314,8 +322,8 @@ public static GeoModel getGeoModelForItem(Item item) { @Nullable public static GeoModel getGeoModelForBlock(BlockEntity blockEntity) { BlockEntityRenderer renderer = Minecraft.getInstance() - .getBlockEntityRenderDispatcher() - .getRenderer(blockEntity); + .getBlockEntityRenderDispatcher() + .getRenderer(blockEntity); return renderer instanceof GeoRenderer geoRenderer ? geoRenderer.getGeoModel() : null; } @@ -332,8 +340,8 @@ public static GeoModel getGeoModelForBlock(BlockEntity blockEntity) { @Nullable public static GeoModel getGeoModelForArmor(ItemStack stack) { if ( - RenderProvider.of(stack) - .getHumanoidArmorModel(null, stack, null, null) instanceof GeoArmorRenderer armorRenderer + RenderProvider.of(stack) + .getHumanoidArmorModel(null, stack, null, null) instanceof GeoArmorRenderer armorRenderer ) return armorRenderer.getGeoModel(); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java index 34809e035..2f19aabd2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLib.java @@ -1,8 +1,7 @@ package mod.azure.azurelib.common.internal.common; import com.mojang.serialization.Codec; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; -import mod.azure.azurelib.common.platform.Services; +import net.minecraft.core.UUIDUtil; import net.minecraft.core.component.DataComponentType; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.resources.ResourceLocation; @@ -11,8 +10,12 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; +import java.util.UUID; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.common.platform.Services; + /** * Base class for AzureLib!
* Hello World!
@@ -27,10 +30,29 @@ public final class AzureLib { public static final Logger LOGGER = LogManager.getLogger(MOD_ID); public static final Marker MAIN_MARKER = MarkerManager.getMarker("main"); - public static final Supplier> STACK_ANIMATABLE_ID_COMPONENT = Services.PLATFORM.registerDataComponent( - "stack_animatable_id", builder -> builder.persistent(Codec.LONG).networkSynchronized( - ByteBufCodecs.VAR_LONG)); + + /** + * @deprecated + */ + @Deprecated(forRemoval = true) + public static final Supplier> STACK_ANIMATABLE_ID_COMPONENT = Services.PLATFORM + .registerDataComponent( + "stack_animatable_id", + builder -> builder.persistent(Codec.LONG) + .networkSynchronized( + ByteBufCodecs.VAR_LONG + ) + ); + + public static final Supplier> AZ_ID = Services.PLATFORM + .registerDataComponent( + "az_id", + builder -> builder.persistent(UUIDUtil.CODEC) + .networkSynchronized(UUIDUtil.STREAM_CODEC) + ); + public static boolean hasInitialized; + public static boolean hasKeyBindsInitialized; private AzureLib() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLibMod.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLibMod.java index c93a2720f..15a86d4a0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLibMod.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/AzureLibMod.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common; @@ -37,7 +35,7 @@ public static void initRegistry() { * for example. * @param Config type * @return Config holder containing your config instance. You obtain it by calling - * {@link ConfigHolder#getConfigInstance()} method. + * {@link ConfigHolder#getConfigInstance()} method. */ public static ConfigHolder registerConfig(Class configClass, IConfigFormatHandler formatFactory) { var config = configClass.getAnnotation(Config.class); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/ai/pathing/AzurePathFinder.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/ai/pathing/AzurePathFinder.java index 27a2a7ce6..e487cbfe7 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/ai/pathing/AzurePathFinder.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/ai/pathing/AzurePathFinder.java @@ -26,12 +26,12 @@ public AzurePathFinder(NodeEvaluator processor, int maxVisitedNodes) { @Nullable @Override public Path findPath( - @NotNull PathNavigationRegion regionIn, - @NotNull Mob mob, - @NotNull Set targetPositions, - float maxRange, - int accuracy, - float searchDepthMultiplier + @NotNull PathNavigationRegion regionIn, + @NotNull Mob mob, + @NotNull Set targetPositions, + float maxRange, + int accuracy, + float searchDepthMultiplier ) { Path path = super.findPath(regionIn, mob, targetPositions, maxRange, accuracy, searchDepthMultiplier); return path == null ? null : new PatchedPath(path); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java index bb18cb799..24596d53e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/animatable/SingletonGeoAnimatable.java @@ -1,12 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.animatable; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; +import java.util.function.Supplier; + import mod.azure.azurelib.common.internal.client.RenderProvider; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; import mod.azure.azurelib.common.internal.common.network.packet.AnimDataSyncPacket; @@ -18,14 +22,11 @@ import mod.azure.azurelib.core.animatable.instance.SingletonAnimatableInstanceCache; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.AnimationController; -import net.minecraft.world.entity.Entity; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; -import java.util.function.Supplier; /** * The {@link GeoAnimatable} interface specific to singleton objects. This primarily applies to armor and items + * + * @deprecated */ public interface SingletonGeoAnimatable extends GeoAnimatable { @@ -79,8 +80,8 @@ default void setAnimData(Entity relatedEntity, long instanceId, Serializable */ default void syncAnimData(long instanceId, SerializableDataTicket dataTicket, D data, Entity entityToTrack) { Services.NETWORK.sendToTrackingEntityAndSelf( - new AnimDataSyncPacket<>(getClass().toString(), instanceId, dataTicket, data), - entityToTrack + new AnimDataSyncPacket<>(getClass().toString(), instanceId, dataTicket, data), + entityToTrack ); } @@ -102,8 +103,8 @@ default void triggerAnim(Entity relatedEntity, long instanceId, @Nullable String getAnimatableInstanceCache().getManagerForId(instanceId).tryTriggerAnimation(controllerName, animName); } else { Services.NETWORK.sendToTrackingEntityAndSelf( - new AnimTriggerPacket(getClass().toString(), instanceId, controllerName, animName), - relatedEntity + new AnimTriggerPacket(getClass().toString(), instanceId, controllerName, animName), + relatedEntity ); } } @@ -122,14 +123,14 @@ default void triggerAnim(Entity relatedEntity, long instanceId, @Nullable String * @param packetCallback The packet callback. Used to call a custom network code */ default void triggerAnim( - long instanceId, - @Nullable String controllerName, - String animName, - AzureLibNetwork.IPacketCallback packetCallback + long instanceId, + @Nullable String controllerName, + String animName, + AzureLibNetwork.IPacketCallback packetCallback ) { AzureLibNetwork.sendWithCallback( - new AnimTriggerPacket(getClass().toString(), instanceId, controllerName, animName), - packetCallback + new AnimTriggerPacket(getClass().toString(), instanceId, controllerName, animName), + packetCallback ); } @@ -149,12 +150,12 @@ default void triggerAnim( * *

      * {@code
-     * @Override
+     * @Override
      * public void createRenderer(Consumer consumer) {
      * 	consumer.accept(new RenderProvider() {
      * 		private final GeoArmorRenderer renderer = new MyArmorRenderer();
      *
-     *        @Override
+     *        @Override
      *        GeoArmorRenderer getRenderer(GeoArmor armor) {
      * 			return this.renderer;
      *        }
@@ -164,7 +165,7 @@ default void triggerAnim(
      * 
* * @param consumer a {@link java.util.function.Consumer} that accepts a {@link RenderProvider} - * */ + */ void createRenderer(Consumer consumer); /** diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightBlock.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightBlock.java index 7bf4f3593..eadd076b3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightBlock.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightBlock.java @@ -1,8 +1,6 @@ package mod.azure.azurelib.common.internal.common.blocks; import com.mojang.serialization.MapCodec; -import mod.azure.azurelib.common.internal.common.registry.AzureBlocksEntityRegistry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.core.BlockPos; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; @@ -24,6 +22,8 @@ import java.util.function.ToIntFunction; +import mod.azure.azurelib.common.internal.common.registry.AzureBlocksEntityRegistry; + public class TickingLightBlock extends BaseEntityBlock { public static final MapCodec CODEC = simpleCodec(TickingLightBlock::new); @@ -54,16 +54,20 @@ public BlockEntity newBlockEntity(@NotNull BlockPos pos, @NotNull BlockState sta @Override public @NotNull VoxelShape getShape( - @NotNull BlockState blockState, - @NotNull BlockGetter blockGetter, - @NotNull BlockPos blockPos, - @NotNull CollisionContext collisionContext + @NotNull BlockState blockState, + @NotNull BlockGetter blockGetter, + @NotNull BlockPos blockPos, + @NotNull CollisionContext collisionContext ) { return Shapes.empty(); } @Override - public boolean propagatesSkylightDown(@NotNull BlockState state, @NotNull BlockGetter world, @NotNull BlockPos pos) { + public boolean propagatesSkylightDown( + @NotNull BlockState state, + @NotNull BlockGetter world, + @NotNull BlockPos pos + ) { return true; } @@ -79,9 +83,9 @@ public boolean propagatesSkylightDown(@NotNull BlockState state, @NotNull BlockG @Override public BlockEntityTicker getTicker( - Level world, - BlockState state, - BlockEntityType type + Level world, + BlockState state, + BlockEntityType type ) { return createTickerHelper(type, AzureBlocksEntityRegistry.TICKING_LIGHT_ENTITY.get(), TickingLightEntity::tick); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightEntity.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightEntity.java index 568d99c25..5f75f7942 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightEntity.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/blocks/TickingLightEntity.java @@ -1,13 +1,13 @@ package mod.azure.azurelib.common.internal.common.blocks; -import mod.azure.azurelib.common.internal.common.registry.AzureBlocksEntityRegistry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import mod.azure.azurelib.common.internal.common.registry.AzureBlocksEntityRegistry; + public class TickingLightEntity extends BlockEntity { private int lifespan = 0; @@ -17,10 +17,10 @@ public TickingLightEntity(BlockPos blockPos, BlockState blockState) { } public static void tick( - Level world, - BlockPos blockPos, - BlockState blockState, - TickingLightEntity blockEntity + Level world, + BlockPos blockPos, + BlockState blockState, + TickingLightEntity blockEntity ) { blockEntity.tick(); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java index 7443f81b7..42d6f859c 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AnimatableIdCache.java @@ -1,32 +1,33 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache; -import mod.azure.azurelib.core.animatable.instance.SingletonAnimatableInstanceCache; import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.saveddata.SavedData; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.core.animatable.instance.SingletonAnimatableInstanceCache; + /** * Storage class that keeps track of the last animatable id used, and provides new ones on request.
* Generally only used for {@link net.minecraft.world.item.Item Items}, but any {@link SingletonAnimatableInstanceCache * singleton} will likely use this. + * + * @deprecated */ +@Deprecated(forRemoval = true) public final class AnimatableIdCache extends SavedData { private static final String DATA_KEY = "AzureLib_id_cache"; private long lastId; - private AnimatableIdCache() { - } + private AnimatableIdCache() {} private AnimatableIdCache(CompoundTag tag, HolderLookup.Provider registryLookup) { this.lastId = tag.getLong("last_id"); @@ -34,9 +35,9 @@ private AnimatableIdCache(CompoundTag tag, HolderLookup.Provider registryLookup) public static SavedData.Factory factory() { return new SavedData.Factory<>( - AnimatableIdCache::new, - AnimatableIdCache::new, - null + AnimatableIdCache::new, + AnimatableIdCache::new, + null ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java index 3fa012d87..c1e2afb6d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/AzureLibCache.java @@ -1,24 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.AzureLibException; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.loading.FileLoader; -import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; -import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; -import mod.azure.azurelib.common.internal.common.loading.object.BakedModelFactory; -import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; -import mod.azure.azurelib.core.animatable.model.CoreGeoModel; -import mod.azure.azurelib.core.animation.Animation; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.PreparableReloadListener.PreparationBarrier; @@ -36,29 +24,56 @@ import java.util.function.BiConsumer; import java.util.function.Function; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.AzureLibException; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.loading.FileLoader; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; +import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; +import mod.azure.azurelib.common.internal.common.loading.object.BakedModelFactory; +import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; +import mod.azure.azurelib.core.animatable.model.CoreGeoModel; +import mod.azure.azurelib.core.animation.Animation; +import mod.azure.azurelib.core2.animation.cache.AzBakedAnimationCache; +import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; + /** * Cache class for holding loaded {@link Animation Animations} and {@link CoreGeoModel Models} + * + * @deprecated Use {@link AzBakedModelCache} and {@link AzBakedAnimationCache} instead. */ public final class AzureLibCache { + /** + * @deprecated + */ private static final Set EXCLUDED_NAMESPACES = ObjectOpenHashSet.of( - "moreplayermodels", - "customnpcs", - "creeperoverhaul", - "geckolib", - "gunsrpg", - "born_in_chaos_v1", - "neoforge" + "moreplayermodels", + "customnpcs", + "creeperoverhaul", + "geckolib", + "gunsrpg", + "born_in_chaos_v1", + "neoforge" ); + /** + * @deprecated + */ private static Map ANIMATIONS = Collections.emptyMap(); + /** + * @deprecated + */ private static Map MODELS = Collections.emptyMap(); private AzureLibCache() { throw new UnsupportedOperationException(); } + /** + * @deprecated Use {@link AzBakedAnimationCache} instead. + */ public static Map getBakedAnimations() { if (!AzureLib.hasInitialized) throw new AzureLibException("AzureLib was never initialized! Please read the documentation!"); @@ -66,6 +81,9 @@ public static Map getBakedAnimations() { return ANIMATIONS; } + /** + * @deprecated Use {@link AzBakedModelCache} instead. + */ public static Map getBakedModels() { if (!AzureLib.hasInitialized) throw new AzureLibException("AzureLib was never initialized! Please read the documentation!"); @@ -76,89 +94,106 @@ public static Map getBakedModels() { public static void registerReloadListener() { Minecraft mc = Minecraft.getInstance(); - if (mc == null) return; + if (mc == null) { + return; + } - if (!(mc.getResourceManager() instanceof ReloadableResourceManager resourceManager)) + if (!(mc.getResourceManager() instanceof ReloadableResourceManager resourceManager)) { throw new AzureLibException("AzureLib was initialized too early!"); + } resourceManager.registerReloadListener(AzureLibCache::reload); } public static CompletableFuture reload( - PreparationBarrier stage, - ResourceManager resourceManager, - ProfilerFiller preparationsProfiler, - ProfilerFiller reloadProfiler, - Executor backgroundExecutor, - Executor gameExecutor + PreparationBarrier stage, + ResourceManager resourceManager, + ProfilerFiller preparationsProfiler, + ProfilerFiller reloadProfiler, + Executor backgroundExecutor, + Executor gameExecutor ) { + // TODO: Remove these. Map animations = new Object2ObjectOpenHashMap<>(); Map models = new Object2ObjectOpenHashMap<>(); return CompletableFuture - .allOf( - loadAnimations(backgroundExecutor, resourceManager, animations::put), - loadModels(backgroundExecutor, resourceManager, models::put) - ) - .thenCompose(stage::wait) - .thenAcceptAsync(empty -> { - AzureLibCache.ANIMATIONS = animations; - AzureLibCache.MODELS = models; - }, gameExecutor); + .allOf( + // TODO: Remove these. + loadAnimations(backgroundExecutor, resourceManager, animations::put), + loadModels(backgroundExecutor, resourceManager, models::put), + // Forward-support for new cache components + AzBakedAnimationCache.getInstance().loadAnimations(backgroundExecutor, resourceManager), + AzBakedModelCache.getInstance().loadModels(backgroundExecutor, resourceManager) + ) + .thenCompose(stage::wait) + .thenAcceptAsync(empty -> { + AzureLibCache.ANIMATIONS = animations; + AzureLibCache.MODELS = models; + }, gameExecutor); } + /** + * @deprecated + */ private static CompletableFuture loadAnimations( - Executor backgroundExecutor, - ResourceManager resourceManager, - BiConsumer elementConsumer + Executor backgroundExecutor, + ResourceManager resourceManager, + BiConsumer elementConsumer ) { return loadResources( - backgroundExecutor, - resourceManager, - "animations", - resource -> FileLoader.loadAnimationsFile(resource, resourceManager), - elementConsumer + backgroundExecutor, + resourceManager, + "animations", + resource -> FileLoader.loadAnimationsFile(resource, resourceManager), + elementConsumer ); } + /** + * @deprecated + */ private static CompletableFuture loadModels( - Executor backgroundExecutor, - ResourceManager resourceManager, - BiConsumer elementConsumer + Executor backgroundExecutor, + ResourceManager resourceManager, + BiConsumer elementConsumer ) { return loadResources(backgroundExecutor, resourceManager, "geo", resource -> { Model model = FileLoader.loadModelFile(resource, resourceManager); return BakedModelFactory.getForNamespace(resource.getNamespace()) - .constructGeoModel(GeometryTree.fromModel(model)); + .constructGeoModel(GeometryTree.fromModel(model)); }, elementConsumer); } + /** + * @deprecated + */ private static CompletableFuture loadResources( - Executor executor, - ResourceManager resourceManager, - String type, - Function loader, - BiConsumer map + Executor executor, + ResourceManager resourceManager, + String type, + Function loader, + BiConsumer map ) { return CompletableFuture.supplyAsync( - () -> resourceManager.listResources(type, fileName -> fileName.toString().endsWith(".json")), - executor - ) - .thenApplyAsync(resources -> { - Map> tasks = new Object2ObjectOpenHashMap<>(); - - for (ResourceLocation resource : resources.keySet()) { - tasks.put(resource, CompletableFuture.supplyAsync(() -> loader.apply(resource), executor)); - } - - return tasks; - }, executor) - .thenAcceptAsync(tasks -> { - for (Entry> entry : tasks.entrySet()) { - if (!EXCLUDED_NAMESPACES.contains(entry.getKey().getNamespace().toLowerCase(Locale.ROOT))) - map.accept(entry.getKey(), entry.getValue().join()); - } - }, executor); + () -> resourceManager.listResources(type, fileName -> fileName.toString().endsWith(".json")), + executor + ) + .thenApplyAsync(resources -> { + Map> tasks = new Object2ObjectOpenHashMap<>(); + + for (ResourceLocation resource : resources.keySet()) { + tasks.put(resource, CompletableFuture.supplyAsync(() -> loader.apply(resource), executor)); + } + + return tasks; + }, executor) + .thenAcceptAsync(tasks -> { + for (Entry> entry : tasks.entrySet()) { + if (!EXCLUDED_NAMESPACES.contains(entry.getKey().getNamespace().toLowerCase(Locale.ROOT))) + map.accept(entry.getKey(), entry.getValue().join()); + } + }, executor); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java index 4e1a25fcb..ee411567d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/BakedGeoModel.java @@ -1,23 +1,24 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.object; -import mod.azure.azurelib.core.animatable.model.CoreBakedGeoModel; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; - import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import mod.azure.azurelib.core.animatable.model.CoreBakedGeoModel; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; + /** * Baked model object for AzureLib models. + * + * @deprecated Use {@link mod.azure.azurelib.core2.model.AzBakedModel} instead. */ +@Deprecated(forRemoval = true) public class BakedGeoModel implements CoreBakedGeoModel { public final Map bonesByName; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java index 4df47dba2..a2fde7602 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoBone.java @@ -1,15 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.object; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core.animatable.model.CoreGeoBone; -import mod.azure.azurelib.core.state.BoneSnapshot; import org.jetbrains.annotations.Nullable; import org.joml.Matrix3f; import org.joml.Matrix4f; @@ -19,10 +15,16 @@ import java.util.List; import java.util.Objects; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.state.BoneSnapshot; + /** * Mutable bone object representing a set of cubes, as well as child bones.
* This is the object that is directly modified by animations to handle movement + * + * @deprecated Use {@link mod.azure.azurelib.core2.model.AzBone} instead. */ +@Deprecated(forRemoval = true) public class GeoBone implements CoreGeoBone { private final GeoBone parent; @@ -40,38 +42,60 @@ public class GeoBone implements CoreGeoBone { private final Boolean dontRender; private final Boolean reset; + private final Matrix4f modelSpaceMatrix = new Matrix4f(); + private final Matrix4f localSpaceMatrix = new Matrix4f(); + private final Matrix4f worldSpaceMatrix = new Matrix4f(); + private BoneSnapshot initialSnapshot; + private boolean hidden; + private boolean childrenHidden = false; + private float scaleX = 1; + private float scaleY = 1; + private float scaleZ = 1; + private float positionX; + private float positionY; + private float positionZ; + private float pivotX; + private float pivotY; + private float pivotZ; + private float rotX; + private float rotY; + private float rotZ; + private boolean positionChanged = false; + private boolean rotationChanged = false; + private boolean scaleChanged = false; + private Matrix3f worldSpaceNormal = new Matrix3f(); private boolean trackingMatrices; public GeoBone( - @Nullable GeoBone parent, - String name, - Boolean mirror, - @Nullable Double inflate, - @Nullable Boolean dontRender, - @Nullable Boolean reset + @Nullable GeoBone parent, + String name, + Boolean mirror, + @Nullable Double inflate, + @Nullable Boolean dontRender, + @Nullable Boolean reset ) { this.parent = parent; this.name = name; @@ -399,9 +423,9 @@ public void setModelPosition(Vector3d pos) { // Doesn't work on bones with parent transforms GeoBone parent = getParent(); Matrix4f matrix = (parent == null ? new Matrix4f().identity() : new Matrix4f(parent.getModelSpaceMatrix())) - .invert(); + .invert(); Vector4f vec = matrix.transform( - new Vector4f(-(float) pos.x / 16f, (float) pos.y / 16f, (float) pos.z / 16f, 1) + new Vector4f(-(float) pos.x / 16f, (float) pos.y / 16f, (float) pos.z / 16f, 1) ); updatePosition(-vec.x() * 16f, vec.y() * 16f, vec.z() * 16f); @@ -457,10 +481,10 @@ public boolean equals(Object obj) { @Override public int hashCode() { return Objects.hash( - getName(), - (getParent() != null ? getParent().getName() : 0), - getCubes().size(), - getChildBones().size() + getName(), + (getParent() != null ? getParent().getName() : 0), + getCubes().size(), + getChildBones().size() ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java index 5e33092a9..4a0922d3a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoCube.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.object; @@ -11,13 +9,14 @@ /** * Baked cuboid for a {@link GeoBone} + * + * @deprecated */ public record GeoCube( - GeoQuad[] quads, - Vec3 pivot, - Vec3 rotation, - Vec3 size, - double inflate, - boolean mirror -) { -} + GeoQuad[] quads, + Vec3 pivot, + Vec3 rotation, + Vec3 size, + double inflate, + boolean mirror +) {} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java index 0d65f4425..154aba466 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoQuad.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.object; @@ -10,47 +8,54 @@ import net.minecraft.core.Direction; import org.joml.Vector3f; +import mod.azure.azurelib.common.internal.common.loading.json.raw.FaceUV; + /** * Quad data holder + * + * @deprecated */ public record GeoQuad( - GeoVertex[] vertices, - Vector3f normal, - Direction direction + GeoVertex[] vertices, + Vector3f normal, + Direction direction ) { public static GeoQuad build( - GeoVertex[] vertices, - double[] uvCoords, - double[] uvSize, - float texWidth, - float texHeight, - boolean mirror, - Direction direction + GeoVertex[] vertices, + double[] uvCoords, + double[] uvSize, + FaceUV.Rotation uvRotation, + float texWidth, + float texHeight, + boolean mirror, + Direction direction ) { return build( - vertices, - (float) uvCoords[0], - (float) uvCoords[1], - (float) uvSize[0], - (float) uvSize[1], - texWidth, - texHeight, - mirror, - direction + vertices, + (float) uvCoords[0], + (float) uvCoords[1], + (float) uvSize[0], + (float) uvSize[1], + uvRotation, + texWidth, + texHeight, + mirror, + direction ); } public static GeoQuad build( - GeoVertex[] vertices, - float u, - float v, - float uSize, - float vSize, - float texWidth, - float texHeight, - boolean mirror, - Direction direction + GeoVertex[] vertices, + float u, + float v, + float uSize, + float vSize, + FaceUV.Rotation uvRotation, + float texWidth, + float texHeight, + boolean mirror, + Direction direction ) { float uWidth = (u + uSize) / texWidth; float vHeight = (v + vSize) / texHeight; @@ -62,15 +67,15 @@ public static GeoQuad build( float tempWidth = uWidth; uWidth = u; u = tempWidth; - } - else { + } else { normal.mul(-1, 1, 1); } - vertices[0] = vertices[0].withUVs(u, v); - vertices[1] = vertices[1].withUVs(uWidth, v); - vertices[2] = vertices[2].withUVs(uWidth, vHeight); - vertices[3] = vertices[3].withUVs(u, vHeight); + float[] uvs = uvRotation.rotateUvs(u, v, uWidth, vHeight); + vertices[0] = vertices[0].withUVs(uvs[0], uvs[1]); + vertices[1] = vertices[1].withUVs(uvs[2], uvs[3]); + vertices[2] = vertices[2].withUVs(uvs[4], uvs[5]); + vertices[3] = vertices[3].withUVs(uvs[6], uvs[7]); return new GeoQuad(vertices, normal, direction); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java index 0bf942552..44ba7d642 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/object/GeoVertex.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.object; @@ -15,11 +13,12 @@ * @param position The position of the vertex * @param texU The texture U coordinate * @param texV The texture V coordinate + * @deprecated */ public record GeoVertex( - Vector3f position, - float texU, - float texV + Vector3f position, + float texU, + float texV ) { public GeoVertex(double x, double y, double z) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java index d7d0d9ce9..9c636f4a3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AnimatableTexture.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.texture; @@ -14,17 +12,14 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.internal.common.AzureLib; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.SimpleTexture; import net.minecraft.client.resources.metadata.animation.AnimationMetadataSection; import net.minecraft.client.resources.metadata.animation.FrameSize; -import net.minecraft.client.resources.metadata.texture.TextureMetadataSection; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.server.packs.resources.ResourceMetadata; import net.minecraft.util.Mth; import java.io.IOException; @@ -32,12 +27,15 @@ import java.util.Arrays; import java.util.List; +import mod.azure.azurelib.common.internal.common.AzureLib; + /** * Wrapper for {@link SimpleTexture SimpleTexture} implementation allowing for casual use of animated non-atlas textures */ public class AnimatableTexture extends SimpleTexture { private AnimationContents animationContents = null; + private boolean isAnimated = false; public AnimatableTexture(final ResourceLocation location) { @@ -72,7 +70,10 @@ public void load(ResourceManager manager) throws IOException { nativeImage = NativeImage.read(inputstream); } - this.animationContents = resource.metadata().getSection(AnimationMetadataSection.SERIALIZER).map(animMeta -> new AnimationContents(nativeImage, animMeta)).orElse(null); + this.animationContents = resource.metadata() + .getSection(AnimationMetadataSection.SERIALIZER) + .map(animMeta -> new AnimationContents(nativeImage, animMeta)) + .orElse(null); if (this.animationContents != null) { if (!this.animationContents.isValid()) { @@ -84,12 +85,26 @@ public void load(ResourceManager manager) throws IOException { this.isAnimated = true; onRenderThread(() -> { - TextureUtil.prepareImage(getId(), 0, this.animationContents.frameSize.width(), this.animationContents.frameSize.height()); - nativeImage.upload(0, 0, 0, 0, 0, this.animationContents.frameSize.width(), this.animationContents.frameSize.height(), false, false); + TextureUtil.prepareImage( + getId(), + 0, + this.animationContents.frameSize.width(), + this.animationContents.frameSize.height() + ); + nativeImage.upload( + 0, + 0, + 0, + 0, + 0, + this.animationContents.frameSize.width(), + this.animationContents.frameSize.height(), + false, + false + ); }); } - } - catch (RuntimeException exception) { + } catch (RuntimeException exception) { AzureLib.LOGGER.warn("Failed reading metadata of: {}", this.location, exception); } } @@ -125,18 +140,18 @@ private boolean isValid() { private Texture generateAnimatedTexture(NativeImage image, AnimationMetadataSection animMeta) { if ( - !Mth.isMultipleOf(image.getWidth(), this.frameSize.width()) || !Mth.isMultipleOf( - image.getHeight(), - this.frameSize.height() - ) + !Mth.isMultipleOf(image.getWidth(), this.frameSize.width()) || !Mth.isMultipleOf( + image.getHeight(), + this.frameSize.height() + ) ) { AzureLib.LOGGER.error( - "Image {} size {},{} is not multiple of frame size {},{}", - AnimatableTexture.this.location, - image.getWidth(), - image.getHeight(), - this.frameSize.width(), - this.frameSize.height() + "Image {} size {},{} is not multiple of frame size {},{}", + AnimatableTexture.this.location, + image.getWidth(), + image.getHeight(), + this.frameSize.width(), + this.frameSize.height() ); return null; @@ -160,18 +175,18 @@ private Texture generateAnimatedTexture(NativeImage image, AnimationMetadataSect for (Frame frame : frames) { if (frame.time <= 0) { AzureLib.LOGGER.warn( - "Invalid frame duration on sprite {} frame {}: {}", - AnimatableTexture.this.location, - index, - frame.time + "Invalid frame duration on sprite {} frame {}: {}", + AnimatableTexture.this.location, + index, + frame.time ); unusedFrames.add(frame.index); } else if (frame.index < 0 || frame.index >= frameCount) { AzureLib.LOGGER.warn( - "Invalid frame index on sprite {} frame {}: {}", - AnimatableTexture.this.location, - index, - frame.index + "Invalid frame index on sprite {} frame {}: {}", + AnimatableTexture.this.location, + index, + frame.index ); unusedFrames.add(frame.index); } @@ -181,22 +196,21 @@ private Texture generateAnimatedTexture(NativeImage image, AnimationMetadataSect if (!unusedFrames.isEmpty()) AzureLib.LOGGER.warn( - "Unused frames in sprite {}: {}", - AnimatableTexture.this.location, - Arrays.toString(unusedFrames.toArray()) + "Unused frames in sprite {}: {}", + AnimatableTexture.this.location, + Arrays.toString(unusedFrames.toArray()) ); } return frames.size() <= 1 - ? null - : new Texture(image, frames.toArray(new Frame[0]), columns, animMeta.isInterpolatedFrames()); + ? null + : new Texture(image, frames.toArray(new Frame[0]), columns, animMeta.isInterpolatedFrames()); } private record Frame( - int index, - int time - ) { - } + int index, + int time + ) {} private class Texture implements AutoCloseable { @@ -222,12 +236,12 @@ private Texture(NativeImage baseImage, Frame[] frames, int framePanelSize, boole this.framePanelSize = framePanelSize; this.interpolating = interpolating; this.interpolatedFrame = interpolating - ? new NativeImage( + ? new NativeImage( AnimationContents.this.frameSize.width(), AnimationContents.this.frameSize.height(), false - ) - : null; + ) + : null; int time = 0; for (Frame frame : this.frames) { @@ -269,21 +283,21 @@ public void setCurrentFrame(int ticks) { if (this.currentFrame != lastFrame && this.currentSubframe == 0) { onRenderThread(() -> { TextureUtil.prepareImage( - AnimatableTexture.this.getId(), - 0, - AnimationContents.this.frameSize.width(), - AnimationContents.this.frameSize.height() + AnimatableTexture.this.getId(), + 0, + AnimationContents.this.frameSize.width(), + AnimationContents.this.frameSize.height() ); this.baseImage.upload( - 0, - 0, - 0, - getFrameX(this.currentFrame) * AnimationContents.this.frameSize.width(), - getFrameY(this.currentFrame) * AnimationContents.this.frameSize.height(), - AnimationContents.this.frameSize.width(), - AnimationContents.this.frameSize.height(), - false, - false + 0, + 0, + 0, + getFrameX(this.currentFrame) * AnimationContents.this.frameSize.width(), + getFrameY(this.currentFrame) * AnimationContents.this.frameSize.height(), + AnimationContents.this.frameSize.width(), + AnimationContents.this.frameSize.height(), + false, + false ); }); } else if (this.currentSubframe != lastSubframe && this.interpolating) { @@ -302,49 +316,49 @@ private void generateInterpolatedFrame() { int prevFramePixel = getPixel(frame.index, x, y); int nextFramePixel = getPixel(nextFrameIndex, x, y); int blendedRed = interpolate( - frameProgress, - prevFramePixel >> 16 & 255, - nextFramePixel >> 16 & 255 + frameProgress, + prevFramePixel >> 16 & 255, + nextFramePixel >> 16 & 255 ); int blendedGreen = interpolate( - frameProgress, - prevFramePixel >> 8 & 255, - nextFramePixel >> 8 & 255 + frameProgress, + prevFramePixel >> 8 & 255, + nextFramePixel >> 8 & 255 ); int blendedBlue = interpolate(frameProgress, prevFramePixel & 255, nextFramePixel & 255); this.interpolatedFrame.setPixelRGBA( - x, - y, - prevFramePixel & -16777216 | blendedRed << 16 | blendedGreen << 8 | blendedBlue + x, + y, + prevFramePixel & -16777216 | blendedRed << 16 | blendedGreen << 8 | blendedBlue ); } } TextureUtil.prepareImage( - AnimatableTexture.this.getId(), - 0, - AnimationContents.this.frameSize.width(), - AnimationContents.this.frameSize.height() + AnimatableTexture.this.getId(), + 0, + AnimationContents.this.frameSize.width(), + AnimationContents.this.frameSize.height() ); this.interpolatedFrame.upload( - 0, - 0, - 0, - 0, - 0, - AnimationContents.this.frameSize.width(), - AnimationContents.this.frameSize.height(), - false, - false + 0, + 0, + 0, + 0, + 0, + AnimationContents.this.frameSize.width(), + AnimationContents.this.frameSize.height(), + false, + false ); } } private int getPixel(int frameIndex, int x, int y) { return this.baseImage.getPixelRGBA( - x + getFrameX(frameIndex) * AnimationContents.this.frameSize.width(), - y + getFrameY(frameIndex) * AnimationContents.this.frameSize.height() + x + getFrameX(frameIndex) * AnimationContents.this.frameSize.width(), + y + getFrameY(frameIndex) * AnimationContents.this.frameSize.height() ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java index 436eddae0..6d213ad25 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/AutoGlowingTexture.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.texture; @@ -30,7 +28,6 @@ import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.function.BiFunction; -import java.util.function.Function; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.platform.Services; @@ -40,26 +37,54 @@ */ public class AutoGlowingTexture extends GeoAbstractTexture { - private static final RenderStateShard.ShaderStateShard SHADER_STATE = new RenderStateShard.ShaderStateShard(GameRenderer::getRendertypeEntityTranslucentEmissiveShader); - private static final RenderStateShard.TransparencyStateShard TRANSPARENCY_STATE = new RenderStateShard.TransparencyStateShard("translucent_transparency", () -> { - RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); - }, () -> { - RenderSystem.disableBlend(); - RenderSystem.defaultBlendFunc(); - }); - private static final RenderStateShard.WriteMaskStateShard WRITE_MASK = new RenderStateShard.WriteMaskStateShard(true, true); - private static final BiFunction GLOWING_RENDER_TYPE = Util.memoize((texture, isGlowing) -> { - RenderStateShard.TextureStateShard textureState = new RenderStateShard.TextureStateShard(texture, false, false); - - return RenderType.create("geo_glowing_layer", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, true, + private static final RenderStateShard.ShaderStateShard SHADER_STATE = new RenderStateShard.ShaderStateShard( + GameRenderer::getRendertypeEntityTranslucentEmissiveShader + ); + + private static final RenderStateShard.TransparencyStateShard TRANSPARENCY_STATE = + new RenderStateShard.TransparencyStateShard("translucent_transparency", () -> { + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate( + GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA + ); + }, () -> { + RenderSystem.disableBlend(); + RenderSystem.defaultBlendFunc(); + }); + + private static final RenderStateShard.WriteMaskStateShard WRITE_MASK = new RenderStateShard.WriteMaskStateShard( + true, + true + ); + + private static final BiFunction GLOWING_RENDER_TYPE = Util.memoize( + (texture, isGlowing) -> { + RenderStateShard.TextureStateShard textureState = new RenderStateShard.TextureStateShard( + texture, + false, + false + ); + + return RenderType.create( + "geo_glowing_layer", + DefaultVertexFormat.NEW_ENTITY, + VertexFormat.Mode.QUADS, + 256, + false, + true, RenderType.CompositeState.builder() - .setShaderState(SHADER_STATE) - .setTextureState(textureState) - .setTransparencyState(TRANSPARENCY_STATE) - .setOverlayState(new RenderStateShard.OverlayStateShard(true)) - .setWriteMaskState(WRITE_MASK).createCompositeState(isGlowing)); - }); + .setShaderState(SHADER_STATE) + .setTextureState(textureState) + .setTransparencyState(TRANSPARENCY_STATE) + .setOverlayState(new RenderStateShard.OverlayStateShard(true)) + .setWriteMaskState(WRITE_MASK) + .createCompositeState(isGlowing) + ); + } + ); private static final String APPENDIX = "_glowmask"; @@ -82,8 +107,8 @@ protected static ResourceLocation getEmissiveResource(ResourceLocation baseResou ResourceLocation path = appendToPath(baseResource, APPENDIX); generateTexture( - path, - textureManager -> textureManager.register(path, new AutoGlowingTexture(baseResource, path)) + path, + textureManager -> textureManager.register(path, new AutoGlowingTexture(baseResource, path)) ); return path; @@ -98,9 +123,9 @@ public static RenderType getRenderType(ResourceLocation texture) { return GLOWING_RENDER_TYPE.apply(getEmissiveResource(texture), false); } - /** - * Return a cached instance of the RenderType for the given texture for AutoGlowingGeoLayer rendering, while the entity has an outline + * Return a cached instance of the RenderType for the given texture for AutoGlowingGeoLayer rendering, while the + * entity has an outline * * @param texture The texture of the resource to apply a glow layer to */ @@ -125,11 +150,11 @@ protected RenderCall loadTexture(ResourceManager resourceManager, Minecraft mc) Resource textureBaseResource = resourceManager.getResource(this.textureBase).get(); NativeImage baseImage = originalTexture instanceof DynamicTexture dynamicTexture - ? dynamicTexture.getPixels() - : NativeImage.read(textureBaseResource.open()); + ? dynamicTexture.getPixels() + : NativeImage.read(textureBaseResource.open()); NativeImage glowImage = null; Optional textureBaseMeta = textureBaseResource.metadata() - .getSection(TextureMetadataSection.SERIALIZER); + .getSection(TextureMetadataSection.SERIALIZER); boolean blur = textureBaseMeta.isPresent() && textureBaseMeta.get().isBlur(); boolean clamp = textureBaseMeta.isPresent() && textureBaseMeta.get().isClamp(); @@ -142,7 +167,7 @@ protected RenderCall loadTexture(ResourceManager resourceManager, Minecraft mc) glowLayerMeta = GeoGlowingTextureMeta.fromExistingImage(glowImage); } else { Optional meta = textureBaseResource.metadata() - .getSection(GeoGlowingTextureMeta.DESERIALIZER); + .getSection(GeoGlowingTextureMeta.DESERIALIZER); if (meta.isPresent()) { glowLayerMeta = meta.get(); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java index 68d8875c1..e0dfb617e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoAbstractTexture.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.texture; @@ -28,6 +26,8 @@ /** * Abstract texture wrapper for AzureLib textures.
* Mostly just handles boilerplate + * + * @deprecated */ public abstract class GeoAbstractTexture extends AbstractTexture { @@ -35,21 +35,21 @@ public abstract class GeoAbstractTexture extends AbstractTexture { * Generates the texture instance for the given path with the given appendix if it hasn't already been generated */ protected static void generateTexture( - ResourceLocation texturePath, - Consumer textureManagerConsumer + ResourceLocation texturePath, + Consumer textureManagerConsumer ) { if (!RenderSystem.isOnRenderThreadOrInit()) throw new IllegalThreadStateException( - "Texture loading called outside of the render thread! This should DEFINITELY not be happening." + "Texture loading called outside of the render thread! This should DEFINITELY not be happening." ); TextureManager textureManager = Minecraft.getInstance().getTextureManager(); if ( - !(textureManager.getTexture( - texturePath, - MissingTextureAtlasSprite.getTexture() - ) instanceof GeoAbstractTexture) + !(textureManager.getTexture( + texturePath, + MissingTextureAtlasSprite.getTexture() + ) instanceof GeoAbstractTexture) ) textureManagerConsumer.accept(textureManager); } @@ -66,7 +66,10 @@ public static ResourceLocation appendToPath(ResourceLocation location, String su String path = location.getPath(); int i = path.lastIndexOf('.'); - return ResourceLocation.fromNamespaceAndPath(location.getNamespace(), path.substring(0, i) + suffix + path.substring(i)); + return ResourceLocation.fromNamespaceAndPath( + location.getNamespace(), + path.substring(0, i) + suffix + path.substring(i) + ); } @Override diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java index 095aaa6e2..103b0ac00 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/cache/texture/GeoGlowingTextureMeta.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.cache.texture; @@ -13,7 +11,6 @@ import com.google.gson.JsonParseException; import com.mojang.blaze3d.platform.NativeImage; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.api.client.renderer.layer.AutoGlowingGeoLayer; import net.minecraft.server.packs.metadata.MetadataSectionSerializer; import net.minecraft.util.FastColor; import net.minecraft.util.GsonHelper; @@ -21,6 +18,8 @@ import java.util.List; +import mod.azure.azurelib.common.api.client.renderer.layer.AutoGlowingGeoLayer; + /** * Metadata class that stores the data for AzureLib's {@link AutoGlowingGeoLayer emissive texture feature} for a given * texture @@ -28,60 +27,61 @@ public class GeoGlowingTextureMeta { public static final MetadataSectionSerializer DESERIALIZER = - new MetadataSectionSerializer<>() { + new MetadataSectionSerializer<>() { - @Override - public String getMetadataSectionName() { - return "glowsections"; - } + @Override + public String getMetadataSectionName() { + return "glowsections"; + } - @Override - public GeoGlowingTextureMeta fromJson(JsonObject json) { - List pixels = fromSections(GsonHelper.getAsJsonArray(json, "sections", null)); + @Override + public GeoGlowingTextureMeta fromJson(JsonObject json) { + List pixels = fromSections(GsonHelper.getAsJsonArray(json, "sections", null)); - if (pixels.isEmpty()) - throw new JsonParseException( - "Empty glowlayer sections file. Must have at least one glow section!"); + if (pixels.isEmpty()) + throw new JsonParseException( + "Empty glowlayer sections file. Must have at least one glow section!" + ); - return new GeoGlowingTextureMeta(pixels); - } + return new GeoGlowingTextureMeta(pixels); + } - /** - * Generate a {@link Pixel} collection from the "sections" array of the mcmeta file - */ - private List fromSections(@Nullable JsonArray sectionsArray) { - if (sectionsArray == null) - return List.of(); - - List pixels = new ObjectArrayList<>(); - - for (JsonElement element : sectionsArray) { - if (!(element instanceof JsonObject obj)) - throw new JsonParseException( - "Invalid glowsections json format, expected a JsonObject, found: " + element.getClass() - ); - - int x1 = GsonHelper.getAsInt(obj, "x1", GsonHelper.getAsInt(obj, "x", 0)); - int y1 = GsonHelper.getAsInt(obj, "y1", GsonHelper.getAsInt(obj, "y", 0)); - int x2 = GsonHelper.getAsInt(obj, "x2", GsonHelper.getAsInt(obj, "w", 0) + x1); - int y2 = GsonHelper.getAsInt(obj, "y2", GsonHelper.getAsInt(obj, "h", 0) + y1); - int alpha = GsonHelper.getAsInt(obj, "alpha", GsonHelper.getAsInt(obj, "a", 0)); - - if (x1 + y1 + x2 + y2 == 0) - throw new IllegalArgumentException( - "Invalid glowsections section object, section must be at least one pixel in size" - ); - - for (int x = x1; x <= x2; x++) { - for (int y = y1; y <= y2; y++) { - pixels.add(new Pixel(x, y, alpha)); - } + /** + * Generate a {@link Pixel} collection from the "sections" array of the mcmeta file + */ + private List fromSections(@Nullable JsonArray sectionsArray) { + if (sectionsArray == null) + return List.of(); + + List pixels = new ObjectArrayList<>(); + + for (JsonElement element : sectionsArray) { + if (!(element instanceof JsonObject obj)) + throw new JsonParseException( + "Invalid glowsections json format, expected a JsonObject, found: " + element.getClass() + ); + + int x1 = GsonHelper.getAsInt(obj, "x1", GsonHelper.getAsInt(obj, "x", 0)); + int y1 = GsonHelper.getAsInt(obj, "y1", GsonHelper.getAsInt(obj, "y", 0)); + int x2 = GsonHelper.getAsInt(obj, "x2", GsonHelper.getAsInt(obj, "w", 0) + x1); + int y2 = GsonHelper.getAsInt(obj, "y2", GsonHelper.getAsInt(obj, "h", 0) + y1); + int alpha = GsonHelper.getAsInt(obj, "alpha", GsonHelper.getAsInt(obj, "a", 0)); + + if (x1 + y1 + x2 + y2 == 0) + throw new IllegalArgumentException( + "Invalid glowsections section object, section must be at least one pixel in size" + ); + + for (int x = x1; x <= x2; x++) { + for (int y = y1; y <= y2; y++) { + pixels.add(new Pixel(x, y, alpha)); } } - - return pixels; } - }; + + return pixels; + } + }; private final List pixels; @@ -119,10 +119,10 @@ public void createImageMask(NativeImage originalImage, NativeImage newImage) { if (pixel.alpha > 0) color = FastColor.ABGR32.color( - pixel.alpha, - FastColor.ABGR32.blue(color), - FastColor.ABGR32.green(color), - FastColor.ABGR32.red(color) + pixel.alpha, + FastColor.ABGR32.blue(color), + FastColor.ABGR32.green(color), + FastColor.ABGR32.red(color) ); newImage.setPixelRGBA(pixel.x, pixel.y, color); @@ -138,9 +138,8 @@ public void createImageMask(NativeImage originalImage, NativeImage newImage) { * @param alpha The alpha value of the mask */ private record Pixel( - int x, - int y, - int alpha - ) { - } + int x, + int y, + int alpha + ) {} } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolder.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolder.java index 632b9f959..838aac5c9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolder.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolder.java @@ -1,11 +1,15 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; + import mod.azure.azurelib.common.internal.client.config.IValidationHandler; import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.AzureLibException; @@ -16,12 +20,6 @@ import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; import mod.azure.azurelib.common.internal.common.config.value.ObjectValue; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.*; - /** * Manages config values and stores some default parameters of your config class. This class also acts as config * registry. @@ -62,11 +60,11 @@ public final class ConfigHolder { private final Object lock = new Object(); public ConfigHolder( - Class cfgClass, - String configId, - String filename, - String group, - IConfigFormatHandler format + Class cfgClass, + String configId, + String filename, + String group, + IConfigFormatHandler format ) { this.configClass = cfgClass; this.configId = configId; @@ -75,7 +73,7 @@ public ConfigHolder( try { this.configInstance = cfgClass.getDeclaredConstructor().newInstance(); } catch ( - NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e + NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e ) { AzureLib.LOGGER.fatal(AzureLib.MAIN_MARKER, "Failed to instantiate config class for {} config", configId); throw new AzureLibException("Config create failed", e); @@ -176,9 +174,9 @@ public Object getLock() { } private Map> serializeType( - Class type, - Object instance, - boolean saveValue + Class type, + Object instance, + boolean saveValue ) throws IllegalAccessException { Map> map = new LinkedHashMap<>(); Field[] fields = type.getFields(); @@ -189,18 +187,18 @@ private Map> serializeType( int modifiers = field.getModifiers(); if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) { AzureLib.LOGGER.warn( - ConfigIO.MARKER, - "Skipping config field {}, only instance non-final types are supported", - field + ConfigIO.MARKER, + "Skipping config field {}, only instance non-final types are supported", + field ); continue; } TypeAdapter adapter = TypeAdapters.forType(field.getType()); if (adapter == null) { AzureLib.LOGGER.warn( - ConfigIO.MARKER, - "Missing adapter for type {}, skipping serialization", - field.getType() + ConfigIO.MARKER, + "Missing adapter for type {}, skipping serialization", + field.getType() ); continue; } @@ -211,39 +209,39 @@ private Map> serializeType( } field.setAccessible(true); ConfigValue cfgValue = adapter.serialize( - field.getName(), - comments, - field.get(instance), - (type1, instance1) -> serializeType(type1, instance1, false), - new TypeAdapter.AdapterContext() { - - @Override - public TypeAdapter getAdapter() { - return adapter; - } + field.getName(), + comments, + field.get(instance), + (type1, instance1) -> serializeType(type1, instance1, false), + new TypeAdapter.AdapterContext() { + + @Override + public TypeAdapter getAdapter() { + return adapter; + } - @Override - public Field getOwner() { - return field; - } + @Override + public Field getOwner() { + return field; + } - @Override - public void setFieldValue(Object value) { - field.setAccessible(true); - try { - adapter.setFieldValue(field, instance, value); - } catch (IllegalAccessException e) { - AzureLib.LOGGER.error( - ConfigIO.MARKER, - "Failed to update config value for field {} from {} to a new value {} due to error {}", - field.getName(), - type, - value, - e - ); - } + @Override + public void setFieldValue(Object value) { + field.setAccessible(true); + try { + adapter.setFieldValue(field, instance, value); + } catch (IllegalAccessException e) { + AzureLib.LOGGER.error( + ConfigIO.MARKER, + "Failed to update config value for field {} from {} to a new value {} due to error {}", + field.getName(), + type, + value, + e + ); } } + } ); Configurable.ValueUpdateCallback callback = field.getAnnotation(Configurable.ValueUpdateCallback.class); if (callback != null) { @@ -259,10 +257,10 @@ public void setFieldValue(Object value) { } private void processCallback( - Configurable.ValueUpdateCallback callback, - Class type, - Object instance, - ConfigValue value + Configurable.ValueUpdateCallback callback, + Class type, + Object instance, + ConfigValue value ) { String methodName = callback.method(); try { @@ -281,24 +279,24 @@ private void processCallback( }; value.setValueValidator(setValueCallback); AzureLib.LOGGER.debug( - ConfigIO.MARKER, - "Attached new value listener method '{}' for config value {}", - methodName, - value.getId() + ConfigIO.MARKER, + "Attached new value listener method '{}' for config value {}", + methodName, + value.getId() ); } catch (NoSuchMethodException e) { AzureLib.LOGGER.error( - ConfigIO.MARKER, - "Unable to map method {} for config value {} due to {}", - methodName, - value.getId(), - e + ConfigIO.MARKER, + "Unable to map method {} for config value {} due to {}", + methodName, + value.getId(), + e ); } catch (Exception e) { AzureLib.LOGGER.fatal( - ConfigIO.MARKER, - "Fatal error occurred while trying to map value listener for {} method", - methodName + ConfigIO.MARKER, + "Fatal error occurred while trying to map value listener for {} method", + methodName ); throw new AzureLibException("Value listener map failed", e); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolderRegistry.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolderRegistry.java index 4be9352d2..9024711cc 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolderRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigHolderRegistry.java @@ -1,12 +1,12 @@ package mod.azure.azurelib.common.internal.common.config; +import java.util.*; +import java.util.stream.Collectors; + import mod.azure.azurelib.common.internal.common.AzureLibMod; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormatHandler; import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import java.util.*; -import java.util.stream.Collectors; - /** * @author Boston Vanseghi */ @@ -58,9 +58,9 @@ public static Map>> getConfigGroupingByGroup() { */ public static List> getConfigsByGroup(String group) { return REGISTERED_CONFIGS.values() - .stream() - .filter(configHolder -> configHolder.getGroup().equals(group)) - .toList(); + .stream() + .filter(configHolder -> configHolder.getGroup().equals(group)) + .toList(); } /** @@ -70,9 +70,9 @@ public static List> getConfigsByGroup(String group) { */ public static Set getSynchronizedConfigs() { return REGISTERED_CONFIGS.entrySet() - .stream() - .filter(e -> !e.getValue().getNetworkSerializedFields().isEmpty()) - .map(Map.Entry::getKey) - .collect(Collectors.toSet()); + .stream() + .filter(e -> !e.getValue().getNetworkSerializedFields().isEmpty()) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigUtils.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigUtils.java index bf2dc3f8f..3ea974948 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigUtils.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/ConfigUtils.java @@ -1,14 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; import net.minecraft.client.gui.components.EditBox; import org.jetbrains.annotations.Nullable; @@ -20,11 +15,15 @@ import java.util.Objects; import java.util.regex.Pattern; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; + public final class ConfigUtils { - public static final char[] INTEGER_CHARS = {'-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + public static final char[] INTEGER_CHARS = { '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; - public static final char[] DECIMAL_CHARS = {'-', '.', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + public static final char[] DECIMAL_CHARS = { '-', '.', 'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; public static final Pattern INTEGER_PATTERN = Pattern.compile("-?[0-9]+"); @@ -49,21 +48,21 @@ private ConfigUtils() { public static void logCorrectedMessage(String field, @Nullable Object prevValue, Object corrected) { AzureLib.LOGGER.warn( - ConfigIO.MARKER, - "Correcting config value '{}' from '{}' to '{}'", - field, - Objects.toString(prevValue), - corrected + ConfigIO.MARKER, + "Correcting config value '{}' from '{}' to '{}'", + field, + Objects.toString(prevValue), + corrected ); } public static void logArraySizeCorrectedMessage(String field, Object prevValue, Object corrected) { AzureLib.LOGGER.warn( - ConfigIO.MARKER, - "Correcting config array value '{}' due to invalid size from '{}' to '{}'", - field, - prevValue, - corrected + ConfigIO.MARKER, + "Correcting config array value '{}' due to invalid size from '{}' to '{}'", + field, + prevValue, + corrected ); } @@ -113,8 +112,8 @@ public static double[] unboxArray(Double[] values) { } public static > E getEnumConstant( - String value, - Class declaringClass + String value, + Class declaringClass ) throws ConfigValueMissingException { E[] constants = declaringClass.getEnumConstants(); for (E e : constants) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/Configurable.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/Configurable.java index bb5ceb967..3141e7b04 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/Configurable.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/Configurable.java @@ -1,18 +1,16 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config; -import mod.azure.azurelib.common.internal.client.config.IValidationHandler; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import mod.azure.azurelib.common.internal.client.config.IValidationHandler; + /** * Marker annotation for field to config serialization. Only public instance fields are allowed. * @@ -42,8 +40,7 @@ */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) - @interface Synchronized { - } + @interface Synchronized {} /** * Allows you to specify number range for int or long values. This annotation is also applicable to int/long arrays @@ -109,7 +106,7 @@ /** * @return Flags used for {@link java.util.regex.Pattern} object. You can use for example value like - * {@code flags = Pattern.CASE_INSENTITIVE | Pattern.LITERAL} for flag specification + * {@code flags = Pattern.CASE_INSENTITIVE | Pattern.LITERAL} for flag specification */ int flags() default 0; @@ -126,8 +123,7 @@ */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) - @interface FixedSize { - } + @interface FixedSize {} /** * Allows you to map custom listener method to listen for value change. Could be useful for example when validating @@ -151,7 +147,7 @@ * Handles remapping of boxed java types to their primitive values * * @return Whether remapping is allowed, unless specific implementation is provided, this should always be set - * to true + * to true */ boolean allowPrimitivesMapping() default true; } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapter.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapter.java index b7a882724..0ff48c252 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapter.java @@ -1,25 +1,24 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.adapter; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; import net.minecraft.network.FriendlyByteBuf; import java.lang.reflect.Field; import java.util.Map; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; + public abstract class TypeAdapter { public abstract ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException; public abstract void encodeToBuffer(ConfigValue value, FriendlyByteBuf buffer); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapters.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapters.java index 7e49b8ecf..6377fbf10 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapters.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeAdapters.java @@ -1,17 +1,15 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.adapter; -import mod.azure.azurelib.common.internal.common.config.value.*; - import java.util.Comparator; import java.util.HashMap; import java.util.Map; +import mod.azure.azurelib.common.internal.common.config.value.*; + public final class TypeAdapters { private static final Map ADAPTER_MAP = new HashMap<>(); @@ -48,12 +46,12 @@ private TypeAdapters() { public static TypeAdapter forType(Class type) { return ADAPTER_MAP.entrySet() - .stream() - .filter(entry -> entry.getKey().test(type)) - .sorted(Comparator.comparingInt(value -> value.getKey().priority())) - .map(Map.Entry::getValue) - .findFirst() - .orElse(null); + .stream() + .filter(entry -> entry.getKey().test(type)) + .sorted(Comparator.comparingInt(value -> value.getKey().priority())) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null); } public static void registerTypeAdapter(TypeMatcher matcher, TypeAdapter adapter) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeMatcher.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeMatcher.java index 90c84b4f7..210f388b6 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeMatcher.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/adapter/TypeMatcher.java @@ -1,17 +1,16 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.adapter; -import mod.azure.azurelib.common.internal.common.AzureLib; import net.minecraft.resources.ResourceLocation; import java.util.Objects; import java.util.function.Predicate; +import mod.azure.azurelib.common.internal.common.AzureLib; + public interface TypeMatcher extends Predicate> { static TypeMatcher matchBoolean() { @@ -76,7 +75,7 @@ static TypeMatcher matchEnumArray() { static TypeMatcher matchObject() { return NamedMatcherImpl.vanilla("object", type -> !type.isArray()) - .withPriority(Integer.MAX_VALUE); + .withPriority(Integer.MAX_VALUE); } ResourceLocation getIdentifier(); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigReadException.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigReadException.java index 4ae6026b3..61abe8869 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigReadException.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigReadException.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.exception; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigValueMissingException.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigValueMissingException.java index 8745a8bfe..700ea4159 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigValueMissingException.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/exception/ConfigValueMissingException.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.exception; @@ -13,8 +11,7 @@ public class ConfigValueMissingException extends Exception { */ private static final long serialVersionUID = -6063813873167943417L; - public ConfigValueMissingException() { - } + public ConfigValueMissingException() {} public ConfigValueMissingException(String message) { super(message); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/ConfigFormats.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/ConfigFormats.java index 8df2aa801..3efe91753 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/ConfigFormats.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/ConfigFormats.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/GsonFormat.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/GsonFormat.java index 8a90bffbc..c91276cc0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/GsonFormat.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/GsonFormat.java @@ -1,19 +1,10 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; import com.google.gson.*; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.ConfigUtils; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; import java.io.File; import java.io.FileReader; @@ -27,6 +18,14 @@ import java.util.function.Consumer; import java.util.function.Function; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.ConfigUtils; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; + public final class GsonFormat implements IConfigFormat { private final Gson gson; @@ -294,9 +293,9 @@ private T tryRead(String field, Function function) throws Co } private T[] readArray( - String field, - Function arrayFactory, - Function function + String field, + Function arrayFactory, + Function function ) throws ConfigValueMissingException { JsonElement element = this.root.get(field); if (element == null || !element.isJsonArray()) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormat.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormat.java index 2164bd643..9b985a017 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormat.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormat.java @@ -1,21 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; - import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Map; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; + /** * Handles exporting of data to custom file format * diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormatHandler.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormatHandler.java index 705e0490d..47aaa052f 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormatHandler.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/IConfigFormatHandler.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/PropertiesFormat.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/PropertiesFormat.java index 4960fd248..d45f45141 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/PropertiesFormat.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/PropertiesFormat.java @@ -1,16 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; -import mod.azure.azurelib.common.internal.common.config.ConfigUtils; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; import org.jetbrains.annotations.Nullable; import java.io.*; @@ -19,6 +12,12 @@ import java.util.function.Function; import java.util.stream.Collectors; +import mod.azure.azurelib.common.internal.common.config.ConfigUtils; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; + public final class PropertiesFormat implements IConfigFormat { private final Settings settings; @@ -287,16 +286,16 @@ public void writeMap(String field, Map> value) { @Override public void readMap(String field, Collection> values) throws ConfigValueMissingException { Set validElements = this.parsed.keySet() - .stream() - .filter(key -> { - String[] strings = key.split("\\.", 2); - if (strings.length < 2) { - return false; - } - String prefix = strings[0]; - return prefix.equals(field); - }) - .collect(Collectors.toSet()); + .stream() + .filter(key -> { + String[] strings = key.split("\\.", 2); + if (strings.length < 2) { + return false; + } + String prefix = strings[0]; + return prefix.equals(field); + }) + .collect(Collectors.toSet()); Map parsed = new HashMap<>(); for (String key : validElements) { String s = key.split("\\.", 2)[1]; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/YamlFormat.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/YamlFormat.java index 49528721f..1711aa070 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/YamlFormat.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/format/YamlFormat.java @@ -1,23 +1,21 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.format; -import mod.azure.azurelib.common.internal.common.config.ConfigUtils; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; - import java.io.*; import java.lang.reflect.Array; import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; +import mod.azure.azurelib.common.internal.common.config.ConfigUtils; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.config.value.IDescriptionProvider; + public class YamlFormat implements IConfigFormat { // writing diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/ConfigIO.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/ConfigIO.java index 041715982..bf83b9dfa 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/ConfigIO.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/ConfigIO.java @@ -1,17 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.io; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.AzureLibException; -import mod.azure.azurelib.common.internal.common.config.ConfigHolder; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormatHandler; import net.minecraft.CrashReport; import net.minecraft.ReportedException; import org.apache.logging.log4j.Marker; @@ -20,14 +12,20 @@ import java.io.File; import java.io.IOException; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.AzureLibException; +import mod.azure.azurelib.common.internal.common.config.ConfigHolder; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigReadException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormatHandler; + public final class ConfigIO { public static final Marker MARKER = MarkerManager.getMarker("IO"); public static final FileWatchManager FILE_WATCH_MANAGER = new FileWatchManager(); - private ConfigIO() { - } + private ConfigIO() {} public static void processConfig(ConfigHolder holder) { AzureLib.LOGGER.debug(MARKER, "Starting processing of config {}", holder.getConfigId()); @@ -38,9 +36,9 @@ public static void processConfig(ConfigHolder holder) { readConfig(holder); } catch (IOException e) { AzureLib.LOGGER.error( - MARKER, - "Config read failed for config ID {}, will create default config file", - holder.getConfigId() + MARKER, + "Config read failed for config ID {}, will create default config file", + holder.getConfigId() ); } } @@ -81,14 +79,16 @@ private static void processSafely(ConfigHolder holder, Runnable action) { } } catch (Exception e) { AzureLib.LOGGER.fatal( - MARKER, - "Error loading config {} due to critical error '{}'. Report this issue to this config's owner!", - holder.getConfigId(), - e.getMessage() + MARKER, + "Error loading config {} due to critical error '{}'. Report this issue to this config's owner!", + holder.getConfigId(), + e.getMessage() ); throw new ReportedException( - CrashReport.forThrowable(e, - "Config " + holder.getConfigId() + " failed. Report issue to config owner") + CrashReport.forThrowable( + e, + "Config " + holder.getConfigId() + " failed. Report issue to config owner" + ) ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/FileWatchManager.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/FileWatchManager.java index 88008753b..5cb03fefe 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/FileWatchManager.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/io/FileWatchManager.java @@ -1,14 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.io; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.AzureLibException; -import mod.azure.azurelib.common.internal.common.config.ConfigHolder; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; import org.jetbrains.annotations.Nullable; @@ -22,6 +17,10 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.AzureLibException; +import mod.azure.azurelib.common.internal.common.config.ConfigHolder; + public final class FileWatchManager { public static final Marker MARKER = MarkerManager.getMarker("FileWatching"); @@ -43,9 +42,9 @@ public FileWatchManager() { watchService = FileSystems.getDefault().newWatchService(); } catch (IOException e) { AzureLib.LOGGER.error( - MARKER, - "Failed to initialize file watch service due to error, configs won't be automatically refreshed", - e + MARKER, + "Failed to initialize file watch service due to error, configs won't be automatically refreshed", + e ); } finally { this.service = watchService; @@ -108,9 +107,9 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th }, 0L, 1000L, TimeUnit.MILLISECONDS); } catch (IOException e) { AzureLib.LOGGER.error( - MARKER, - "Unable to create watch key for config directory, disabling auto-sync function", - e + MARKER, + "Unable to create watch key for config directory, disabling auto-sync function", + e ); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/NotificationSeverity.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/NotificationSeverity.java index 1ffc43253..11cd83e26 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/NotificationSeverity.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/NotificationSeverity.java @@ -1,15 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.validate; -import mod.azure.azurelib.common.internal.common.AzureLib; import net.minecraft.ChatFormatting; import net.minecraft.resources.ResourceLocation; +import mod.azure.azurelib.common.internal.common.AzureLib; + public enum NotificationSeverity { INFO("", ChatFormatting.RESET, 0xF0030319, 0x502493E5, 0x502469E5), @@ -17,9 +16,13 @@ public enum NotificationSeverity { ERROR("error", ChatFormatting.RED, 0xF0270006, 0x50FF0000, 0x50880000); public final int background; + public final int fadeMin; + public final int fadeMax; + private final ResourceLocation icon; + private final ChatFormatting extraFormatting; NotificationSeverity(String iconName, ChatFormatting formatting, int background, int fadeMin, int fadeMax) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/ValidationResult.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/ValidationResult.java index fa07f92e2..64101f19a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/ValidationResult.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/validate/ValidationResult.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.validate; @@ -10,13 +8,13 @@ import net.minecraft.network.chat.MutableComponent; public record ValidationResult( - NotificationSeverity severity, - MutableComponent text + NotificationSeverity severity, + MutableComponent text ) { private static final ValidationResult OK = new ValidationResult( - NotificationSeverity.INFO, - (MutableComponent) CommonComponents.EMPTY + NotificationSeverity.INFO, + (MutableComponent) CommonComponents.EMPTY ); public static ValidationResult ok() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ArrayValue.java index c75dd4489..9418cf1a9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ArrayValue.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanArrayValue.java index 49778b1dc..634b6ccc3 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; public class BooleanArrayValue extends ConfigValue implements ArrayValue { @@ -40,9 +39,9 @@ protected boolean[] getCorrectedValue(boolean[] in) { boolean[] defaultArray = this.valueData.getDefaultValue(); if (in.length != defaultArray.length) { ConfigUtils.logArraySizeCorrectedMessage( - this.getId(), - Arrays.toString(in), - Arrays.toString(defaultArray) + this.getId(), + Arrays.toString(in), + Arrays.toString(defaultArray) ); return defaultArray; } @@ -79,11 +78,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new BooleanArrayValue(ValueData.of(name, (boolean[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanValue.java index 0b0be276e..a6e2fff73 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/BooleanValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import net.minecraft.network.FriendlyByteBuf; import java.lang.reflect.Field; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; + public final class BooleanValue extends ConfigValue { public BooleanValue(ValueData valueData) { @@ -35,11 +34,11 @@ public static class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) { return new BooleanValue(ValueData.of(name, (boolean) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/CharValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/CharValue.java index 88b52dbff..c81332a16 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/CharValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/CharValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import net.minecraft.network.FriendlyByteBuf; import java.lang.reflect.Field; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; + public final class CharValue extends ConfigValue { public CharValue(ValueData valueData) { @@ -33,11 +32,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new CharValue(ValueData.of(name, (char) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ConfigValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ConfigValue.java index 1529a818f..c501983df 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ConfigValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ConfigValue.java @@ -1,17 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.client.config.IValidationHandler; -import mod.azure.azurelib.common.internal.common.config.ConfigUtils; -import mod.azure.azurelib.common.internal.common.config.Configurable; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; @@ -20,6 +12,13 @@ import java.util.List; import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.client.config.IValidationHandler; +import mod.azure.azurelib.common.internal.common.config.ConfigUtils; +import mod.azure.azurelib.common.internal.common.config.Configurable; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; + public abstract class ConfigValue implements Supplier { protected final ValueData valueData; @@ -73,8 +72,7 @@ public final void processFieldData(Field field) { this.readFieldData(field); } - protected void readFieldData(Field field) { - } + protected void readFieldData(Field field) {} protected T getCorrectedValue(T in) { return in; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DecimalValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DecimalValue.java index 6569a47a8..09a05d928 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DecimalValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DecimalValue.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.Configurable; - import java.lang.reflect.Field; import java.util.Objects; +import mod.azure.azurelib.common.internal.common.config.Configurable; + public abstract class DecimalValue extends ConfigValue { protected Range range; @@ -50,8 +48,11 @@ private Range(double min, double max) { public static Range newBoundedRange(double min, double max) { if (min > max) { throw new IllegalArgumentException( - String.format("Invalid number range: Min value (%f) cannot be bigger than max value (%f)", min, - max) + String.format( + "Invalid number range: Min value (%f) cannot be bigger than max value (%f)", + min, + max + ) ); } return new Range(min, max); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleArrayValue.java index 9b3ff8953..9e1cefdab 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; public class DoubleArrayValue extends ConfigValue implements ArrayValue { @@ -36,8 +35,8 @@ protected void readFieldData(Field field) { this.fixedSize = field.getAnnotation(Configurable.FixedSize.class) != null; Configurable.DecimalRange decimalRange = field.getAnnotation(Configurable.DecimalRange.class); this.range = decimalRange != null - ? DecimalValue.Range.newBoundedRange(decimalRange.min(), decimalRange.max()) - : DecimalValue.Range.unboundedDouble(); + ? DecimalValue.Range.newBoundedRange(decimalRange.min(), decimalRange.max()) + : DecimalValue.Range.unboundedDouble(); } @Override @@ -46,9 +45,9 @@ protected double[] getCorrectedValue(double[] in) { double[] defaultArray = this.valueData.getDefaultValue(); if (in.length != defaultArray.length) { ConfigUtils.logArraySizeCorrectedMessage( - this.getId(), - Arrays.toString(in), - Arrays.toString(defaultArray) + this.getId(), + Arrays.toString(in), + Arrays.toString(defaultArray) ); in = defaultArray; } @@ -117,11 +116,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new DoubleArrayValue(ValueData.of(name, (double[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleValue.java index fa3fd2603..a2bc2ee01 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/DoubleValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; public class DoubleValue extends DecimalValue { @@ -46,11 +45,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new DoubleValue(ValueData.of(name, (double) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumArrayValue.java index 680f228e2..4e11af2c7 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.Configurable; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import net.minecraft.network.FriendlyByteBuf; import java.lang.reflect.Array; import java.lang.reflect.Field; +import mod.azure.azurelib.common.internal.common.config.Configurable; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; + public class EnumArrayValue> extends ConfigValue implements ArrayValue { private boolean fixedSize; @@ -50,11 +49,11 @@ public static final class Adapter> extends TypeAdapter { @SuppressWarnings("unchecked") @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new EnumArrayValue<>(ValueData.of(name, (E[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumValue.java index 65ec420a7..4dd39de09 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/EnumValue.java @@ -1,15 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; public class EnumValue> extends ConfigValue { @@ -32,11 +31,11 @@ public static final class Adapter> extends TypeAdapter { @SuppressWarnings("unchecked") @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new EnumValue<>(ValueData.of(name, (E) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatArrayValue.java index 73f6fd3fd..59a3310a2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; public class FloatArrayValue extends ConfigValue implements ArrayValue { @@ -36,8 +35,8 @@ protected void readFieldData(Field field) { this.fixedSize = field.getAnnotation(Configurable.FixedSize.class) != null; Configurable.DecimalRange decimalRange = field.getAnnotation(Configurable.DecimalRange.class); this.range = decimalRange != null - ? DecimalValue.Range.newBoundedRange(decimalRange.min(), decimalRange.max()) - : DecimalValue.Range.unboundedFloat(); + ? DecimalValue.Range.newBoundedRange(decimalRange.min(), decimalRange.max()) + : DecimalValue.Range.unboundedFloat(); } @Override @@ -46,9 +45,9 @@ protected float[] getCorrectedValue(float[] in) { float[] defaultArray = this.valueData.getDefaultValue(); if (in.length != defaultArray.length) { ConfigUtils.logArraySizeCorrectedMessage( - this.getId(), - Arrays.toString(in), - Arrays.toString(defaultArray) + this.getId(), + Arrays.toString(in), + Arrays.toString(defaultArray) ); in = defaultArray; } @@ -117,11 +116,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new FloatArrayValue(ValueData.of(name, (float[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatValue.java index 3254d79ee..da8be4e84 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/FloatValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; public class FloatValue extends DecimalValue { @@ -46,11 +45,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new FloatValue(ValueData.of(name, (float) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IDescriptionProvider.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IDescriptionProvider.java index df025e7c2..44e007fae 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IDescriptionProvider.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IDescriptionProvider.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntArrayValue.java index 9d83ce3f8..2950341a0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; public class IntArrayValue extends ConfigValue implements ArrayValue { @@ -36,8 +35,8 @@ protected void readFieldData(Field field) { this.fixedSize = field.getAnnotation(Configurable.FixedSize.class) != null; Configurable.Range intRange = field.getAnnotation(Configurable.Range.class); this.range = intRange != null - ? IntegerValue.Range.newBoundedRange(intRange.min(), intRange.max()) - : IntegerValue.Range.unboundedInt(); + ? IntegerValue.Range.newBoundedRange(intRange.min(), intRange.max()) + : IntegerValue.Range.unboundedInt(); } @Override @@ -46,9 +45,9 @@ protected int[] getCorrectedValue(int[] in) { int[] defaultArray = this.valueData.getDefaultValue(); if (in.length != defaultArray.length) { ConfigUtils.logArraySizeCorrectedMessage( - this.getId(), - Arrays.toString(in), - Arrays.toString(defaultArray) + this.getId(), + Arrays.toString(in), + Arrays.toString(defaultArray) ); in = defaultArray; } @@ -117,11 +116,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new IntArrayValue(ValueData.of(name, (int[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntValue.java index 489414954..91e98fcd2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; public final class IntValue extends IntegerValue { @@ -46,11 +45,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) { return new IntValue(ValueData.of(name, (int) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntegerValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntegerValue.java index 7fb3774a7..21012ba30 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntegerValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/IntegerValue.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.Configurable; - import java.lang.reflect.Field; import java.util.Objects; +import mod.azure.azurelib.common.internal.common.config.Configurable; + public abstract class IntegerValue extends ConfigValue { protected Range range; @@ -48,8 +46,11 @@ private Range(long min, long max) { public static Range newBoundedRange(long min, long max) { if (min > max) { throw new IllegalArgumentException( - String.format("Invalid number range: Min value (%d) cannot be bigger than max value (%d)", min, - max) + String.format( + "Invalid number range: Min value (%d) cannot be bigger than max value (%d)", + min, + max + ) ); } return new Range(min, max); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongArrayValue.java index 919af962a..f74f001a0 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongArrayValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; public class LongArrayValue extends ConfigValue implements ArrayValue { @@ -36,8 +35,8 @@ protected void readFieldData(Field field) { this.fixedSize = field.getAnnotation(Configurable.FixedSize.class) != null; Configurable.Range intRange = field.getAnnotation(Configurable.Range.class); this.range = intRange != null - ? IntegerValue.Range.newBoundedRange(intRange.min(), intRange.max()) - : IntegerValue.Range.unboundedLong(); + ? IntegerValue.Range.newBoundedRange(intRange.min(), intRange.max()) + : IntegerValue.Range.unboundedLong(); } @Override @@ -46,9 +45,9 @@ protected long[] getCorrectedValue(long[] in) { long[] defaultArray = this.valueData.getDefaultValue(); if (in.length != defaultArray.length) { ConfigUtils.logArraySizeCorrectedMessage( - this.getId(), - Arrays.toString(in), - Arrays.toString(defaultArray) + this.getId(), + Arrays.toString(in), + Arrays.toString(defaultArray) ); in = defaultArray; } @@ -117,11 +116,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new LongArrayValue(ValueData.of(name, (long[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongValue.java index 989d6b869..696b54778 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/LongValue.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; + import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; public class LongValue extends IntegerValue { @@ -46,11 +45,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new LongValue(ValueData.of(name, (long) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ObjectValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ObjectValue.java index 5adf7cd65..e60894d91 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ObjectValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ObjectValue.java @@ -1,19 +1,18 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; -import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import net.minecraft.network.FriendlyByteBuf; import java.lang.reflect.Field; import java.util.Map; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; +import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; + public class ObjectValue extends ConfigValue>> { public ObjectValue(ValueData>> valueData) { @@ -40,11 +39,11 @@ public static final class Adapter extends TypeAdapter { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { Class type = value.getClass(); Map> map = serializer.serialize(type, value); @@ -52,8 +51,7 @@ public ConfigValue serialize( } @Override - public void encodeToBuffer(ConfigValue value, FriendlyByteBuf buffer) { - } + public void encodeToBuffer(ConfigValue value, FriendlyByteBuf buffer) {} @Override public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringArrayValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringArrayValue.java index 26031b908..f5f910f17 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringArrayValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringArrayValue.java @@ -1,11 +1,15 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.regex.Pattern; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; @@ -13,11 +17,6 @@ import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.regex.Pattern; public class StringArrayValue extends ConfigValue implements ArrayValue { @@ -47,20 +46,20 @@ protected void readFieldData(Field field) { this.pattern = Pattern.compile(value, stringPattern.flags()); } catch (IllegalArgumentException e) { AzureLib.LOGGER.error( - ConfigIO.MARKER, - "Invalid @StringPattern value for {} field - {}", - this.getId(), - e + ConfigIO.MARKER, + "Invalid @StringPattern value for {} field - {}", + this.getId(), + e ); } if (this.pattern != null && !this.pattern.matcher(this.defaultElementValue).matches()) { throw new IllegalArgumentException( - String.format( - "Invalid config default value '%s' for field '%s' - does not match required pattern \\%s\\", - this.defaultElementValue, - this.getId(), - this.pattern.toString() - ) + String.format( + "Invalid config default value '%s' for field '%s' - does not match required pattern \\%s\\", + this.defaultElementValue, + this.getId(), + this.pattern.toString() + ) ); } } @@ -136,11 +135,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new StringArrayValue(ValueData.of(name, (String[]) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringValue.java index cfc14b7eb..7c93dbb83 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/StringValue.java @@ -1,11 +1,14 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; +import net.minecraft.network.FriendlyByteBuf; + +import java.lang.reflect.Field; +import java.util.regex.Pattern; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.config.ConfigUtils; import mod.azure.azurelib.common.internal.common.config.Configurable; @@ -13,10 +16,6 @@ import mod.azure.azurelib.common.internal.common.config.exception.ConfigValueMissingException; import mod.azure.azurelib.common.internal.common.config.format.IConfigFormat; import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import net.minecraft.network.FriendlyByteBuf; - -import java.lang.reflect.Field; -import java.util.regex.Pattern; public class StringValue extends ConfigValue { @@ -38,10 +37,10 @@ protected void readFieldData(Field field) { this.pattern = Pattern.compile(value, stringPattern.flags()); } catch (IllegalArgumentException e) { AzureLib.LOGGER.error( - ConfigIO.MARKER, - "Invalid @StringPattern value for {} field - {}", - this.getId(), - e + ConfigIO.MARKER, + "Invalid @StringPattern value for {} field - {}", + this.getId(), + e ); } } @@ -53,12 +52,12 @@ protected String getCorrectedValue(String in) { String defaultValue = this.valueData.getDefaultValue(); if (!this.pattern.matcher(defaultValue).matches()) { throw new IllegalArgumentException( - String.format( - "Invalid config default value '%s' for field '%s' - does not match required pattern \\%s\\", - defaultValue, - this.getId(), - this.pattern.toString() - ) + String.format( + "Invalid config default value '%s' for field '%s' - does not match required pattern \\%s\\", + defaultValue, + this.getId(), + this.pattern.toString() + ) ); } ConfigUtils.logCorrectedMessage(this.getId(), in, defaultValue); @@ -99,11 +98,11 @@ public Object decodeFromBuffer(ConfigValue value, FriendlyByteBuf buffer) { @Override public ConfigValue serialize( - String name, - String[] comments, - Object value, - TypeSerializer serializer, - AdapterContext context + String name, + String[] comments, + Object value, + TypeSerializer serializer, + AdapterContext context ) throws IllegalAccessException { return new StringValue(ValueData.of(name, (String) value, context, comments)); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ValueData.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ValueData.java index dcedfb150..3181981d1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ValueData.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/config/value/ValueData.java @@ -1,16 +1,15 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.common.config.value; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; import org.jetbrains.annotations.Nullable; import java.util.Objects; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; + public final class ValueData implements IDescriptionProvider { private final String id; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java index ad8ed3f07..bfd6046c2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DataTickets.java @@ -1,17 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.constant; -import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; -import mod.azure.azurelib.core.object.DataTicket; import net.minecraft.core.Direction; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; @@ -23,60 +16,77 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import mod.azure.azurelib.common.internal.client.model.data.EntityModelData; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.core.object.DataTicket; + /** * Stores the default (builtin) {@link DataTicket DataTickets} used in AzureLib.
* Additionally handles registration of {@link SerializableDataTicket SerializableDataTickets} + * + * @deprecated */ +@Deprecated(forRemoval = true) public final class DataTickets { // Builtin tickets // These tickets are used by AzureLib by default, usually added in by the GeoRenderer for use in animations public static final DataTicket BLOCK_ENTITY = new DataTicket<>("block_entity", BlockEntity.class); + public static final DataTicket ITEMSTACK = new DataTicket<>("itemstack", ItemStack.class); + public static final DataTicket ENTITY = new DataTicket<>("entity", Entity.class); + public static final DataTicket EQUIPMENT_SLOT = new DataTicket<>( - "equipment_slot", - EquipmentSlot.class + "equipment_slot", + EquipmentSlot.class ); + public static final DataTicket ENTITY_MODEL_DATA = new DataTicket<>( - "entity_model_data", - EntityModelData.class + "entity_model_data", + EntityModelData.class ); + public static final DataTicket TICK = new DataTicket<>("tick", Double.class); + public static final DataTicket ITEM_RENDER_PERSPECTIVE = new DataTicket<>( - "item_render_perspective", - ItemDisplayContext.class + "item_render_perspective", + ItemDisplayContext.class ); + private static final Map> SERIALIZABLE_TICKETS = new ConcurrentHashMap<>(); + // Builtin serializable tickets // These are not used anywhere by default, but are provided as examples // and for ease of use public static final SerializableDataTicket ANIM_STATE = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofInt(AzureLib.modResource("anim_state")) + SerializableDataTicket.ofInt(AzureLib.modResource("anim_state")) ); public static final SerializableDataTicket ANIM = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofString(AzureLib.modResource("anim")) + SerializableDataTicket.ofString(AzureLib.modResource("anim")) ); public static final SerializableDataTicket USE_TICKS = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofInt(AzureLib.modResource("use_ticks")) + SerializableDataTicket.ofInt(AzureLib.modResource("use_ticks")) ); public static final SerializableDataTicket ACTIVE = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofBoolean(AzureLib.modResource("active")) + SerializableDataTicket.ofBoolean(AzureLib.modResource("active")) ); public static final SerializableDataTicket OPEN = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofBoolean(AzureLib.modResource("open")) + SerializableDataTicket.ofBoolean(AzureLib.modResource("open")) ); public static final SerializableDataTicket CLOSED = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofBoolean(AzureLib.modResource("closed")) + SerializableDataTicket.ofBoolean(AzureLib.modResource("closed")) ); public static final SerializableDataTicket DIRECTION = AzureLibUtil.addDataTicket( - SerializableDataTicket.ofEnum(AzureLib.modResource("direction"), Direction.class) + SerializableDataTicket.ofEnum(AzureLib.modResource("direction"), Direction.class) ); private DataTickets() { @@ -100,9 +110,9 @@ public static SerializableDataTicket registerSerializable(SerializableDat if (existingTicket != null) AzureLib.LOGGER.error( - "Duplicate SerializableDataTicket registered! This will cause issues. Existing: {}, New: {}", - existingTicket.id(), - ticket.id() + "Duplicate SerializableDataTicket registered! This will cause issues. Existing: {}, New: {}", + existingTicket.id(), + ticket.id() ); return ticket; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java index 1e318bf3c..8e71ead4b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/constant/DefaultAnimations.java @@ -1,12 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.constant; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; + +import java.util.function.BiPredicate; +import java.util.function.Function; + import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; import mod.azure.azurelib.common.api.common.animatable.GeoEntity; import mod.azure.azurelib.common.api.common.animatable.GeoItem; @@ -16,18 +20,15 @@ import mod.azure.azurelib.core.animation.AnimationState; import mod.azure.azurelib.core.animation.RawAnimation; import mod.azure.azurelib.core.object.PlayState; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; - -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.Function; /** * Optionally usable class that holds constants for recommended animation paths.
* Using these won't affect much, but it may help keep some consistency in animation namings.
* Additionally, it encourages use of cached {@link RawAnimation RawAnimations}, to reduce overheads. + * + * @deprecated */ +@Deprecated(forRemoval = true) public record DefaultAnimations() { public static final RawAnimation ITEM_ON_USE = RawAnimation.begin().thenPlay("item.use"); @@ -101,10 +102,10 @@ public record DefaultAnimations() { * */ public static AnimationController basicPredicateController( - T animatable, - RawAnimation optionA, - RawAnimation optionB, - BiPredicate> predicate + T animatable, + RawAnimation optionA, + RawAnimation optionB, + BiPredicate> predicate ) { return new AnimationController<>(animatable, "Generic", 10, state -> { var result = predicate.test(animatable, state); @@ -148,9 +149,9 @@ public static AnimationController genericIdleContro * animation will no longer play */ public static AnimationController getSpawnController( - T animatable, - Function, Object> objectSupplier, - int ticks + T animatable, + Function, Object> objectSupplier, + int ticks ) { return new AnimationController<>(animatable, "Spawn", 0, state -> { if (animatable.getTick(objectSupplier.apply(state)) <= ticks) @@ -183,8 +184,8 @@ public static AnimationController genericWalkContro * @return A new {@link AnimationController} instance to use */ public static AnimationController genericAttackAnimation( - T animatable, - RawAnimation attackAnimation + T animatable, + RawAnimation attackAnimation ) { return new AnimationController<>(animatable, "Attack", 5, state -> { if (animatable.swinging) @@ -202,10 +203,10 @@ public static AnimationController ge */ public static AnimationController genericWalkIdleController(T animatable) { return new AnimationController<>( - animatable, - "Walk/Idle", - 0, - state -> state.setAndContinue(state.isMoving() ? WALK : IDLE) + animatable, + "Walk/Idle", + 0, + state -> state.setAndContinue(state.isMoving() ? WALK : IDLE) ); } @@ -228,10 +229,10 @@ public static AnimationController genericSwimContro */ public static AnimationController genericSwimIdleController(T animatable) { return new AnimationController<>( - animatable, - "Swim/Idle", - 0, - state -> state.setAndContinue(state.isMoving() ? SWIM : IDLE) + animatable, + "Swim/Idle", + 0, + state -> state.setAndContinue(state.isMoving() ? SWIM : IDLE) ); } @@ -249,10 +250,10 @@ public static AnimationController genericFlyControl */ public static AnimationController genericFlyIdleController(T animatable) { return new AnimationController<>( - animatable, - "Fly/Idle", - 0, - state -> state.setAndContinue(state.isMoving() ? FLY : IDLE) + animatable, + "Fly/Idle", + 0, + state -> state.setAndContinue(state.isMoving() ? FLY : IDLE) ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java index 7d4b63346..ed9436c52 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/FileLoader.java @@ -1,20 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading; import com.google.gson.JsonObject; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.AzureLibException; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; -import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; -import mod.azure.azurelib.core.animation.Animation; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.util.GsonHelper; @@ -23,6 +14,16 @@ import java.io.InputStream; import java.nio.charset.Charset; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.AzureLibException; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; +import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; +import mod.azure.azurelib.core.animation.Animation; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimation; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; + /** * Extracts raw information from given files, and other similar functions */ @@ -37,11 +38,22 @@ private FileLoader() { * * @param location The resource path of the animations file * @param manager The Minecraft {@code ResourceManager} responsible for maintaining in-memory resource access + * @deprecated */ public static BakedAnimations loadAnimationsFile(ResourceLocation location, ResourceManager manager) { return JsonUtil.GEO_GSON.fromJson(loadFile(location, manager), BakedAnimations.class); } + /** + * Load up and deserialize an animation json file to its respective {@link AzBakedAnimation} components + * + * @param location The resource path of the animations file + * @param manager The Minecraft {@code ResourceManager} responsible for maintaining in-memory resource access + */ + public static AzBakedAnimations loadAzAnimationsFile(ResourceLocation location, ResourceManager manager) { + return JsonUtil.GEO_GSON.fromJson(loadFile(location, manager), AzBakedAnimations.class); + } + /** * Load up and deserialize a geo model json file to its respective {@link BakedGeoModel} format * diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/FormatVersion.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/FormatVersion.java index 243f36a24..deb137f94 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/FormatVersion.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/FormatVersion.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java index e305f3a22..f6526d4e2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Bone.java @@ -1,90 +1,88 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializer; -import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; import java.util.Map; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for cube information, only used in deserialization at startup */ public record Bone( - double[] bindPoseRotation, - Cube[] cubes, - @Nullable Boolean debug, - @Nullable Double inflate, - @Nullable Map locators, - @Nullable Boolean mirror, - @Nullable String name, - @Nullable Boolean neverRender, - @Nullable String parent, - double[] pivot, - @Nullable PolyMesh polyMesh, - @Nullable Long renderGroupId, - @Nullable Boolean reset, - double[] rotation, - @Nullable TextureMesh[] textureMeshes + double[] bindPoseRotation, + Cube[] cubes, + @Nullable Boolean debug, + @Nullable Double inflate, + @Nullable Map locators, + @Nullable Boolean mirror, + @Nullable String name, + @Nullable Boolean neverRender, + @Nullable String parent, + double[] pivot, + @Nullable PolyMesh polyMesh, + @Nullable Long renderGroupId, + @Nullable Boolean reset, + double[] rotation, + @Nullable TextureMesh[] textureMeshes ) { public static JsonDeserializer deserializer() throws JsonParseException { return (json, type, context) -> { - JsonObject obj = json.getAsJsonObject(); - double[] bindPoseRotation = JsonUtil.jsonArrayToDoubleArray( - GsonHelper.getAsJsonArray(obj, "bind_pose_rotation", null) + var obj = json.getAsJsonObject(); + var bindPoseRotation = JsonUtil.jsonArrayToDoubleArray( + GsonHelper.getAsJsonArray(obj, "bind_pose_rotation", null) ); - Cube[] cubes = JsonUtil.jsonArrayToObjectArray( - GsonHelper.getAsJsonArray(obj, "cubes", new JsonArray(0)), - context, - Cube.class + var cubes = JsonUtil.jsonArrayToObjectArray( + GsonHelper.getAsJsonArray(obj, "cubes", new JsonArray(0)), + context, + Cube.class ); - Boolean debug = JsonUtil.getOptionalBoolean(obj, "debug"); - Double inflate = JsonUtil.getOptionalDouble(obj, "inflate"); - Map locators = obj.has("locators") - ? JsonUtil.jsonObjToMap(GsonHelper.getAsJsonObject(obj, "locators"), context, LocatorValue.class) - : null; - Boolean mirror = JsonUtil.getOptionalBoolean(obj, "mirror"); - String name = GsonHelper.getAsString(obj, "name", null); - Boolean neverRender = JsonUtil.getOptionalBoolean(obj, "neverRender"); - String parent = GsonHelper.getAsString(obj, "parent", null); - double[] pivot = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "pivot", new JsonArray(0))); - PolyMesh polyMesh = GsonHelper.getAsObject(obj, "poly_mesh", null, context, PolyMesh.class); - Long renderGroupId = JsonUtil.getOptionalLong(obj, "render_group_id"); - Boolean reset = JsonUtil.getOptionalBoolean(obj, "reset"); - double[] rotation = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "rotation", null)); - TextureMesh[] textureMeshes = JsonUtil.jsonArrayToObjectArray( - GsonHelper.getAsJsonArray(obj, "texture_meshes", new JsonArray(0)), - context, - TextureMesh.class + var debug = JsonUtil.getOptionalBoolean(obj, "debug"); + var inflate = JsonUtil.getOptionalDouble(obj, "inflate"); + var locators = obj.has("locators") + ? JsonUtil.jsonObjToMap(GsonHelper.getAsJsonObject(obj, "locators"), context, LocatorValue.class) + : null; + var mirror = JsonUtil.getOptionalBoolean(obj, "mirror"); + var name = GsonHelper.getAsString(obj, "name", null); + var neverRender = JsonUtil.getOptionalBoolean(obj, "neverRender"); + var parent = GsonHelper.getAsString(obj, "parent", null); + var pivot = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "pivot", new JsonArray(0))); + var polyMesh = GsonHelper.getAsObject(obj, "poly_mesh", null, context, PolyMesh.class); + var renderGroupId = JsonUtil.getOptionalLong(obj, "render_group_id"); + var reset = JsonUtil.getOptionalBoolean(obj, "reset"); + var rotation = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "rotation", null)); + var textureMeshes = JsonUtil.jsonArrayToObjectArray( + GsonHelper.getAsJsonArray(obj, "texture_meshes", new JsonArray(0)), + context, + TextureMesh.class ); return new Bone( - bindPoseRotation, - cubes, - debug, - inflate, - locators, - mirror, - name, - neverRender, - parent, - pivot, - polyMesh, - renderGroupId, - reset, - rotation, - textureMeshes + bindPoseRotation, + cubes, + debug, + inflate, + locators, + mirror, + name, + neverRender, + parent, + pivot, + polyMesh, + renderGroupId, + reset, + rotation, + textureMeshes ); }; } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Cube.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Cube.java index 7ad2f8f12..25f9cc484 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Cube.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Cube.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,21 +8,22 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for cube information, only used in deserialization at startup */ public record Cube( - @Nullable Double inflate, - @Nullable Boolean mirror, - double[] origin, - double[] pivot, - double[] rotation, - double[] size, - UVUnion uv + @Nullable Double inflate, + @Nullable Boolean mirror, + double[] origin, + double[] pivot, + double[] rotation, + double[] size, + UVUnion uv ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java index dc3ab49bd..370c4f940 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/FaceUV.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,17 +8,21 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; +import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for face UV information, only used in deserialization at startup */ public record FaceUV( - @Nullable String materialInstance, - double[] uv, - double[] uvSize + @Nullable String materialInstance, + double[] uv, + double[] uvSize, + Rotation uvRotation ) { public static JsonDeserializer deserializer() throws JsonParseException { @@ -29,8 +31,36 @@ public static JsonDeserializer deserializer() throws JsonParseException String materialInstance = GsonHelper.getAsString(obj, "material_instance", null); double[] uv = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "uv", null)); double[] uvSize = JsonUtil.jsonArrayToDoubleArray(GsonHelper.getAsJsonArray(obj, "uv_size", null)); + Rotation uvRotation = Rotation.fromValue(GsonHelper.getAsInt(obj, "uv_rotation", 0)); - return new FaceUV(materialInstance, uv, uvSize); + return new FaceUV(materialInstance, uv, uvSize, uvRotation); }; } + + public enum Rotation { + + NONE, + CLOCKWISE_90, + CLOCKWISE_180, + CLOCKWISE_270; + + public static Rotation fromValue(int value) throws JsonParseException { + try { + return Rotation.values()[(value % 360) / 90]; + } catch (Exception e) { + AzureLib.LOGGER.error("Invalid Face UV rotation: " + value); + + return fromValue(Mth.floor(Math.abs(value) / 90f) * 90); + } + } + + public float[] rotateUvs(float u, float v, float uWidth, float vHeight) { + return switch (this) { + case NONE -> new float[] { u, v, uWidth, v, uWidth, vHeight, u, vHeight }; + case CLOCKWISE_90 -> new float[] { uWidth, v, uWidth, vHeight, u, vHeight, u, v }; + case CLOCKWISE_180 -> new float[] { uWidth, vHeight, u, vHeight, u, v, uWidth, v }; + case CLOCKWISE_270 -> new float[] { u, vHeight, u, v, uWidth, v, uWidth, vHeight }; + }; + } + } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorClass.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorClass.java index 1f5dd9d7a..cc2ed2a60 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorClass.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorClass.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,17 +8,18 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for locator class information, only used in deserialization at startup */ public record LocatorClass( - @Nullable Boolean ignoreInheritedScale, - double[] offset, - double[] rotation + @Nullable Boolean ignoreInheritedScale, + double[] offset, + double[] rotation ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorValue.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorValue.java index 49a1e9563..c157b72b9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorValue.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/LocatorValue.java @@ -1,23 +1,22 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; import com.google.gson.JsonDeserializer; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for locator value information, only used in deserialization at startup */ public record LocatorValue( - @Nullable LocatorClass locatorClass, - double[] values + @Nullable LocatorClass locatorClass, + double[] values ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/MinecraftGeometry.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/MinecraftGeometry.java index 5ee7cc69e..27f01af2a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/MinecraftGeometry.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/MinecraftGeometry.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -11,34 +9,35 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for generic geometry information, only used in deserialization at startup */ public record MinecraftGeometry( - Bone[] bones, - @Nullable String cape, - @Nullable ModelProperties modelProperties + Bone[] bones, + @Nullable String cape, + @Nullable ModelProperties modelProperties ) { public static JsonDeserializer deserializer() throws JsonParseException { return (json, type, context) -> { JsonObject obj = json.getAsJsonObject(); Bone[] bones = JsonUtil.jsonArrayToObjectArray( - GsonHelper.getAsJsonArray(obj, "bones", new JsonArray(0)), - context, - Bone.class + GsonHelper.getAsJsonArray(obj, "bones", new JsonArray(0)), + context, + Bone.class ); String cape = GsonHelper.getAsString(obj, "cape", null); ModelProperties modelProperties = GsonHelper.getAsObject( - obj, - "description", - null, - context, - ModelProperties.class + obj, + "description", + null, + context, + ModelProperties.class ); return new MinecraftGeometry(bones, cape, modelProperties); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Model.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Model.java index 4528960c5..d8f870f70 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Model.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/Model.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -11,17 +9,18 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.loading.json.FormatVersion; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.loading.json.FormatVersion; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for model information, only used in deserialization at startup */ public record Model( - @Nullable FormatVersion formatVersion, - MinecraftGeometry[] minecraftGeometry + @Nullable FormatVersion formatVersion, + MinecraftGeometry[] minecraftGeometry ) { public static JsonDeserializer deserializer() throws JsonParseException { @@ -29,9 +28,9 @@ public static JsonDeserializer deserializer() throws JsonParseException { JsonObject obj = json.getAsJsonObject(); FormatVersion formatVersion = context.deserialize(obj.get("format_version"), FormatVersion.class); MinecraftGeometry[] minecraftGeometry = JsonUtil.jsonArrayToObjectArray( - GsonHelper.getAsJsonArray(obj, "minecraft:geometry", new JsonArray(0)), - context, - MinecraftGeometry.class + GsonHelper.getAsJsonArray(obj, "minecraft:geometry", new JsonArray(0)), + context, + MinecraftGeometry.class ); return new Model(formatVersion, minecraftGeometry); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/ModelProperties.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/ModelProperties.java index a70691b53..c9fe245cb 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/ModelProperties.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/ModelProperties.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,31 +8,32 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for model property information, only used in deserialization at startup */ public record ModelProperties( - @Nullable Boolean animationArmsDown, - @Nullable Boolean animationArmsOutFront, - @Nullable Boolean animationDontShowArmor, - @Nullable Boolean animationInvertedCrouch, - @Nullable Boolean animationNoHeadBob, - @Nullable Boolean animationSingleArmAnimation, - @Nullable Boolean animationSingleLegAnimation, - @Nullable Boolean animationStationaryLegs, - @Nullable Boolean animationStatueOfLibertyArms, - @Nullable Boolean animationUpsideDown, - @Nullable String identifier, - @Nullable Boolean preserveModelPose, - double textureHeight, - double textureWidth, - @Nullable Double visibleBoundsHeight, - double[] visibleBoundsOffset, - @Nullable Double visibleBoundsWidth + @Nullable Boolean animationArmsDown, + @Nullable Boolean animationArmsOutFront, + @Nullable Boolean animationDontShowArmor, + @Nullable Boolean animationInvertedCrouch, + @Nullable Boolean animationNoHeadBob, + @Nullable Boolean animationSingleArmAnimation, + @Nullable Boolean animationSingleLegAnimation, + @Nullable Boolean animationStationaryLegs, + @Nullable Boolean animationStatueOfLibertyArms, + @Nullable Boolean animationUpsideDown, + @Nullable String identifier, + @Nullable Boolean preserveModelPose, + double textureHeight, + double textureWidth, + @Nullable Double visibleBoundsHeight, + double[] visibleBoundsOffset, + @Nullable Double visibleBoundsWidth ) { public static JsonDeserializer deserializer() throws JsonParseException { @@ -56,28 +55,28 @@ public static JsonDeserializer deserializer() throws JsonParseE double textureWidth = GsonHelper.getAsDouble(obj, "texture_width"); Double visibleBoundsHeight = JsonUtil.getOptionalDouble(obj, "visible_bounds_height"); double[] visibleBoundsOffset = JsonUtil.jsonArrayToDoubleArray( - GsonHelper.getAsJsonArray(obj, "visible_bounds_offset", null) + GsonHelper.getAsJsonArray(obj, "visible_bounds_offset", null) ); Double visibleBoundsWidth = JsonUtil.getOptionalDouble(obj, "visible_bounds_width"); return new ModelProperties( - animationArmsDown, - animationArmsOutFront, - animationDontShowArmor, - animationInvertedCrouch, - animationNoHeadBob, - animationSingleArmAnimation, - animationSingleLegAnimation, - animationStationaryLegs, - animationStatueOfLibertyArms, - animationUpsideDown, - identifier, - preserveModelPose, - textureHeight, - textureWidth, - visibleBoundsHeight, - visibleBoundsOffset, - visibleBoundsWidth + animationArmsDown, + animationArmsOutFront, + animationDontShowArmor, + animationInvertedCrouch, + animationNoHeadBob, + animationSingleArmAnimation, + animationSingleLegAnimation, + animationStationaryLegs, + animationStatueOfLibertyArms, + animationUpsideDown, + identifier, + preserveModelPose, + textureHeight, + textureWidth, + visibleBoundsHeight, + visibleBoundsOffset, + visibleBoundsWidth ); }; } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolyMesh.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolyMesh.java index ee62603e2..59d7adcf4 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolyMesh.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolyMesh.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,19 +8,20 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for poly mesh information, only used in deserialization at startup */ public record PolyMesh( - @Nullable Boolean normalizedUVs, - double[] normals, - @Nullable PolysUnion polysUnion, - double[] positions, - double[] uvs + @Nullable Boolean normalizedUVs, + double[] normals, + @Nullable PolysUnion polysUnion, + double[] positions, + double[] uvs ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolysUnion.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolysUnion.java index e93250519..a1446027d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolysUnion.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/PolysUnion.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -11,15 +9,16 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonParseException; import com.google.gson.annotations.SerializedName; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for poly union information, only used in deserialization at startup */ public record PolysUnion( - double[][][] union, - @Nullable Type type + double[][][] union, + @Nullable Type type ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/TextureMesh.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/TextureMesh.java index b6c3fc8f1..2b3d783f5 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/TextureMesh.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/TextureMesh.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -10,19 +8,20 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for texture mesh information, only used in deserialization at startup */ public record TextureMesh( - double[] localPivot, - double[] position, - double[] rotation, - double[] scale, - @Nullable String texture + double[] localPivot, + double[] position, + double[] rotation, + double[] scale, + @Nullable String texture ) { public static JsonDeserializer deserializer() throws JsonParseException { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVFaces.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVFaces.java index c01cd4764..081325cfb 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVFaces.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVFaces.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; @@ -17,12 +15,12 @@ * Container class for UV face information, only used in deserialization at startup */ public record UVFaces( - @Nullable FaceUV north, - @Nullable FaceUV south, - @Nullable FaceUV east, - @Nullable FaceUV west, - @Nullable FaceUV up, - @Nullable FaceUV down + @Nullable FaceUV north, + @Nullable FaceUV south, + @Nullable FaceUV east, + @Nullable FaceUV west, + @Nullable FaceUV up, + @Nullable FaceUV down ) { public static JsonDeserializer deserializer() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVUnion.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVUnion.java index 9f6331edb..9b6545be1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVUnion.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/raw/UVUnion.java @@ -1,24 +1,23 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.raw; import com.google.gson.JsonDeserializer; import com.google.gson.JsonParseException; -import mod.azure.azurelib.common.internal.common.util.JsonUtil; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; + /** * Container class for UV information, only used in deserialization at startup */ public record UVUnion( - double[] boxUVCoords, - @Nullable UVFaces faceUV, - boolean isBoxUV + double[] boxUVCoords, + @Nullable UVFaces faceUV, + boolean isBoxUV ) { public static JsonDeserializer deserializer() throws JsonParseException { @@ -29,7 +28,7 @@ public static JsonDeserializer deserializer() throws JsonParseException return new UVUnion(JsonUtil.jsonArrayToDoubleArray(json.getAsJsonArray()), null, true); } else { throw new JsonParseException( - "Invalid format provided for UVUnion, must be either double array or UVFaces collection" + "Invalid format provided for UVUnion, must be either double array or UVFaces collection" ); } }; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/BakedAnimationsAdapter.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/BakedAnimationsAdapter.java index bb34bdb0e..1a192181d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/BakedAnimationsAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/BakedAnimationsAdapter.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.typeadapter; @@ -11,6 +9,14 @@ import com.mojang.datafixers.util.Pair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import org.apache.commons.lang3.math.NumberUtils; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + import mod.azure.azurelib.common.internal.common.AzureLib; import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; import mod.azure.azurelib.common.internal.common.util.JsonUtil; @@ -24,13 +30,6 @@ import mod.azure.azurelib.core.molang.MolangException; import mod.azure.azurelib.core.molang.MolangParser; import mod.azure.azurelib.core.molang.expressions.MolangValue; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.GsonHelper; -import org.apache.commons.lang3.math.NumberUtils; - -import java.lang.reflect.Type; -import java.util.List; -import java.util.Map; /** * {@link com.google.gson.Gson} {@link JsonDeserializer} for {@link BakedAnimations}.
@@ -79,11 +78,14 @@ private static Pair getTripletObjBedrock(String timestamp, if (keyframe.has("pre")) { JsonElement pre = keyframe.get("pre"); - keyframeValues = pre.isJsonArray() ? pre.getAsJsonArray() : GsonHelper.getAsJsonArray(pre.getAsJsonObject(), "vector"); - } - else if (keyframe.has("post")) { + keyframeValues = pre.isJsonArray() + ? pre.getAsJsonArray() + : GsonHelper.getAsJsonArray(pre.getAsJsonObject(), "vector"); + } else if (keyframe.has("post")) { JsonElement post = keyframe.get("post"); - keyframeValues = post.isJsonArray() ? post.getAsJsonArray() : GsonHelper.getAsJsonArray(post.getAsJsonObject(), "vector"); + keyframeValues = post.isJsonArray() + ? post.getAsJsonArray() + : GsonHelper.getAsJsonArray(post.getAsJsonObject(), "vector"); } if (keyframeValues != null) @@ -106,9 +108,9 @@ private static double calculateAnimationLength(BoneAnimation[] boneAnimations) { @Override public BakedAnimations deserialize( - JsonElement json, - Type type, - JsonDeserializationContext context + JsonElement json, + Type type, + JsonDeserializationContext context ) throws JsonParseException { JsonObject jsonObj = json.getAsJsonObject(); @@ -124,10 +126,10 @@ public BakedAnimations deserialize( String ani = animName.getAsString(); if (includes.containsKey(ani)) { AzureLib.LOGGER.warn( - "Animation {} is already included! File already including: {} File trying to include from again: {}", - ani, - includes.get(ani), - fileId + "Animation {} is already included! File already including: {} File trying to include from again: {}", + ani, + includes.get(ani), + fileId ); } else { includes.put(ani, fileId); @@ -141,8 +143,8 @@ public BakedAnimations deserialize( for (Map.Entry entry : animationJsonList.entrySet()) { try { animations.put( - entry.getKey(), - bakeAnimation(entry.getKey(), entry.getValue().getAsJsonObject(), context) + entry.getKey(), + bakeAnimation(entry.getKey(), entry.getValue().getAsJsonObject(), context) ); } catch (MolangException ex) { AzureLib.LOGGER.error("Unable to parse animation: {}", entry.getKey()); @@ -154,16 +156,16 @@ public BakedAnimations deserialize( } private Animation bakeAnimation( - String name, - JsonObject animationObj, - JsonDeserializationContext context + String name, + JsonObject animationObj, + JsonDeserializationContext context ) throws MolangException { double length = animationObj.has("animation_length") - ? GsonHelper.getAsDouble(animationObj, "animation_length") * 20d - : -1; + ? GsonHelper.getAsDouble(animationObj, "animation_length") * 20d + : -1; Animation.LoopType loopType = Animation.LoopType.fromJson(animationObj.get("loop")); BoneAnimation[] boneAnimations = bakeBoneAnimations( - GsonHelper.getAsJsonObject(animationObj, "bones", new JsonObject()) + GsonHelper.getAsJsonObject(animationObj, "bones", new JsonObject()) ); Animation.Keyframes keyframes = context.deserialize(animationObj, Animation.Keyframes.class); @@ -180,16 +182,16 @@ private BoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangExc for (Map.Entry entry : bonesObj.entrySet()) { JsonObject entryObj = entry.getValue().getAsJsonObject(); KeyframeStack> scaleFrames = buildKeyframeStack( - getTripletObj(entryObj.get("scale")), - false + getTripletObj(entryObj.get("scale")), + false ); KeyframeStack> positionFrames = buildKeyframeStack( - getTripletObj(entryObj.get("position")), - false + getTripletObj(entryObj.get("position")), + false ); KeyframeStack> rotationFrames = buildKeyframeStack( - getTripletObj(entryObj.get("rotation")), - true + getTripletObj(entryObj.get("rotation")), + true ); animations[index] = new BoneAnimation(entry.getKey(), rotationFrames, positionFrames, scaleFrames); @@ -200,8 +202,8 @@ private BoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangExc } private KeyframeStack> buildKeyframeStack( - List> entries, - boolean isForRotation + List> entries, + boolean isForRotation ) throws MolangException { if (entries.isEmpty()) return new KeyframeStack<>(); @@ -227,40 +229,40 @@ private KeyframeStack> buildKeyframeStack( double timeDelta = curTime - prevTime; JsonArray keyFrameVector = element instanceof JsonArray array - ? array - : GsonHelper.getAsJsonArray(element.getAsJsonObject(), "vector"); + ? array + : GsonHelper.getAsJsonArray(element.getAsJsonObject(), "vector"); MolangValue rawXValue = MolangParser.parseJson(keyFrameVector.get(0)); MolangValue rawYValue = MolangParser.parseJson(keyFrameVector.get(1)); MolangValue rawZValue = MolangParser.parseJson(keyFrameVector.get(2)); IValue xValue = isForRotation && rawXValue.isConstant() - ? new Constant(Math.toRadians(-rawXValue.get())) - : rawXValue; + ? new Constant(Math.toRadians(-rawXValue.get())) + : rawXValue; IValue yValue = isForRotation && rawYValue.isConstant() - ? new Constant(Math.toRadians(-rawYValue.get())) - : rawYValue; + ? new Constant(Math.toRadians(-rawYValue.get())) + : rawYValue; IValue zValue = isForRotation && rawZValue.isConstant() - ? new Constant(Math.toRadians(rawZValue.get())) - : rawZValue; + ? new Constant(Math.toRadians(rawZValue.get())) + : rawZValue; JsonObject entryObj = element instanceof JsonObject obj ? obj : null; EasingType easingType = entryObj != null && entryObj.has("easing") - ? EasingType.fromJson(entryObj.get("easing")) - : EasingType.LINEAR; + ? EasingType.fromJson(entryObj.get("easing")) + : EasingType.LINEAR; List easingArgs = entryObj != null && entryObj.has("easingArgs") - ? JsonUtil.jsonArrayToList( + ? JsonUtil.jsonArrayToList( GsonHelper.getAsJsonArray(entryObj, "easingArgs"), ele -> new Constant(ele.getAsDouble()) - ) - : new ObjectArrayList<>(); + ) + : new ObjectArrayList<>(); xFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) ); yFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) ); zFrames.add( - new Keyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) + new Keyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) ); xPrev = xValue; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/KeyFramesAdapter.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/KeyFramesAdapter.java index 00e22b14d..571859db1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/KeyFramesAdapter.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/json/typeadapter/KeyFramesAdapter.java @@ -1,23 +1,22 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.json.typeadapter; import com.google.gson.*; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.util.GsonHelper; + +import java.lang.reflect.Type; +import java.util.Map; + import mod.azure.azurelib.common.internal.common.util.JsonUtil; import mod.azure.azurelib.core.animation.Animation; import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; -import net.minecraft.util.GsonHelper; - -import java.lang.reflect.Type; -import java.util.Map; /** * {@link Gson} {@link JsonDeserializer} for {@link Animation.Keyframes}.
@@ -32,8 +31,8 @@ private static SoundKeyframeData[] buildSoundFrameData(JsonObject rootObj) { for (Map.Entry entry : soundsObj.entrySet()) { sounds[index] = new SoundKeyframeData( - Double.parseDouble(entry.getKey()) * 20d, - GsonHelper.getAsString(entry.getValue().getAsJsonObject(), "effect") + Double.parseDouble(entry.getKey()) * 20d, + GsonHelper.getAsString(entry.getValue().getAsJsonObject(), "effect") ); index++; } @@ -53,10 +52,10 @@ private static ParticleKeyframeData[] buildParticleFrameData(JsonObject rootObj) String script = GsonHelper.getAsString(obj, "pre_effect_script", ""); particles[index] = new ParticleKeyframeData( - Double.parseDouble(entry.getKey()) * 20d, - effect, - locator, - script + Double.parseDouble(entry.getKey()) * 20d, + effect, + locator, + script ); index++; } @@ -67,7 +66,7 @@ private static ParticleKeyframeData[] buildParticleFrameData(JsonObject rootObj) private static CustomInstructionKeyframeData[] buildCustomFrameData(JsonObject rootObj) { JsonObject customInstructionsObj = GsonHelper.getAsJsonObject(rootObj, "timeline", new JsonObject()); CustomInstructionKeyframeData[] customInstructions = new CustomInstructionKeyframeData[customInstructionsObj - .size()]; + .size()]; int index = 0; for (Map.Entry entry : customInstructionsObj.entrySet()) { @@ -80,8 +79,8 @@ private static CustomInstructionKeyframeData[] buildCustomFrameData(JsonObject r } customInstructions[index] = new CustomInstructionKeyframeData( - Double.parseDouble(entry.getKey()) * 20d, - instructions + Double.parseDouble(entry.getKey()) * 20d, + instructions ); index++; } @@ -91,9 +90,9 @@ private static CustomInstructionKeyframeData[] buildCustomFrameData(JsonObject r @Override public Animation.Keyframes deserialize( - JsonElement json, - Type type, - JsonDeserializationContext context + JsonElement json, + Type type, + JsonDeserializationContext context ) throws JsonParseException { JsonObject obj = json.getAsJsonObject(); SoundKeyframeData[] sounds = buildSoundFrameData(obj); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedAnimations.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedAnimations.java index c42b2c95c..a6834e440 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedAnimations.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedAnimations.java @@ -1,26 +1,25 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.object; -import mod.azure.azurelib.core.animation.Animation; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; import java.util.Map; +import mod.azure.azurelib.core.animation.Animation; + /** * Container object that holds a deserialized map of {@link Animation Animations}.
* Kept as a unique object so that it can be registered as a {@link com.google.gson.JsonDeserializer deserializer} for * {@link com.google.gson.Gson Gson} */ public record BakedAnimations( - Map animations, - Map includes + Map animations, + Map includes ) { /** diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java index 313ee8afb..59db763ee 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BakedModelFactory.java @@ -1,18 +1,12 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.object; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.cache.object.*; -import mod.azure.azurelib.common.internal.common.loading.json.raw.*; -import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; import net.minecraft.core.Direction; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; @@ -20,9 +14,16 @@ import java.util.List; import java.util.Map; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.*; +import mod.azure.azurelib.common.internal.common.loading.json.raw.*; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; + /** * Base interface for a factory of {@link BakedGeoModel} objects. Handled by default by AzureLib, but custom * implementations may be added by other mods for special needs + * + * @deprecated */ public interface BakedModelFactory { @@ -75,12 +76,12 @@ static void register(String namespace, BakedModelFactory factory) { * Vertices have already been mirrored here if {@code mirror} is true */ default GeoQuad[] buildQuads( - UVUnion uvUnion, - VertexSet vertices, - Cube cube, - float textureWidth, - float textureHeight, - boolean mirror + UVUnion uvUnion, + VertexSet vertices, + Cube cube, + float textureWidth, + float textureHeight, + boolean mirror ) { GeoQuad[] quads = new GeoQuad[6]; @@ -98,13 +99,13 @@ default GeoQuad[] buildQuads( * Build an individual quad */ default GeoQuad buildQuad( - VertexSet vertices, - Cube cube, - UVUnion uvUnion, - float textureWidth, - float textureHeight, - boolean mirror, - Direction direction + VertexSet vertices, + Cube cube, + UVUnion uvUnion, + float textureWidth, + float textureHeight, + boolean mirror, + Direction direction ) { if (!uvUnion.isBoxUV()) { FaceUV faceUV = uvUnion.faceUV().fromDirection(direction); @@ -113,13 +114,14 @@ default GeoQuad buildQuad( return null; return GeoQuad.build( - vertices.verticesForQuad(direction, false, mirror || cube.mirror() == Boolean.TRUE), - faceUV.uv(), - faceUV.uvSize(), - textureWidth, - textureHeight, - mirror, - direction + vertices.verticesForQuad(direction, false, mirror || cube.mirror() == Boolean.TRUE), + faceUV.uv(), + faceUV.uvSize(), + faceUV.uvRotation(), + textureWidth, + textureHeight, + mirror, + direction ); } @@ -127,40 +129,41 @@ default GeoQuad buildQuad( double[] uvSize = cube.size(); Vec3 uvSizeVec = new Vec3(Math.floor(uvSize[0]), Math.floor(uvSize[1]), Math.floor(uvSize[2])); double[][] uvData = switch (direction) { - case WEST -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.z, uvSizeVec.y} + case WEST -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.z, uvSizeVec.y } }; - case EAST -> new double[][]{ - new double[]{uv[0], uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.z, uvSizeVec.y} + case EAST -> new double[][] { + new double[] { uv[0], uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.z, uvSizeVec.y } }; - case NORTH -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.x, uvSizeVec.y} + case NORTH -> new double[][] { + new double[] { uv[0] + uvSizeVec.z, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, uvSizeVec.y } }; - case SOUTH -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x + uvSizeVec.z, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.x, uvSizeVec.y} + case SOUTH -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x + uvSizeVec.z, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, uvSizeVec.y } }; - case UP -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z, uv[1]}, - new double[]{uvSizeVec.x, uvSizeVec.z} + case UP -> new double[][] { + new double[] { uv[0] + uvSizeVec.z, uv[1] }, + new double[] { uvSizeVec.x, uvSizeVec.z } }; - case DOWN -> new double[][]{ - new double[]{uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z}, - new double[]{uvSizeVec.x, -uvSizeVec.z} + case DOWN -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, -uvSizeVec.z } }; }; return GeoQuad.build( - vertices.verticesForQuad(direction, true, mirror || cube.mirror() == Boolean.TRUE), - uvData[0], - uvData[1], - textureWidth, - textureHeight, - mirror, - direction + vertices.verticesForQuad(direction, true, mirror || cube.mirror() == Boolean.TRUE), + uvData[0], + uvData[1], + FaceUV.Rotation.NONE, + textureWidth, + textureHeight, + mirror, + direction ); } @@ -181,20 +184,20 @@ public BakedGeoModel constructGeoModel(GeometryTree geometryTree) { public GeoBone constructBone(BoneStructure boneStructure, ModelProperties properties, GeoBone parent) { Bone bone = boneStructure.self(); GeoBone newBone = new GeoBone( - parent, - bone.name(), - bone.mirror(), - bone.inflate(), - bone.neverRender(), - bone.reset() + parent, + bone.name(), + bone.mirror(), + bone.inflate(), + bone.neverRender(), + bone.reset() ); Vec3 rotation = RenderUtils.arrayToVec(bone.rotation()); Vec3 pivot = RenderUtils.arrayToVec(bone.pivot()); newBone.updateRotation( - (float) Math.toRadians(-rotation.x), - (float) Math.toRadians(-rotation.y), - (float) Math.toRadians(rotation.z) + (float) Math.toRadians(-rotation.x), + (float) Math.toRadians(-rotation.y), + (float) Math.toRadians(rotation.z) ); newBone.updatePivot((float) -pivot.x, (float) pivot.y, (float) pivot.z); @@ -213,8 +216,8 @@ public GeoBone constructBone(BoneStructure boneStructure, ModelProperties proper public GeoCube constructCube(Cube cube, ModelProperties properties, GeoBone bone) { boolean mirror = cube.mirror() == Boolean.TRUE; double inflate = cube.inflate() != null - ? cube.inflate() / 16f - : (bone.getInflate() == null ? 0 : bone.getInflate() / 16f); + ? cube.inflate() / 16f + : (bone.getInflate() == null ? 0 : bone.getInflate() / 16f); Vec3 size = RenderUtils.arrayToVec(cube.size()); Vec3 origin = RenderUtils.arrayToVec(cube.origin()); Vec3 rotation = RenderUtils.arrayToVec(cube.rotation()); @@ -225,12 +228,12 @@ public GeoCube constructCube(Cube cube, ModelProperties properties, GeoBone bone pivot = pivot.multiply(-1, 1, 1); rotation = new Vec3(Math.toRadians(-rotation.x), Math.toRadians(-rotation.y), Math.toRadians(rotation.z)); GeoQuad[] quads = buildQuads( - cube.uv(), - new VertexSet(origin, vertexSize, inflate), - cube, - (float) properties.textureWidth(), - (float) properties.textureHeight(), - mirror + cube.uv(), + new VertexSet(origin, vertexSize, inflate), + cube, + (float) properties.textureWidth(), + (float) properties.textureHeight(), + mirror ); return new GeoCube(quads, pivot, rotation, size, inflate, mirror); @@ -241,42 +244,42 @@ public GeoCube constructCube(Cube cube, ModelProperties properties, GeoBone bone * Holder class to make it easier to store and refer to vertices for a given cube */ record VertexSet( - GeoVertex bottomLeftBack, - GeoVertex bottomRightBack, - GeoVertex topLeftBack, - GeoVertex topRightBack, - GeoVertex topLeftFront, - GeoVertex topRightFront, - GeoVertex bottomLeftFront, - GeoVertex bottomRightFront + GeoVertex bottomLeftBack, + GeoVertex bottomRightBack, + GeoVertex topLeftBack, + GeoVertex topRightBack, + GeoVertex topLeftFront, + GeoVertex topRightFront, + GeoVertex bottomLeftFront, + GeoVertex bottomRightFront ) { public VertexSet(Vec3 origin, Vec3 vertexSize, double inflation) { this( - new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z - inflation), - new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z + vertexSize.z + inflation), - new GeoVertex(origin.x - inflation, origin.y + vertexSize.y + inflation, origin.z - inflation), - new GeoVertex( - origin.x - inflation, - origin.y + vertexSize.y + inflation, - origin.z + vertexSize.z + inflation - ), - new GeoVertex( - origin.x + vertexSize.x + inflation, - origin.y + vertexSize.y + inflation, - origin.z - inflation - ), - new GeoVertex( - origin.x + vertexSize.x + inflation, - origin.y + vertexSize.y + inflation, - origin.z + vertexSize.z + inflation - ), - new GeoVertex(origin.x + vertexSize.x + inflation, origin.y - inflation, origin.z - inflation), - new GeoVertex( - origin.x + vertexSize.x + inflation, - origin.y - inflation, - origin.z + vertexSize.z + inflation - ) + new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z - inflation), + new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z + vertexSize.z + inflation), + new GeoVertex(origin.x - inflation, origin.y + vertexSize.y + inflation, origin.z - inflation), + new GeoVertex( + origin.x - inflation, + origin.y + vertexSize.y + inflation, + origin.z + vertexSize.z + inflation + ), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y + vertexSize.y + inflation, + origin.z - inflation + ), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y + vertexSize.y + inflation, + origin.z + vertexSize.z + inflation + ), + new GeoVertex(origin.x + vertexSize.x + inflation, origin.y - inflation, origin.z - inflation), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y - inflation, + origin.z + vertexSize.z + inflation + ) ); } @@ -284,54 +287,54 @@ public VertexSet(Vec3 origin, Vec3 vertexSize, double inflation) { * Returns the normal vertex array for a west-facing quad */ public GeoVertex[] quadWest() { - return new GeoVertex[]{this.topRightBack, this.topLeftBack, this.bottomLeftBack, this.bottomRightBack}; + return new GeoVertex[] { this.topRightBack, this.topLeftBack, this.bottomLeftBack, this.bottomRightBack }; } /** * Returns the normal vertex array for an east-facing quad */ public GeoVertex[] quadEast() { - return new GeoVertex[]{ - this.topLeftFront, - this.topRightFront, - this.bottomRightFront, - this.bottomLeftFront}; + return new GeoVertex[] { + this.topLeftFront, + this.topRightFront, + this.bottomRightFront, + this.bottomLeftFront }; } /** * Returns the normal vertex array for a north-facing quad */ public GeoVertex[] quadNorth() { - return new GeoVertex[]{this.topLeftBack, this.topLeftFront, this.bottomLeftFront, this.bottomLeftBack}; + return new GeoVertex[] { this.topLeftBack, this.topLeftFront, this.bottomLeftFront, this.bottomLeftBack }; } /** * Returns the normal vertex array for a south-facing quad */ public GeoVertex[] quadSouth() { - return new GeoVertex[]{ - this.topRightFront, - this.topRightBack, - this.bottomRightBack, - this.bottomRightFront}; + return new GeoVertex[] { + this.topRightFront, + this.topRightBack, + this.bottomRightBack, + this.bottomRightFront }; } /** * Returns the normal vertex array for a top-facing quad */ public GeoVertex[] quadUp() { - return new GeoVertex[]{this.topRightBack, this.topRightFront, this.topLeftFront, this.topLeftBack}; + return new GeoVertex[] { this.topRightBack, this.topRightFront, this.topLeftFront, this.topLeftBack }; } /** * Returns the normal vertex array for a bottom-facing quad */ public GeoVertex[] quadDown() { - return new GeoVertex[]{ - this.bottomLeftBack, - this.bottomLeftFront, - this.bottomRightFront, - this.bottomRightBack}; + return new GeoVertex[] { + this.bottomLeftBack, + this.bottomLeftFront, + this.bottomRightFront, + this.bottomRightBack }; } /** diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BoneStructure.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BoneStructure.java index 631c8fc3d..cf24a6a14 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BoneStructure.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/BoneStructure.java @@ -1,23 +1,22 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.object; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.internal.common.loading.json.raw.Bone; import java.util.Map; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Bone; + /** * Container class for holding a {@link Bone} structure. Used at startup in deserialization */ public record BoneStructure( - Bone self, - Map children + Bone self, + Map children ) { public BoneStructure(Bone self) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/GeometryTree.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/GeometryTree.java index db382b860..a2c94c1eb 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/GeometryTree.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/loading/object/GeometryTree.java @@ -1,28 +1,27 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.loading.object; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +import java.util.List; +import java.util.Map; + import mod.azure.azurelib.common.internal.common.loading.json.raw.Bone; import mod.azure.azurelib.common.internal.common.loading.json.raw.MinecraftGeometry; import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; import mod.azure.azurelib.common.internal.common.loading.json.raw.ModelProperties; -import java.util.List; -import java.util.Map; - /** * Container class for a {@link Bone} structure, used at startup during deserialization */ public record GeometryTree( - Map topLevelBones, - ModelProperties properties + Map topLevelBones, + ModelProperties properties ) { public static GeometryTree fromModel(Model model) { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/AbstractPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/AbstractPacket.java index 2ed3c85c5..0aa84f979 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/AbstractPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/AbstractPacket.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java index 047713e9b..b60e857f1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/SerializableDataTicket.java @@ -1,29 +1,33 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network; -import mod.azure.azurelib.common.internal.common.constant.DataTickets; -import mod.azure.azurelib.core.object.DataTicket; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.internal.common.constant.DataTickets; +import mod.azure.azurelib.core.object.DataTicket; + /** * Network-compatible {@link DataTicket} implementation. Used for sending data from server -> client in an easy manner + * + * @deprecated */ +@Deprecated(forRemoval = true) public abstract class SerializableDataTicket extends DataTicket { - public static final StreamCodec> STREAM_CODEC = StreamCodec.composite( + public static final StreamCodec> STREAM_CODEC = StreamCodec + .composite( ByteBufCodecs.STRING_UTF8, SerializableDataTicket::id, - DataTickets::byName); + DataTickets::byName + ); protected SerializableDataTicket(String id, Class objectType) { super(id, objectType); @@ -36,6 +40,7 @@ protected SerializableDataTicket(String id, Class objectType) { */ public static SerializableDataTicket ofDouble(ResourceLocation id) { return new SerializableDataTicket<>(id.toString(), Double.class) { + @Override public StreamCodec streamCodec() { return ByteBufCodecs.DOUBLE; @@ -52,6 +57,7 @@ public StreamCodec streamCodec() { */ public static SerializableDataTicket ofFloat(ResourceLocation id) { return new SerializableDataTicket<>(id.toString(), Float.class) { + @Override public StreamCodec streamCodec() { return ByteBufCodecs.FLOAT; @@ -66,6 +72,7 @@ public StreamCodec streamCodec() { */ public static SerializableDataTicket ofBoolean(ResourceLocation id) { return new SerializableDataTicket<>(id.toString(), Boolean.class) { + @Override public StreamCodec streamCodec() { return ByteBufCodecs.BOOL; @@ -80,6 +87,7 @@ public StreamCodec streamCodec() { */ public static SerializableDataTicket ofInt(ResourceLocation id) { return new SerializableDataTicket<>(id.toString(), Integer.class) { + @Override public StreamCodec streamCodec() { return ByteBufCodecs.VAR_INT; @@ -94,6 +102,7 @@ public StreamCodec streamCodec() { */ public static SerializableDataTicket ofString(ResourceLocation id) { return new SerializableDataTicket<>(id.toString(), String.class) { + @Override public StreamCodec streamCodec() { return ByteBufCodecs.STRING_UTF8; @@ -108,8 +117,10 @@ public StreamCodec streamCodec() { */ public static > SerializableDataTicket ofEnum(ResourceLocation id, Class enumClass) { return new SerializableDataTicket<>(id.toString(), enumClass) { + public StreamCodec streamCodec() { return new StreamCodec<>() { + @Override public @NotNull E decode(@NotNull RegistryFriendlyByteBuf buf) { return Enum.valueOf(enumClass, buf.readUtf()); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java index 79b9a6bce..debffe187 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimDataSyncPacket.java @@ -1,43 +1,57 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import org.jetbrains.annotations.NotNull; + import mod.azure.azurelib.common.api.client.helper.ClientUtils; import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; import mod.azure.azurelib.common.internal.common.network.AbstractPacket; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import mod.azure.azurelib.core.animatable.GeoAnimatable; -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import org.jetbrains.annotations.NotNull; /** * Packet for syncing user-definable animation data for {@link SingletonGeoAnimatable} instances + * + * @deprecated */ -public record AnimDataSyncPacket(String syncableId, long instanceId, SerializableDataTicket dataTicket, - D data) implements AbstractPacket { +@Deprecated(forRemoval = true) +public record AnimDataSyncPacket( + String syncableId, + long instanceId, + SerializableDataTicket dataTicket, + D data +) implements AbstractPacket { public static final CustomPacketPayload.Type> TYPE = new Type<>( - AzureLibNetwork.ANIM_DATA_SYNC_PACKET_ID); + AzureLibNetwork.ANIM_DATA_SYNC_PACKET_ID + ); + public static final StreamCodec> CODEC = StreamCodec.of( - (buf, packet) -> { - SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); - buf.writeUtf(packet.syncableId); - buf.writeVarLong(packet.instanceId); - ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); - }, buf -> { - final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); - - return new AnimDataSyncPacket<>(buf.readUtf(), buf.readVarLong(), dataTicket, - dataTicket.streamCodec().decode(buf)); - }); + (buf, packet) -> { + SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); + buf.writeUtf(packet.syncableId); + buf.writeVarLong(packet.instanceId); + ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); + }, + buf -> { + final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); + + return new AnimDataSyncPacket<>( + buf.readUtf(), + buf.readVarLong(), + dataTicket, + dataTicket.streamCodec().decode(buf) + ); + } + ); @Override public void handle() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java index 35660559c..9f4edbf42 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AnimTriggerPacket.java @@ -1,33 +1,48 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.animation.AnimatableManager; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.animation.AnimatableManager; + /** * Packet for syncing user-definable animations that can be triggered from the server + * + * @deprecated */ -public record AnimTriggerPacket(String syncableId, long instanceId, String controllerName, - String animName) implements AbstractPacket { +public record AnimTriggerPacket( + String syncableId, + long instanceId, + String controllerName, + String animName +) implements AbstractPacket { + public static final CustomPacketPayload.Type TYPE = new Type<>( - AzureLibNetwork.ANIM_TRIGGER_SYNC_PACKET_ID); + AzureLibNetwork.ANIM_TRIGGER_SYNC_PACKET_ID + ); + public static final StreamCodec CODEC = StreamCodec.composite( - ByteBufCodecs.STRING_UTF8, AnimTriggerPacket::syncableId, ByteBufCodecs.VAR_LONG, - AnimTriggerPacket::instanceId, ByteBufCodecs.STRING_UTF8, AnimTriggerPacket::controllerName, - ByteBufCodecs.STRING_UTF8, AnimTriggerPacket::animName, AnimTriggerPacket::new); + ByteBufCodecs.STRING_UTF8, + AnimTriggerPacket::syncableId, + ByteBufCodecs.VAR_LONG, + AnimTriggerPacket::instanceId, + ByteBufCodecs.STRING_UTF8, + AnimTriggerPacket::controllerName, + ByteBufCodecs.STRING_UTF8, + AnimTriggerPacket::animName, + AnimTriggerPacket::new + ); @Override public void handle() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzBlockEntityDispatchCommandPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzBlockEntityDispatchCommandPacket.java new file mode 100644 index 000000000..5311cba90 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzBlockEntityDispatchCommandPacket.java @@ -0,0 +1,51 @@ +package mod.azure.azurelib.common.internal.common.network.packet; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; + +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.AzCommand; + +public record AzBlockEntityDispatchCommandPacket( + BlockPos blockPos, + AzCommand dispatchCommand +) implements AbstractPacket { + + public static final CustomPacketPayload.Type TYPE = new Type<>( + AzureLibNetwork.AZ_BLOCKENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID + ); + + public static final StreamCodec CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, + AzBlockEntityDispatchCommandPacket::blockPos, + AzCommand.CODEC, + AzBlockEntityDispatchCommandPacket::dispatchCommand, + AzBlockEntityDispatchCommandPacket::new + ); + + @Override + public void handle() { + var blockEntity = ClientUtils.getLevel().getBlockEntity(blockPos); + + if (blockEntity == null) { + return; + } + + var animator = AzAnimatorAccessor.getOrNull(blockEntity); + + if (animator != null) { + dispatchCommand.actions().forEach(action -> action.handle(AzDispatchSide.SERVER, animator)); + } + } + + @Override + public Type type() { + return TYPE; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityDispatchCommandPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityDispatchCommandPacket.java new file mode 100644 index 000000000..bdbb2cc40 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzEntityDispatchCommandPacket.java @@ -0,0 +1,51 @@ +package mod.azure.azurelib.common.internal.common.network.packet; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.AzCommand; + +public record AzEntityDispatchCommandPacket( + int entityId, + AzCommand dispatchCommand +) implements AbstractPacket { + + public static final Type TYPE = new Type<>( + AzureLibNetwork.AZ_ENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID + ); + + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, + AzEntityDispatchCommandPacket::entityId, + AzCommand.CODEC, + AzEntityDispatchCommandPacket::dispatchCommand, + AzEntityDispatchCommandPacket::new + ); + + public void handle() { + var entity = ClientUtils.getLevel().getEntity(this.entityId); + + if (entity == null) { + return; + } + + var animator = AzAnimatorAccessor.getOrNull(entity); + + if (animator != null) { + dispatchCommand.actions().forEach(action -> action.handle(AzDispatchSide.SERVER, animator)); + } + } + + @Override + public @NotNull Type type() { + return TYPE; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzItemStackDispatchCommandPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzItemStackDispatchCommandPacket.java new file mode 100644 index 000000000..3ef0aac62 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/AzItemStackDispatchCommandPacket.java @@ -0,0 +1,46 @@ +package mod.azure.azurelib.common.internal.common.network.packet; + +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.core2.animation.cache.AzIdentifiableItemStackAnimatorCache; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.AzCommand; + +public record AzItemStackDispatchCommandPacket( + UUID itemStackId, + AzCommand dispatchCommand +) implements AbstractPacket { + + public static final Type TYPE = new Type<>( + AzureLibNetwork.AZ_ITEM_STACK_DISPATCH_COMMAND_SYNC_PACKET_ID + ); + + public static final StreamCodec CODEC = StreamCodec.composite( + UUIDUtil.STREAM_CODEC, + AzItemStackDispatchCommandPacket::itemStackId, + AzCommand.CODEC, + AzItemStackDispatchCommandPacket::dispatchCommand, + AzItemStackDispatchCommandPacket::new + ); + + public void handle() { + var animator = AzIdentifiableItemStackAnimatorCache.getInstance().getOrNull(itemStackId); + + if (animator != null) { + dispatchCommand.actions().forEach(action -> action.handle(AzDispatchSide.SERVER, animator)); + } + } + + @Override + public @NotNull Type type() { + return TYPE; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java index 4f6cf0436..f61bc9ef9 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimDataSyncPacket.java @@ -1,17 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; -import mod.azure.azurelib.common.api.client.helper.ClientUtils; -import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.minecraft.core.BlockPos; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; @@ -19,24 +12,44 @@ import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + /** * Packet for syncing user-definable animation data for {@link BlockEntity BlockEntities} + * + * @deprecated */ -public record BlockEntityAnimDataSyncPacket(BlockPos blockPos, SerializableDataTicket dataTicket, - D data) implements AbstractPacket { +@Deprecated(forRemoval = true) +public record BlockEntityAnimDataSyncPacket( + BlockPos blockPos, + SerializableDataTicket dataTicket, + D data +) implements AbstractPacket { + public static final CustomPacketPayload.Type> TYPE = new Type<>( - AzureLibNetwork.BLOCK_ENTITY_ANIM_DATA_SYNC_PACKET_ID); + AzureLibNetwork.BLOCK_ENTITY_ANIM_DATA_SYNC_PACKET_ID + ); + public static final StreamCodec> CODEC = StreamCodec.of( - (buf, packet) -> { - SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); - buf.writeBlockPos(packet.blockPos); - ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); - }, buf -> { - final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); - - return new BlockEntityAnimDataSyncPacket<>(buf.readBlockPos(), dataTicket, - dataTicket.streamCodec().decode(buf)); - }); + (buf, packet) -> { + SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); + buf.writeBlockPos(packet.blockPos); + ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); + }, + buf -> { + final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); + + return new BlockEntityAnimDataSyncPacket<>( + buf.readBlockPos(), + dataTicket, + dataTicket.streamCodec().decode(buf) + ); + } + ); @Override public void handle() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java index eb7e9da42..1df11dcd2 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/BlockEntityAnimTriggerPacket.java @@ -1,16 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; -import mod.azure.azurelib.common.api.client.helper.ClientUtils; -import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; @@ -20,22 +14,36 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.api.common.animatable.GeoBlockEntity; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + /** * Packet for syncing user-definable animations that can be triggered from the server for * {@link net.minecraft.world.level.block.entity.BlockEntity BlockEntities} + * + * @deprecated */ -public record BlockEntityAnimTriggerPacket(BlockPos blockPos, @Nullable String controllerName, - String animName) implements AbstractPacket { +public record BlockEntityAnimTriggerPacket( + BlockPos blockPos, + @Nullable String controllerName, + String animName +) implements AbstractPacket { + public static final CustomPacketPayload.Type TYPE = new Type<>( - AzureLibNetwork.BLOCK_ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID); + AzureLibNetwork.BLOCK_ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID + ); + public static final StreamCodec CODEC = StreamCodec.composite( - BlockPos.STREAM_CODEC, - BlockEntityAnimTriggerPacket::blockPos, - ByteBufCodecs.STRING_UTF8, - BlockEntityAnimTriggerPacket::controllerName, - ByteBufCodecs.STRING_UTF8, - BlockEntityAnimTriggerPacket::animName, - BlockEntityAnimTriggerPacket::new); + BlockPos.STREAM_CODEC, + BlockEntityAnimTriggerPacket::blockPos, + ByteBufCodecs.STRING_UTF8, + BlockEntityAnimTriggerPacket::controllerName, + ByteBufCodecs.STRING_UTF8, + BlockEntityAnimTriggerPacket::animName, + BlockEntityAnimTriggerPacket::new + ); @Override public void handle() { diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java index a8f425e2c..bf9f62f2b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimDataSyncPacket.java @@ -1,12 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.NotNull; + import mod.azure.azurelib.common.api.client.helper.ClientUtils; import mod.azure.azurelib.common.api.common.animatable.GeoEntity; import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; @@ -14,38 +18,51 @@ import mod.azure.azurelib.common.internal.common.network.AbstractPacket; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; import mod.azure.azurelib.common.platform.services.AzureLibNetwork; -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.world.entity.Entity; -import org.jetbrains.annotations.NotNull; /** * Packet for syncing user-definable animation data for {@link net.minecraft.world.entity.Entity Entities} + * + * @deprecated */ -public record EntityAnimDataSyncPacket(int entityId, boolean isReplacedEntity, SerializableDataTicket dataTicket, - D data) implements AbstractPacket { +@Deprecated(forRemoval = true) +public record EntityAnimDataSyncPacket( + int entityId, + boolean isReplacedEntity, + SerializableDataTicket dataTicket, + D data +) implements AbstractPacket { + public static final CustomPacketPayload.Type> TYPE = new Type<>( - AzureLibNetwork.ENTITY_ANIM_DATA_SYNC_PACKET_ID); + AzureLibNetwork.ENTITY_ANIM_DATA_SYNC_PACKET_ID + ); + public static final StreamCodec> CODEC = StreamCodec.of( - (buf, packet) -> { - SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); - buf.writeVarInt(packet.entityId); - buf.writeBoolean(packet.isReplacedEntity); - ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); - }, buf -> { - final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); - - return new EntityAnimDataSyncPacket<>(buf.readVarInt(), buf.readBoolean(), dataTicket, - dataTicket.streamCodec().decode(buf)); - }); + (buf, packet) -> { + SerializableDataTicket.STREAM_CODEC.encode(buf, packet.dataTicket); + buf.writeVarInt(packet.entityId); + buf.writeBoolean(packet.isReplacedEntity); + ((StreamCodec) packet.dataTicket.streamCodec()).encode(buf, packet.data); + }, + buf -> { + final SerializableDataTicket dataTicket = SerializableDataTicket.STREAM_CODEC.decode(buf); + + return new EntityAnimDataSyncPacket<>( + buf.readVarInt(), + buf.readBoolean(), + dataTicket, + dataTicket.streamCodec().decode(buf) + ); + } + ); @Override public void handle() { Entity entity = ClientUtils.getLevel().getEntity(this.entityId); - if (entity == null) return; + if (entity == null) + return; if (!this.isReplacedEntity) { - if (entity instanceof GeoEntity geoEntity) geoEntity.setAnimData(this.dataTicket, this.data); + if (entity instanceof GeoEntity geoEntity) + geoEntity.setAnimData(this.dataTicket, this.data); return; } if (RenderUtils.getReplacedAnimatable(entity.getType()) instanceof GeoReplacedEntity replacedEntity) diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java index fd6d32d11..35f98ed63 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/EntityAnimTriggerPacket.java @@ -1,18 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.network.packet; -import mod.azure.azurelib.common.api.client.helper.ClientUtils; -import mod.azure.azurelib.common.api.common.animatable.GeoEntity; -import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; -import mod.azure.azurelib.common.internal.client.util.RenderUtils; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; @@ -20,24 +12,41 @@ import net.minecraft.world.entity.Entity; import org.jetbrains.annotations.NotNull; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.api.common.animatable.GeoEntity; +import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + /** * Packet for syncing user-definable animations that can be triggered from the server for * {@link net.minecraft.world.entity.Entity Entities} + * + * @deprecated */ -public record EntityAnimTriggerPacket(int entityId, boolean isReplacedEntity, String controllerName, - String animName) implements AbstractPacket { +public record EntityAnimTriggerPacket( + int entityId, + boolean isReplacedEntity, + String controllerName, + String animName +) implements AbstractPacket { + public static final CustomPacketPayload.Type TYPE = new Type<>( - AzureLibNetwork.ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID); + AzureLibNetwork.ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID + ); + public static final StreamCodec CODEC = StreamCodec.composite( - ByteBufCodecs.VAR_INT, - EntityAnimTriggerPacket::entityId, - ByteBufCodecs.BOOL, - EntityAnimTriggerPacket::isReplacedEntity, - ByteBufCodecs.STRING_UTF8, - EntityAnimTriggerPacket::controllerName, - ByteBufCodecs.STRING_UTF8, - EntityAnimTriggerPacket::animName, - EntityAnimTriggerPacket::new); + ByteBufCodecs.VAR_INT, + EntityAnimTriggerPacket::entityId, + ByteBufCodecs.BOOL, + EntityAnimTriggerPacket::isReplacedEntity, + ByteBufCodecs.STRING_UTF8, + EntityAnimTriggerPacket::controllerName, + ByteBufCodecs.STRING_UTF8, + EntityAnimTriggerPacket::animName, + EntityAnimTriggerPacket::new + ); public void handle() { Entity entity = ClientUtils.getLevel().getEntity(this.entityId); @@ -49,8 +58,11 @@ public void handle() { return; } if (RenderUtils.getReplacedAnimatable(entity.getType()) instanceof GeoReplacedEntity replacedEntity) - replacedEntity.triggerAnim(entity, this.controllerName.isEmpty() ? null : this.controllerName, - this.animName); + replacedEntity.triggerAnim( + entity, + this.controllerName.isEmpty() ? null : this.controllerName, + this.animName + ); } @Override diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/SendConfigDataPacket.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/SendConfigDataPacket.java index d8e2f345c..35557242b 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/SendConfigDataPacket.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/network/packet/SendConfigDataPacket.java @@ -1,18 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ - package mod.azure.azurelib.common.internal.common.network.packet; +package mod.azure.azurelib.common.internal.common.network.packet; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.AzureLibException; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; -import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; -import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; @@ -23,42 +14,55 @@ import java.util.Map; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.AzureLibException; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; +import mod.azure.azurelib.common.internal.common.config.adapter.TypeAdapter; +import mod.azure.azurelib.common.internal.common.config.value.ConfigValue; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + public record SendConfigDataPacket(String config) implements AbstractPacket { public static final Marker MARKER = MarkerManager.getMarker("Network"); + public static final Type TYPE = new Type<>( - AzureLibNetwork.CONFIG_PACKET_ID); + AzureLibNetwork.CONFIG_PACKET_ID + ); + public static final StreamCodec CODEC = StreamCodec.of( - (buf, packet) -> { - buf.writeUtf(packet.config); - ConfigHolderRegistry.getConfig(packet.config).ifPresent(data -> { - Map> serialized = data.getNetworkSerializedFields(); - buf.writeInt(serialized.size()); - for (Map.Entry> entry : serialized.entrySet()) { - String id = entry.getKey(); - ConfigValue value = entry.getValue(); - TypeAdapter adapter = value.getAdapter(); - buf.writeUtf(id); - adapter.encodeToBuffer(value, buf); - } - }); - }, buf -> { - String config = buf.readUtf(); - int i = buf.readInt(); - ConfigHolderRegistry.getConfig(config).ifPresent(data -> { - Map> serialized = data.getNetworkSerializedFields(); - for (int j = 0; j < i; j++) { - String fieldId = buf.readUtf(); - ConfigValue value = serialized.get(fieldId); - if (value == null) { - AzureLib.LOGGER.fatal(MARKER, "Received unknown config value " + fieldId); - throw new AzureLibException("Unknown config field: " + fieldId); - } - setValue(value, buf); + (buf, packet) -> { + buf.writeUtf(packet.config); + ConfigHolderRegistry.getConfig(packet.config).ifPresent(data -> { + Map> serialized = data.getNetworkSerializedFields(); + buf.writeInt(serialized.size()); + for (Map.Entry> entry : serialized.entrySet()) { + String id = entry.getKey(); + ConfigValue value = entry.getValue(); + TypeAdapter adapter = value.getAdapter(); + buf.writeUtf(id); + adapter.encodeToBuffer(value, buf); + } + }); + }, + buf -> { + String config = buf.readUtf(); + int i = buf.readInt(); + ConfigHolderRegistry.getConfig(config).ifPresent(data -> { + Map> serialized = data.getNetworkSerializedFields(); + for (int j = 0; j < i; j++) { + String fieldId = buf.readUtf(); + ConfigValue value = serialized.get(fieldId); + if (value == null) { + AzureLib.LOGGER.fatal(MARKER, "Received unknown config value " + fieldId); + throw new AzureLibException("Unknown config field: " + fieldId); } - }); - return new SendConfigDataPacket(config); + setValue(value, buf); + } }); + return new SendConfigDataPacket(config); + } + ); @SuppressWarnings("unchecked") private static void setValue(ConfigValue value, FriendlyByteBuf buffer) { @@ -73,7 +77,5 @@ private static void setValue(ConfigValue value, FriendlyByteBuf buffer) { } @Override - public void handle() { - - } + public void handle() {} } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksEntityRegistry.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksEntityRegistry.java index 25a2f3609..db085c85f 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksEntityRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksEntityRegistry.java @@ -1,24 +1,22 @@ package mod.azure.azurelib.common.internal.common.registry; -import mod.azure.azurelib.common.api.common.registry.CommonBlockEntityRegistryInterface; -import mod.azure.azurelib.common.api.common.registry.CommonBlockRegistryInterface; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.material.PushReaction; import java.util.function.Supplier; +import mod.azure.azurelib.common.api.common.registry.CommonBlockEntityRegistryInterface; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; + public class AzureBlocksEntityRegistry implements CommonBlockEntityRegistryInterface { - public static final Supplier> TICKING_LIGHT_ENTITY = CommonBlockEntityRegistryInterface.registerBlockEntity( + public static final Supplier> TICKING_LIGHT_ENTITY = + CommonBlockEntityRegistryInterface.registerBlockEntity( AzureLib.MOD_ID, "lightblock", - () -> BlockEntityType.Builder.of(TickingLightEntity::new, AzureBlocksRegistry.TICKING_LIGHT_BLOCK.get()).build(null)); + () -> BlockEntityType.Builder.of(TickingLightEntity::new, AzureBlocksRegistry.TICKING_LIGHT_BLOCK.get()) + .build(null) + ); - public static void init() { - } + public static void init() {} } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksRegistry.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksRegistry.java index c4af24904..2871a0f0c 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/registry/AzureBlocksRegistry.java @@ -1,24 +1,28 @@ package mod.azure.azurelib.common.internal.common.registry; -import mod.azure.azurelib.common.api.common.registry.CommonBlockRegistryInterface; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.material.PushReaction; import java.util.function.Supplier; +import mod.azure.azurelib.common.api.common.registry.CommonBlockRegistryInterface; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; + public class AzureBlocksRegistry implements CommonBlockRegistryInterface { - public static final Supplier TICKING_LIGHT_BLOCK = CommonBlockRegistryInterface.registerBlock(AzureLib.MOD_ID, "lightblock", () -> new TickingLightBlock( + public static final Supplier TICKING_LIGHT_BLOCK = CommonBlockRegistryInterface.registerBlock( + AzureLib.MOD_ID, + "lightblock", + () -> new TickingLightBlock( BlockBehaviour.Properties.of() - .sound(SoundType.CANDLE) - .lightLevel(TickingLightBlock.litBlockEmission(15)) - .pushReaction(PushReaction.DESTROY) - .noOcclusion() - )); + .sound(SoundType.CANDLE) + .lightLevel(TickingLightBlock.litBlockEmission(15)) + .pushReaction(PushReaction.DESTROY) + .noOcclusion() + ) + ); - public static void init() { - } + public static void init() {} } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java index e4ceda8f0..28acb96b6 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/AzureLibUtil.java @@ -1,17 +1,19 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.util; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; + import mod.azure.azurelib.common.internal.common.constant.DataTickets; import mod.azure.azurelib.common.internal.common.loading.object.BakedModelFactory; import mod.azure.azurelib.common.internal.common.network.SerializableDataTicket; import mod.azure.azurelib.common.internal.common.registry.AzureBlocksRegistry; -import mod.azure.azurelib.common.platform.Services; import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; import mod.azure.azurelib.core.animatable.instance.InstancedAnimatableInstanceCache; @@ -19,17 +21,16 @@ import mod.azure.azurelib.core.animation.Animation; import mod.azure.azurelib.core.animation.EasingType; import mod.azure.azurelib.core.object.DataTicket; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; /** * Helper class for various AzureLib-specific functions. */ public record AzureLibUtil() { + public static T self(Object object) { + return (T) object; + } + /** * Creates a new AnimatableInstanceCache for the given animatable object * @@ -39,11 +40,11 @@ public static AnimatableInstanceCache createInstanceCache(GeoAnimatable animatab AnimatableInstanceCache cache = animatable.animatableCacheOverride(); return cache != null - ? cache - : createInstanceCache( + ? cache + : createInstanceCache( animatable, !(animatable instanceof Entity) && !(animatable instanceof BlockEntity) - ); + ); } /** @@ -61,10 +62,10 @@ public static AnimatableInstanceCache createInstanceCache(GeoAnimatable animatab return cache; return singletonObject - ? new SingletonAnimatableInstanceCache( + ? new SingletonAnimatableInstanceCache( animatable - ) - : new InstancedAnimatableInstanceCache(animatable); + ) + : new InstancedAnimatableInstanceCache(animatable); } /** @@ -116,9 +117,9 @@ public static synchronized SerializableDataTicket addDataTicket(Serializa public static boolean checkDistance(BlockPos blockPosA, BlockPos blockPosB, int distance) { return Math.abs(blockPosA.getX() - blockPosB.getX()) <= distance && Math.abs( - blockPosA.getY() - blockPosB.getY() + blockPosA.getY() - blockPosB.getY() ) <= distance && Math.abs( - blockPosA.getZ() - blockPosB.getZ() + blockPosA.getZ() - blockPosB.getZ() ) <= distance; } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java index 4ab7c0be2..f3cbad15d 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/common/util/JsonUtil.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.common.util; @@ -10,11 +8,6 @@ import com.google.gson.*; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.common.internal.common.loading.json.raw.*; -import mod.azure.azurelib.common.internal.common.loading.json.typeadapter.BakedAnimationsAdapter; -import mod.azure.azurelib.common.internal.common.loading.json.typeadapter.KeyFramesAdapter; -import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; -import mod.azure.azurelib.core.animation.Animation; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; @@ -23,28 +16,42 @@ import java.util.Map; import java.util.function.Function; +import mod.azure.azurelib.common.internal.common.loading.json.raw.*; +import mod.azure.azurelib.common.internal.common.loading.json.typeadapter.BakedAnimationsAdapter; +import mod.azure.azurelib.common.internal.common.loading.json.typeadapter.KeyFramesAdapter; +import mod.azure.azurelib.common.internal.common.loading.object.BakedAnimations; +import mod.azure.azurelib.core.animation.Animation; +import mod.azure.azurelib.core2.animation.parse.AzBakedAnimationsAdapter; +import mod.azure.azurelib.core2.animation.parse.AzKeyframesAdapter; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; +import mod.azure.azurelib.core2.animation.primitive.AzKeyframes; + /** * Json helper class for various json functions */ public record JsonUtil() { public static final Gson GEO_GSON = new GsonBuilder().setLenient() - .registerTypeAdapter(Bone.class, Bone.deserializer()) - .registerTypeAdapter(Cube.class, Cube.deserializer()) - .registerTypeAdapter(FaceUV.class, FaceUV.deserializer()) - .registerTypeAdapter(LocatorClass.class, LocatorClass.deserializer()) - .registerTypeAdapter(LocatorValue.class, LocatorValue.deserializer()) - .registerTypeAdapter(MinecraftGeometry.class, MinecraftGeometry.deserializer()) - .registerTypeAdapter(Model.class, Model.deserializer()) - .registerTypeAdapter(ModelProperties.class, ModelProperties.deserializer()) - .registerTypeAdapter(PolyMesh.class, PolyMesh.deserializer()) - .registerTypeAdapter(PolysUnion.class, PolysUnion.deserializer()) - .registerTypeAdapter(TextureMesh.class, TextureMesh.deserializer()) - .registerTypeAdapter(UVFaces.class, UVFaces.deserializer()) - .registerTypeAdapter(UVUnion.class, UVUnion.deserializer()) - .registerTypeAdapter(Animation.Keyframes.class, new KeyFramesAdapter()) - .registerTypeAdapter(BakedAnimations.class, new BakedAnimationsAdapter()) - .create(); + .registerTypeAdapter(Bone.class, Bone.deserializer()) + .registerTypeAdapter(Cube.class, Cube.deserializer()) + .registerTypeAdapter(FaceUV.class, FaceUV.deserializer()) + .registerTypeAdapter(LocatorClass.class, LocatorClass.deserializer()) + .registerTypeAdapter(LocatorValue.class, LocatorValue.deserializer()) + .registerTypeAdapter(MinecraftGeometry.class, MinecraftGeometry.deserializer()) + .registerTypeAdapter(Model.class, Model.deserializer()) + .registerTypeAdapter(ModelProperties.class, ModelProperties.deserializer()) + .registerTypeAdapter(PolyMesh.class, PolyMesh.deserializer()) + .registerTypeAdapter(PolysUnion.class, PolysUnion.deserializer()) + .registerTypeAdapter(TextureMesh.class, TextureMesh.deserializer()) + .registerTypeAdapter(UVFaces.class, UVFaces.deserializer()) + .registerTypeAdapter(UVUnion.class, UVUnion.deserializer()) + // TODO: Remove + .registerTypeAdapter(Animation.Keyframes.class, new KeyFramesAdapter()) + // TODO: Remove + .registerTypeAdapter(BakedAnimations.class, new BakedAnimationsAdapter()) + .registerTypeAdapter(AzKeyframes.class, new AzKeyframesAdapter()) + .registerTypeAdapter(AzBakedAnimations.class, new AzBakedAnimationsAdapter()) + .create(); /** * Convert a {@link JsonArray} of doubles to a {@code double[]}.
@@ -73,9 +80,9 @@ public static double[] jsonArrayToDoubleArray(@Nullable JsonArray array) throws * @param objectClass The object type that the array contains */ public static T[] jsonArrayToObjectArray( - JsonArray array, - JsonDeserializationContext context, - Class objectClass + JsonArray array, + JsonDeserializationContext context, + Class objectClass ) { T[] objArray = (T[]) Array.newInstance(objectClass, array.size()); @@ -114,9 +121,9 @@ public static List jsonArrayToList(@Nullable JsonArray array, Function Map jsonObjToMap( - JsonObject obj, - JsonDeserializationContext context, - Class objectType + JsonObject obj, + JsonDeserializationContext context, + Class objectType ) { Map map = new Object2ObjectOpenHashMap<>(obj.size()); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java new file mode 100644 index 000000000..e47d1b8a3 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/BlockEntityMixin_AzBlockEntityAnimatorCache.java @@ -0,0 +1,33 @@ +package mod.azure.azurelib.common.internal.mixins; + +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; + +/** + * Mixin class that implements the {@code AzAnimatorAccessor} interface to enable managing and associating + * an {@link AzAnimator} instance with a {@link BlockEntity}. This allows for caching and retrieval of the animator + * associated with specific block entities. This mixin modifies the behavior of {@link BlockEntity} by adding an + * animator cache that can be used to store and retrieve {@link AzAnimator} instances for animation handling. + */ +@Mixin(BlockEntity.class) +public abstract class BlockEntityMixin_AzBlockEntityAnimatorCache implements AzAnimatorAccessor { + + @Unique + @Nullable + private AzAnimator animator; + + @Override + public void setAnimator(@Nullable AzAnimator animator) { + this.animator = animator; + } + + @Override + public @Nullable AzAnimator getAnimatorOrNull() { + return animator; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java new file mode 100644 index 000000000..e1382d938 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/EntityMixin_AzEntityAnimatorCache.java @@ -0,0 +1,33 @@ +package mod.azure.azurelib.common.internal.mixins; + +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; + +/** + * A Mixin class designed to integrate an animation cache mechanism into the {@link Entity} class through the use of the + * {@link AzAnimatorAccessor} interface. This allows entities to store an instance of {@link AzAnimator} for managing + * animations. Implements methods to set and retrieve the {@link AzAnimator} instance, enabling animation control and + * association to the entity. + */ +@Mixin(Entity.class) +public abstract class EntityMixin_AzEntityAnimatorCache implements AzAnimatorAccessor { + + @Unique + @Nullable + private AzAnimator animator; + + @Override + public void setAnimator(@Nullable AzAnimator animator) { + this.animator = animator; + } + + @Override + public @Nullable AzAnimator getAnimatorOrNull() { + return animator; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemRendererAccessor.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemRendererAccessor.java index af03e289b..dd7e653cd 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemRendererAccessor.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemRendererAccessor.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.mixins; diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java new file mode 100644 index 000000000..5879900dd --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemAnimatorCache.java @@ -0,0 +1,29 @@ +package mod.azure.azurelib.common.internal.mixins; + +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.cache.AzIdentifiableItemStackAnimatorCache; +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; + +@Mixin(ItemStack.class) +public abstract class ItemStackMixin_AzItemAnimatorCache implements AzAnimatorAccessor { + + @Override + public void setAnimator(@Nullable AzAnimator animator) { + var itemStack = AzureLibUtil.self(this); + AzIdentifiableItemStackAnimatorCache.getInstance().add(itemStack, (AzItemAnimator) animator); + } + + @Override + public @Nullable AzAnimator getAnimatorOrNull() { + var self = AzureLibUtil.self(this); + var uuid = self.getComponents().get(AzureLib.AZ_ID.get()); + return AzIdentifiableItemStackAnimatorCache.getInstance().getOrNull(uuid); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java new file mode 100644 index 000000000..db744d71d --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/ItemStackMixin_AzItemStackIdentityRegistry.java @@ -0,0 +1,40 @@ +package mod.azure.azurelib.common.internal.mixins; + +import net.minecraft.core.component.PatchedDataComponentMap; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.UUID; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.core2.animation.cache.AzIdentityRegistry; + +/** + * A mixin class for modifying the initialization behavior of the {@link ItemStack} class. This mixin specifically + * ensures that a unique identity component is added to an {@link ItemStack} upon creation, provided that the associated + * item has been registered in the {@link AzIdentityRegistry}. When an {@link ItemStack} is instantiated, the mixin + * checks if: - The item has an identity registered in {@link AzIdentityRegistry}. - The provided + * {@link PatchedDataComponentMap} does not already contain an `az_id` component. If both conditions are met, the mixin + * assigns a universally unique identifier (UUID) as the `az_id` component to the associated + * {@link PatchedDataComponentMap}. This mechanism enables unique identification and tracking of specific item stacks in + * the game. + */ +@Mixin(ItemStack.class) +public class ItemStackMixin_AzItemStackIdentityRegistry { + + @Inject( + method = "(Lnet/minecraft/world/level/ItemLike;ILnet/minecraft/core/component/PatchedDataComponentMap;)V", + at = @At("TAIL") + ) + public void az_addIdentityComponent(ItemLike item, int count, PatchedDataComponentMap components, CallbackInfo ci) { + var self = AzureLibUtil.self(this); + if (AzIdentityRegistry.hasIdentity(self.getItem()) && !components.has(AzureLib.AZ_ID.get())) { + components.set(AzureLib.AZ_ID.get(), UUID.randomUUID()); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MinecraftMixin.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MinecraftMixin.java index c0f67ffc0..d1a420092 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MinecraftMixin.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MinecraftMixin.java @@ -1,14 +1,10 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.mixins; import com.mojang.blaze3d.platform.WindowEventHandler; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; -import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; import net.minecraft.util.thread.ReentrantBlockableEventLoop; @@ -19,6 +15,9 @@ import java.util.Optional; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; +import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; + @Mixin(Minecraft.class) public abstract class MinecraftMixin extends ReentrantBlockableEventLoop implements WindowEventHandler { @@ -26,12 +25,17 @@ public MinecraftMixin(String p_i50401_1_) { super(p_i50401_1_); } - @Inject(method = "clearClientLevel(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;resetData()V")) + @Inject( + method = "clearClientLevel(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At( + value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;resetData()V" + ) + ) private void configuration_reloadClientConfigs(Screen screen, CallbackInfo ci) { - ConfigHolderRegistry.getSynchronizedConfigs().stream() - .map(ConfigHolderRegistry::getConfig) - .filter(Optional::isPresent) - .map(Optional::get) - .forEach(ConfigIO::reloadClientValues); + ConfigHolderRegistry.getSynchronizedConfigs() + .stream() + .map(ConfigHolderRegistry::getConfig) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(ConfigIO::reloadClientValues); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java index 46262ee9f..35e25c696 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinHumanoidArmorLayer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.mixins; @@ -11,11 +9,7 @@ import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalRef; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; import net.minecraft.client.model.HumanoidModel; -import net.minecraft.client.model.Model; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer; import net.minecraft.client.renderer.texture.OverlayTexture; @@ -30,35 +24,82 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.core2.render.armor.AzArmorRendererRegistry; + +/** + * @deprecated + */ @Mixin(HumanoidArmorLayer.class) +@Deprecated(forRemoval = true) public abstract class MixinHumanoidArmorLayer> { @ModifyExpressionValue( - method = "renderArmorPiece", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/entity/LivingEntity;getItemBySlot(Lnet/minecraft/world/entity/EquipmentSlot;)Lnet/minecraft/world/item/ItemStack;" - ) + method = "renderArmorPiece", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;getItemBySlot(Lnet/minecraft/world/entity/EquipmentSlot;)Lnet/minecraft/world/item/ItemStack;" + ) ) - private ItemStack azurelib$captureItemBySlot(ItemStack original, @Share("item_by_slot") LocalRef itemBySlotRef) { + private ItemStack azurelib$captureItemBySlot( + ItemStack original, + @Share("item_by_slot") LocalRef itemBySlotRef + ) { itemBySlotRef.set(original); return original; } - @Inject(method = "renderArmorPiece", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;usesInnerModel(Lnet/minecraft/world/entity/EquipmentSlot;)Z"), cancellable = true) - public void azurelib$renderAzurelibModel(PoseStack poseStack, MultiBufferSource bufferSource, T entity, EquipmentSlot equipmentSlot, int packedLight, A baseModel, CallbackInfo ci, @Share("item_by_slot") LocalRef itemBySlotRef) { - final ItemStack stack = itemBySlotRef.get(); - final Model geckolibModel = RenderProvider.of(stack).getGenericArmorModel(entity, stack, equipmentSlot, - (HumanoidModel) baseModel); + @Inject( + method = "renderArmorPiece", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;usesInnerModel(Lnet/minecraft/world/entity/EquipmentSlot;)Z" + ), cancellable = true + ) + public void azurelib$renderAzurelibModel( + PoseStack poseStack, + MultiBufferSource bufferSource, + T entity, + EquipmentSlot equipmentSlot, + int packedLight, + A baseModel, + CallbackInfo ci, + @Share("item_by_slot") LocalRef itemBySlotRef + ) { + var stack = itemBySlotRef.get(); + var renderProvider = RenderProvider.of(stack); + @SuppressWarnings("unchecked") + var humanoidModel = (HumanoidModel) baseModel; + var geckolibModel = renderProvider + .getGenericArmorModel(entity, stack, equipmentSlot, humanoidModel); + var i2 = stack.is( + ItemTags.DYEABLE + ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(stack, -6265536)) : -1; if (geckolibModel != null && stack.getItem() instanceof GeoItem) { - if (geckolibModel instanceof GeoArmorRenderer geoArmorRenderer) + if (geckolibModel instanceof GeoArmorRenderer geoArmorRenderer) { geoArmorRenderer.prepForRender(entity, stack, equipmentSlot, baseModel); + } baseModel.copyPropertiesTo((A) geckolibModel); - geckolibModel.renderToBuffer(poseStack, null, packedLight, OverlayTexture.NO_OVERLAY, stack.is( - ItemTags.DYEABLE) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(stack, -6265536)) : -1); + + geckolibModel.renderToBuffer(poseStack, null, packedLight, OverlayTexture.NO_OVERLAY, i2); + ci.cancel(); + } + + var renderer = AzArmorRendererRegistry.getOrNull(stack.getItem()); + + if (renderer != null) { + var rendererPipeline = renderer.rendererPipeline(); + var armorModel = rendererPipeline.armorModel(); + @SuppressWarnings("unchecked") + var typedHumanoidModel = (HumanoidModel) armorModel; + + renderer.prepForRender(entity, stack, equipmentSlot, baseModel); + baseModel.copyPropertiesTo(typedHumanoidModel); + armorModel.renderToBuffer(poseStack, null, packedLight, OverlayTexture.NO_OVERLAY, i2); ci.cancel(); } } -} \ No newline at end of file +} diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java index 1ce904dd0..d51e59e8a 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/MixinItemRenderer.java @@ -1,15 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.mixins; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.resources.model.BakedModel; @@ -20,6 +16,10 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.core2.render.item.AzItemRendererRegistry; + /** * Render hook to inject AzureLib's ISTER rendering callback */ @@ -27,25 +27,37 @@ public class MixinItemRenderer { @Inject( - method = "render", at = @At( + method = "render", at = @At( value = "INVOKE", target = "Lnet/minecraft/client/renderer/BlockEntityWithoutLevelRenderer;renderByItem(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemDisplayContext;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;II)V" - ), cancellable = true + ), cancellable = true ) public void itemModelHook( - ItemStack itemStack, - ItemDisplayContext transformType, - boolean bl, - PoseStack poseStack, - MultiBufferSource multiBufferSource, - int i, - int j, - BakedModel bakedModel, - CallbackInfo ci + ItemStack itemStack, + ItemDisplayContext transformType, + boolean bl, + PoseStack poseStack, + MultiBufferSource multiBufferSource, + int i, + int j, + BakedModel bakedModel, + CallbackInfo ci ) { - if (itemStack.getItem() instanceof GeoItem) + // TODO: Remove this along with Geo-code. + if (itemStack.getItem() instanceof GeoItem) { RenderProvider.of(itemStack) - .getCustomRenderer() - .renderByItem(itemStack, transformType, poseStack, multiBufferSource, i, j); + .getCustomRenderer() + .renderByItem(itemStack, transformType, poseStack, multiBufferSource, i, j); + } + + var item = itemStack.getItem(); + var renderer = AzItemRendererRegistry.getOrNull(item); + + if (renderer != null) { + switch (transformType) { + case GUI -> renderer.renderByGui(itemStack, poseStack, multiBufferSource, i); + default -> renderer.renderByItem(itemStack, poseStack, multiBufferSource, i); + } + } } } diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/PlayerListMixin.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/PlayerListMixin.java index 7f570b5d9..67360ad68 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/PlayerListMixin.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/PlayerListMixin.java @@ -1,13 +1,9 @@ /** - * This class is a fork of the matching class found in the Configuration repository. - * Original source: https://github.com/Toma1O6/Configuration - * Copyright © 2024 Toma1O6. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Configuration repository. Original source: + * https://github.com/Toma1O6/Configuration Copyright © 2024 Toma1O6. Licensed under the MIT License. */ package mod.azure.azurelib.common.internal.mixins; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; -import mod.azure.azurelib.common.platform.Services; import net.minecraft.network.Connection; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; @@ -19,15 +15,18 @@ import java.util.Set; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; +import mod.azure.azurelib.common.platform.Services; + @Mixin(PlayerList.class) public abstract class PlayerListMixin { @Inject(method = "placeNewPlayer", at = @At("TAIL")) private void configuration_sendServerConfigs( - Connection connection, - ServerPlayer player, - CommonListenerCookie commonListenerCookie, - CallbackInfo ci + Connection connection, + ServerPlayer player, + CommonListenerCookie commonListenerCookie, + CallbackInfo ci ) { Set set = ConfigHolderRegistry.getSynchronizedConfigs(); set.forEach(id -> Services.NETWORK.sendClientPacket(player, id)); diff --git a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java index f62300c24..1e2816d35 100644 --- a/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java +++ b/common/src/main/java/mod/azure/azurelib/common/internal/mixins/TextureManagerMixin.java @@ -1,13 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.common.internal.mixins; -import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.resources.ResourceLocation; @@ -20,7 +17,13 @@ import java.util.Map; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; + +/** + * @deprecated + */ @Mixin(TextureManager.class) +@Deprecated(forRemoval = true) public abstract class TextureManagerMixin { @Shadow @@ -31,8 +34,8 @@ public abstract class TextureManagerMixin { public abstract void register(ResourceLocation resourceLocation, AbstractTexture abstractTexture); @Inject( - method = "getTexture(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/renderer/texture/AbstractTexture;", - at = @At("HEAD") + method = "getTexture(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/renderer/texture/AbstractTexture;", + at = @At("HEAD") ) private void wrapAnimatableTexture(ResourceLocation path, CallbackInfoReturnable callback) { AbstractTexture existing = this.byPath.get(path); diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/Services.java b/common/src/main/java/mod/azure/azurelib/common/platform/Services.java index 0b4c83fb4..f3ee93951 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/Services.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/Services.java @@ -1,10 +1,9 @@ package mod.azure.azurelib.common.platform; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.platform.services.*; - import java.util.ServiceLoader; +import mod.azure.azurelib.common.platform.services.*; + public final class Services { public static final AzureEvents GEO_RENDER_PHASE_EVENT_FACTORY = load(AzureEvents.class); @@ -23,7 +22,7 @@ private Services() { public static T load(Class clazz) { return ServiceLoader.load(clazz) - .findFirst() - .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); + .findFirst() + .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); } } diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AccessWidener.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AccessWidener.java index a11c1dee0..aa737aa0f 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AccessWidener.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AccessWidener.java @@ -1,4 +1,3 @@ package mod.azure.azurelib.common.platform.services; -public interface AccessWidener { -} +public interface AccessWidener {} diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureEvents.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureEvents.java index bcea2d28c..44c88e8c1 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureEvents.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureEvents.java @@ -1,86 +1,184 @@ package mod.azure.azurelib.common.platform.services; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; + import mod.azure.azurelib.common.api.client.renderer.*; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import net.minecraft.client.renderer.MultiBufferSource; public interface AzureEvents { + /** * Fire the Block.CompileRenderLayers event */ void fireCompileBlockRenderLayers(GeoBlockRenderer renderer); + /** * Fire the Block.Pre event */ - boolean fireBlockPreRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireBlockPreRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the Block.Post event */ - void fireBlockPostRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireBlockPostRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Fire the Armor.CompileRenderLayers event */ void fireCompileArmorRenderLayers(GeoArmorRenderer renderer); + /** * Fire the Armor.Pre event */ - boolean fireArmorPreRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireArmorPreRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the Armor.Post event */ - void fireArmorPostRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireArmorPostRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Fire the Entity.CompileRenderLayers event */ void fireCompileEntityRenderLayers(GeoEntityRenderer renderer); + /** * Fire the Entity.Pre event */ - boolean fireEntityPreRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireEntityPreRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the Entity.Post event */ - void fireEntityPostRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireEntityPostRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Fire the ReplacedEntity.CompileRenderLayers event */ void fireCompileReplacedEntityRenderLayers(GeoReplacedEntityRenderer renderer); + /** * Fire the ReplacedEntity.Pre event */ - boolean fireReplacedEntityPreRender(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireReplacedEntityPreRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the ReplacedEntity.Post event */ - void fireReplacedEntityPostRender(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireReplacedEntityPostRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Fire the Item.CompileRenderLayers event */ void fireCompileItemRenderLayers(GeoItemRenderer renderer); + /** * Fire the Item.Pre event */ - boolean fireItemPreRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireItemPreRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the Item.Post event */ - void fireItemPostRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireItemPostRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); /** * Fire the Object.CompileRenderLayers event */ void fireCompileObjectRenderLayers(GeoObjectRenderer renderer); + /** * Fire the Object.Pre event */ - boolean fireObjectPreRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + boolean fireObjectPreRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); + /** * Fire the Object.Post event */ - void fireObjectPostRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight); + void fireObjectPostRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ); } diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java index 8a57ef2c1..a1d167601 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/AzureLibNetwork.java @@ -1,10 +1,6 @@ package mod.azure.azurelib.common.platform.services; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; @@ -17,12 +13,31 @@ import java.util.Map; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + public interface AzureLibNetwork { ResourceLocation ANIM_DATA_SYNC_PACKET_ID = AzureLib.modResource("anim_data_sync"); ResourceLocation ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("anim_trigger_sync"); + ResourceLocation AZ_BLOCKENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID = AzureLib.modResource( + "az_blockentity_dispatch_command_sync" + ); + + ResourceLocation AZ_ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("az_entity_anim_trigger_sync"); + + ResourceLocation AZ_ENTITY_DISPATCH_COMMAND_SYNC_PACKET_ID = AzureLib.modResource( + "az_entity_dispatch_command_sync" + ); + + ResourceLocation AZ_ITEM_STACK_DISPATCH_COMMAND_SYNC_PACKET_ID = AzureLib.modResource( + "az_item_stack_dispatch_command_sync" + ); + ResourceLocation ENTITY_ANIM_DATA_SYNC_PACKET_ID = AzureLib.modResource("entity_anim_data_sync"); ResourceLocation ENTITY_ANIM_TRIGGER_SYNC_PACKET_ID = AzureLib.modResource("entity_anim_trigger_sync"); @@ -54,7 +69,11 @@ static GeoAnimatable getSyncedAnimatable(String className) { return animatable; } - void registerPacketInternal(CustomPacketPayload.Type

payloadType, StreamCodec codec, boolean isClientBound); + void registerPacketInternal( + CustomPacketPayload.Type

payloadType, + StreamCodec codec, + boolean isClientBound + ); /** * Registers a synced {@link GeoAnimatable} object for networking support.
diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/CommonRegistry.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/CommonRegistry.java index 1ccfde3a3..eccdc9b9e 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/CommonRegistry.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/CommonRegistry.java @@ -24,11 +24,19 @@ public interface CommonRegistry { - Supplier> registerBlockEntity(String modID, String blockEntityName, Supplier> blockEntityType); + Supplier> registerBlockEntity( + String modID, + String blockEntityName, + Supplier> blockEntityType + ); Supplier registerBlock(String modID, String blockName, Supplier block); - Supplier> registerEntity(String modID, String entityName, Supplier> entity); + Supplier> registerEntity( + String modID, + String entityName, + Supplier> entity + ); Holder registerArmorMaterial(String modID, String matName, Supplier armorMaterial); @@ -38,13 +46,21 @@ public interface CommonRegistry { > Supplier registerScreen(String modID, String screenName, Supplier menuType); - Supplier> registerStructure(String modID, String structureName, MapCodec structure); + Supplier> registerStructure( + String modID, + String structureName, + MapCodec structure + ); > Supplier registerParticle(String modID, String particleName, Supplier particle); Supplier registerCreativeModeTab(String modID, String tabName, Supplier tab); - default Holder registerStatusEffect(String modID, String effectName, Supplier statusEffect) { + default Holder registerStatusEffect( + String modID, + String effectName, + Supplier statusEffect + ) { return null; } @@ -52,7 +68,12 @@ default Supplier registerFluid(String modID, String fluidNa return null; } - Supplier makeSpawnEggFor(Supplier> entityType, int primaryEggColour, int secondaryEggColour, Item.Properties itemProperties); + Supplier makeSpawnEggFor( + Supplier> entityType, + int primaryEggColour, + int secondaryEggColour, + Item.Properties itemProperties + ); CreativeModeTab.Builder newCreativeTabBuilder(); } diff --git a/common/src/main/java/mod/azure/azurelib/common/platform/services/IPlatformHelper.java b/common/src/main/java/mod/azure/azurelib/common/platform/services/IPlatformHelper.java index d78bf008d..49253aa73 100644 --- a/common/src/main/java/mod/azure/azurelib/common/platform/services/IPlatformHelper.java +++ b/common/src/main/java/mod/azure/azurelib/common/platform/services/IPlatformHelper.java @@ -1,10 +1,6 @@ package mod.azure.azurelib.common.platform.services; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; import net.minecraft.core.component.DataComponentType; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.level.block.entity.BlockEntityType; import java.nio.file.Path; import java.util.function.Supplier; @@ -22,5 +18,8 @@ public interface IPlatformHelper { boolean isEnvironmentClient(); - Supplier> registerDataComponent(String id, UnaryOperator> builder); + Supplier> registerDataComponent( + String id, + UnaryOperator> builder + ); } diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java b/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java index 6ecb4a43f..4b07b9526 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/GeoAnimatable.java @@ -1,18 +1,17 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable; +import org.jetbrains.annotations.Nullable; + import mod.azure.azurelib.core.animatable.instance.AnimatableInstanceCache; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.AnimationController; import mod.azure.azurelib.core.animation.AnimationProcessor; -import org.jetbrains.annotations.Nullable; /** * This is the root interface for all animatable objects in AzureLib. Generally speaking you should use one of the @@ -23,7 +22,10 @@ *

  • {@code GeoEntity}
  • *
  • {@code GeoItem}
  • * + * + * @deprecated */ +@Deprecated(forRemoval = true) public interface GeoAnimatable { /** diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java index 92ad6b7d6..7cf873c3d 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/AnimatableInstanceCache.java @@ -1,13 +1,15 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.instance; import com.google.common.base.Suppliers; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + import mod.azure.azurelib.common.internal.client.RenderProvider; import mod.azure.azurelib.common.internal.common.animatable.SingletonGeoAnimatable; import mod.azure.azurelib.common.platform.Services; @@ -15,23 +17,27 @@ import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.object.DataTicket; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; - /** * The base cache class responsible for returning the {@link AnimatableManager} for a given instanceof of a * {@link GeoAnimatable}. This class is abstracted and not intended for direct use. See either * {@link SingletonAnimatableInstanceCache} or {@link InstancedAnimatableInstanceCache} + * + * @deprecated */ +@Deprecated(forRemoval = true) public abstract class AnimatableInstanceCache { protected final GeoAnimatable animatable; + protected final Supplier renderProvider; protected AnimatableInstanceCache(GeoAnimatable animatable) { this.animatable = animatable; this.renderProvider = Suppliers.memoize(() -> { - if (!(this.animatable instanceof SingletonGeoAnimatable singleton) || !Services.PLATFORM.isEnvironmentClient()) + if ( + !(this.animatable instanceof SingletonGeoAnimatable singleton) || !Services.PLATFORM + .isEnvironmentClient() + ) return null; final AtomicReference consumer = new AtomicReference<>(RenderProvider.DEFAULT); @@ -75,7 +81,8 @@ public D getDataPoint(long uniqueId, DataTicket dataTicket) { /** * Get the {@link RenderProvider} for this animatable *

    - * Because only {@link SingletonGeoAnimatable}s use this functionality, it this method should not be used and will always return null for anything other than a SingletonGeoAnimatable + * Because only {@link SingletonGeoAnimatable}s use this functionality, it this method should not be used and will + * always return null for anything other than a SingletonGeoAnimatable *

    * The returned object is upcast to Object for side-safety * diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java index 4f373f4b4..8f227ca6a 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/InstancedAnimatableInstanceCache.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.instance; @@ -13,7 +11,10 @@ /** * AnimatableInstanceCache implementation for instantiated objects such as Entities or BlockEntities. Returns a single * {@link AnimatableManager} instance per cache. + * + * @deprecated */ +@Deprecated(forRemoval = true) public class InstancedAnimatableInstanceCache extends AnimatableInstanceCache { protected AnimatableManager manager; diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java index 64c11ae0c..9fbf88998 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/instance/SingletonAnimatableInstanceCache.java @@ -1,21 +1,23 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.instance; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; + import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimatableManager; /** * AnimatableInstanceCache implementation for singleton/flyweight objects such as Items. Utilises a keyed map to * differentiate different instances of the object. + * + * @deprecated */ +@Deprecated(forRemoval = true) public class SingletonAnimatableInstanceCache extends AnimatableInstanceCache { protected final Long2ObjectMap> managers = new Long2ObjectOpenHashMap<>(); diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java index c524a9935..e97aa9a07 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreBakedGeoModel.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.model; @@ -13,6 +11,8 @@ /** * Baked model object for AzureLib models.
    * Mostly an internal placeholder to allow for splitting up core (non-Minecraft) libraries + * + * @deprecated Use {@link mod.azure.azurelib.core2.model.AzBakedModel} instead. */ public interface CoreBakedGeoModel { diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java index 513f843b9..7ee553f15 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoBone.java @@ -1,19 +1,19 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.model; -import mod.azure.azurelib.core.state.BoneSnapshot; - import java.util.List; +import mod.azure.azurelib.core.state.BoneSnapshot; + /** * Base class for AzureLib {@link CoreGeoModel model} bones.
    * Mostly a placeholder to allow for splitting up core (non-Minecraft) libraries + * + * @deprecated */ public interface CoreGeoBone { diff --git a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java index 6669ec019..64cf4262d 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java +++ b/common/src/main/java/mod/azure/azurelib/core/animatable/model/CoreGeoModel.java @@ -1,23 +1,23 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animatable.model; +import java.util.Optional; + import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animation.AnimatableManager; import mod.azure.azurelib.core.animation.Animation; import mod.azure.azurelib.core.animation.AnimationProcessor; import mod.azure.azurelib.core.animation.AnimationState; -import java.util.Optional; - /** * Base class for AzureLib models.
    * Mostly an internal placeholder to allow for splitting up core (non-Minecraft) libraries + * + * @deprecated */ public interface CoreGeoModel { @@ -70,8 +70,7 @@ default Optional getBone(String name) { * @param animationState An {@link AnimationState} instance created to hold animation data for the * {@code animatable} for this method call */ - default void setCustomAnimations(E animatable, long instanceId, AnimationState animationState) { - } + default void setCustomAnimations(E animatable, long instanceId, AnimationState animationState) {} /** * This method is called once per render frame for each {@link GeoAnimatable} being rendered.
    @@ -81,6 +80,5 @@ default void setCustomAnimations(E animatable, long instanceId, AnimationState * Generally speaking, a single working-instance of an {@link GeoAnimatable Animatable} will have a single instance of * {@code AnimatableManager} associated with it.
    + * + * @deprecated */ +@Deprecated(forRemoval = true) public class AnimatableManager { private final Map boneSnapshotCollection = new Object2ObjectOpenHashMap<>(); @@ -180,7 +182,7 @@ public ControllerRegistrar remove(String name) { private Object2ObjectArrayMap> build() { Object2ObjectArrayMap> map = new Object2ObjectArrayMap<>( - this.controllers.size() + this.controllers.size() ); this.controllers.forEach(controller -> map.put(controller.getName(), controller)); diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java index fa78b85b6..89b5391df 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/Animation.java @@ -1,44 +1,49 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.keyframe.BoneAnimation; import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - /** * A compiled animation instance for use by the {@link AnimationController}
    * Modifications or extensions of a compiled Animation are not supported, and therefore an instance of * Animation is considered final and immutable. + * + * @deprecated */ +@Deprecated(forRemoval = true) public record Animation( - String name, - double length, - LoopType loopType, - BoneAnimation[] boneAnimations, - Keyframes keyFrames + String name, + double length, + LoopType loopType, + BoneAnimation[] boneAnimations, + Keyframes keyFrames ) { - static Animation generateWaitAnimation(double length) { + public static Animation generateWaitAnimation(double length) { return new Animation( - RawAnimation.Stage.WAIT, - length, - LoopType.PLAY_ONCE, - new BoneAnimation[0], - new Keyframes(new SoundKeyframeData[0], new ParticleKeyframeData[0], - new CustomInstructionKeyframeData[0]) + RawAnimation.Stage.WAIT, + length, + LoopType.PLAY_ONCE, + new BoneAnimation[0], + new Keyframes( + new SoundKeyframeData[0], + new ParticleKeyframeData[0], + new CustomInstructionKeyframeData[0] + ) ); } @@ -53,11 +58,11 @@ public interface LoopType { final Map LOOP_TYPES = new ConcurrentHashMap<>(4); LoopType DEFAULT = (animatable, controller, currentAnimation) -> currentAnimation.loopType() - .shouldPlayAgain(animatable, controller, currentAnimation); + .shouldPlayAgain(animatable, controller, currentAnimation); LoopType PLAY_ONCE = register( - "play_once", - register("false", (animatable, controller, currentAnimation) -> false) + "play_once", + register("false", (animatable, controller, currentAnimation) -> false) ); LoopType HOLD_ON_LAST_FRAME = register("hold_on_last_frame", (animatable, controller, currentAnimation) -> { @@ -120,16 +125,15 @@ static LoopType register(String name, LoopType loopType) { * @return Whether the animation should play again, or stop */ boolean shouldPlayAgain( - GeoAnimatable animatable, - AnimationController controller, - Animation currentAnimation + GeoAnimatable animatable, + AnimationController controller, + Animation currentAnimation ); } public record Keyframes( - SoundKeyframeData[] sounds, - ParticleKeyframeData[] particles, - CustomInstructionKeyframeData[] customInstructions - ) { - } + SoundKeyframeData[] sounds, + ParticleKeyframeData[] particles, + CustomInstructionKeyframeData[] customInstructions + ) {} } diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java index 6da9f63af..400e2e236 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationController.java @@ -1,14 +1,19 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; +import java.util.function.Function; +import java.util.function.ToDoubleFunction; + import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; import mod.azure.azurelib.core.animatable.model.CoreGeoModel; @@ -27,18 +32,15 @@ import mod.azure.azurelib.core.object.Axis; import mod.azure.azurelib.core.object.PlayState; import mod.azure.azurelib.core.state.BoneSnapshot; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; -import java.util.function.Function; -import java.util.function.ToDoubleFunction; /** * The actual controller that handles the playing and usage of animations, including their various keyframes and * instruction markers. Each controller can only play a single animation at a time - for example you may have one * controller to animate walking, one to control attacks, one to control size, etc. + * + * @deprecated */ +@Deprecated(forRemoval = true) public class AnimationController { protected static final Logger LOGGER = LoggerFactory.getLogger(AnimationController.class); @@ -52,16 +54,27 @@ public class AnimationController { protected final Map boneAnimationQueues = new Object2ObjectOpenHashMap<>(); protected final Map boneSnapshots = new Object2ObjectOpenHashMap<>(); + protected final Map triggerableAnimations = new Object2ObjectOpenHashMap<>(0); + protected final Set executedKeyFrames = new ObjectOpenHashSet<>(); + protected Queue animationQueue = new LinkedList<>(); + protected boolean isJustStarting = false; + protected boolean needsAnimationReload = false; + protected boolean shouldResetTick = false; + protected boolean justStartedTransition = false; + protected SoundKeyframeHandler soundKeyframeHandler = null; + protected ParticleKeyframeHandler particleKeyframeHandler = null; + protected CustomKeyframeHandler customKeyframeHandler = null; + protected RawAnimation triggeredAnimation = null; protected boolean handlingTriggeredAnimations = false; @@ -79,7 +92,9 @@ public class AnimationController { protected ToDoubleFunction animationSpeedModifier = obj -> 1d; protected Function overrideEasingTypeFunction = obj -> null; + protected CoreGeoModel lastModel; + protected boolean justStopped = true; /** @@ -132,10 +147,10 @@ public AnimationController(T animatable, int transitionTickTime, AnimationStateH * which animations to play */ public AnimationController( - T animatable, - String name, - int transitionTickTime, - AnimationStateHandler animationHandler + T animatable, + String name, + int transitionTickTime, + AnimationStateHandler animationHandler ) { this.animatable = animatable; this.name = name; @@ -174,7 +189,7 @@ public AnimationController setParticleKeyframeHandler(ParticleKeyframeHandler * @return this */ public AnimationController setCustomInstructionKeyframeHandler( - CustomKeyframeHandler customInstructionHandler + CustomKeyframeHandler customInstructionHandler ) { this.customKeyframeHandler = customInstructionHandler; @@ -196,6 +211,10 @@ public AnimationController setAnimationSpeedHandler(ToDoubleFunction speed return this; } + public void setJustStarting(boolean justStarting) { + isJustStarting = justStarting; + } + /** * Sets the controller's {@link EasingType} override for animations.
    * By default, the controller will use whatever {@code EasingType} was defined in the animation json @@ -207,6 +226,10 @@ public AnimationController setOverrideEasingType(EasingType easingTypeFunctio return setOverrideEasingTypeFunction(obj -> easingTypeFunction); } + public Function getOverrideEasingTypeFunction() { + return overrideEasingTypeFunction; + } + /** * Sets the controller's {@link EasingType} override function for animations.
    * By default, the controller will use whatever {@code EasingType} was defined in the animation json @@ -379,7 +402,7 @@ public void setAnimation(RawAnimation rawAnimation) { if (this.needsAnimationReload || !rawAnimation.equals(this.currentRawAnimation)) { if (this.lastModel != null) { Queue animations = this.lastModel.getAnimationProcessor() - .buildAnimationQueue(this.animatable, rawAnimation); + .buildAnimationQueue(this.animatable, rawAnimation); if (animations != null) { this.animationQueue = animations; @@ -432,9 +455,9 @@ protected PlayState handleAnimationState(AnimationState state) { setAnimation(this.triggeredAnimation); if ( - !hasAnimationFinished() && (!this.handlingTriggeredAnimations || this.stateHandler.handle( - state - ) == PlayState.CONTINUE) + !hasAnimationFinished() && (!this.handlingTriggeredAnimations || this.stateHandler.handle( + state + ) == PlayState.CONTINUE) ) return PlayState.CONTINUE; @@ -458,12 +481,12 @@ protected PlayState handleAnimationState(AnimationState state) { * bones */ public void process( - CoreGeoModel model, - AnimationState state, - Map bones, - Map snapshots, - final double seekTime, - boolean crashWhenCantFindBone + CoreGeoModel model, + AnimationState state, + Map bones, + Map snapshots, + final double seekTime, + boolean crashWhenCantFindBone ) { double adjustedTick = adjustTick(seekTime); this.lastModel = model; @@ -537,38 +560,38 @@ public void process( if (!rotationKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addNextRotation( - null, - adjustedTick, - this.transitionLength, - boneSnapshot, - bone.getInitialSnapshot(), - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) + null, + adjustedTick, + this.transitionLength, + boneSnapshot, + bone.getInitialSnapshot(), + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), 0, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), 0, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), 0, true, Axis.Z) ); } if (!positionKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addNextPosition( - null, - adjustedTick, - this.transitionLength, - boneSnapshot, - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) + null, + adjustedTick, + this.transitionLength, + boneSnapshot, + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), 0, false, Axis.Z) ); } if (!scaleKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addNextScale( - null, - adjustedTick, - this.transitionLength, - boneSnapshot, - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) + null, + adjustedTick, + this.transitionLength, + boneSnapshot, + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), 0, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), 0, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), 0, false, Axis.Z) ); } } @@ -587,8 +610,8 @@ public void process( protected void processCurrentAnimation(double adjustedTick, double seekTime, boolean crashWhenCantFindBone) { if (adjustedTick >= this.currentAnimation.animation().length()) { if ( - this.currentAnimation.loopType() - .shouldPlayAgain(this.animatable, this, this.currentAnimation.animation()) + this.currentAnimation.loopType() + .shouldPlayAgain(this.animatable, this, this.currentAnimation.animation()) ) { if (this.animationState != State.PAUSED) { this.shouldResetTick = true; @@ -633,25 +656,25 @@ protected void processCurrentAnimation(double adjustedTick, double seekTime, boo if (!rotationKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addRotations( - getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), - getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), - getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) + getAnimationPointAtTick(rotationKeyFrames.xKeyframes(), adjustedTick, true, Axis.X), + getAnimationPointAtTick(rotationKeyFrames.yKeyframes(), adjustedTick, true, Axis.Y), + getAnimationPointAtTick(rotationKeyFrames.zKeyframes(), adjustedTick, true, Axis.Z) ); } if (!positionKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addPositions( - getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + getAnimationPointAtTick(positionKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(positionKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(positionKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) ); } if (!scaleKeyFrames.xKeyframes().isEmpty()) { boneAnimationQueue.addScales( - getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), - getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), - getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) + getAnimationPointAtTick(scaleKeyFrames.xKeyframes(), adjustedTick, false, Axis.X), + getAnimationPointAtTick(scaleKeyFrames.yKeyframes(), adjustedTick, false, Axis.Y), + getAnimationPointAtTick(scaleKeyFrames.zKeyframes(), adjustedTick, false, Axis.Z) ); } } @@ -662,15 +685,15 @@ protected void processCurrentAnimation(double adjustedTick, double seekTime, boo if (adjustedTick >= keyframeData.getStartTick() && this.executedKeyFrames.add(keyframeData)) { if (this.soundKeyframeHandler == null) { LOGGER.warn( - "Sound Keyframe found for {} -> {}, but no keyframe handler registered", - this.animatable.getClass().getSimpleName(), - getName() + "Sound Keyframe found for {} -> {}, but no keyframe handler registered", + this.animatable.getClass().getSimpleName(), + getName() ); break; } this.soundKeyframeHandler.handle( - new SoundKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) + new SoundKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) ); } } @@ -679,36 +702,36 @@ protected void processCurrentAnimation(double adjustedTick, double seekTime, boo if (adjustedTick >= keyframeData.getStartTick() && this.executedKeyFrames.add(keyframeData)) { if (this.particleKeyframeHandler == null) { LOGGER.warn( - "Particle Keyframe found for {} -> {}, but no keyframe handler registered", - this.animatable.getClass().getSimpleName(), - getName() + "Particle Keyframe found for {} -> {}, but no keyframe handler registered", + this.animatable.getClass().getSimpleName(), + getName() ); break; } this.particleKeyframeHandler.handle( - new ParticleKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) + new ParticleKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) ); } } for ( - CustomInstructionKeyframeData keyframeData : this.currentAnimation.animation() + CustomInstructionKeyframeData keyframeData : this.currentAnimation.animation() .keyFrames() .customInstructions() ) { if (adjustedTick >= keyframeData.getStartTick() && this.executedKeyFrames.add(keyframeData)) { if (this.customKeyframeHandler == null) { LOGGER.warn( - "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", - this.animatable.getClass().getSimpleName(), - getName() + "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", + this.animatable.getClass().getSimpleName(), + getName() ); break; } this.customKeyframeHandler.handle( - new CustomInstructionKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) + new CustomInstructionKeyframeEvent<>(this.animatable, adjustedTick, this, keyframeData) ); } } @@ -739,8 +762,8 @@ protected void createInitialQueues(Collection modelRendererList) { * @param snapshots The master snapshot collection to pull filter from */ protected void saveSnapshotsForAnimation( - AnimationProcessor.QueuedAnimation animation, - Map snapshots + AnimationProcessor.QueuedAnimation animation, + Map snapshots ) { if (animation.animation().boneAnimations() == null) { return; @@ -762,7 +785,7 @@ protected void saveSnapshotsForAnimation( * * @param tick The currently used tick value * @return 0 if {@link AnimationController#shouldResetTick} is set to false, or a - * {@link AnimationController#animationSpeedModifier} modified value otherwise + * {@link AnimationController#animationSpeedModifier} modified value otherwise */ protected double adjustTick(double tick) { if (!this.shouldResetTick) @@ -780,10 +803,10 @@ protected double adjustTick(double tick) { * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} */ protected AnimationPoint getAnimationPointAtTick( - List> frames, - double tick, - boolean isRotation, - Axis axis + List> frames, + double tick, + boolean isRotation, + Axis axis ) { KeyframeLocation> location = getCurrentKeyFrameLocation(frames, tick); Keyframe currentFrame = location.keyframe(); @@ -817,8 +840,8 @@ protected AnimationPoint getAnimationPointAtTick( * @return A new {@code KeyFrameLocation} containing the current {@code KeyFrame} and the tick time used to find it */ protected KeyframeLocation> getCurrentKeyFrameLocation( - List> frames, - double ageInTicks + List> frames, + double ageInTicks ) { double totalFrameTime = 0; diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java index ae2517605..5363da646 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationProcessor.java @@ -1,13 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + import mod.azure.azurelib.core.animatable.GeoAnimatable; import mod.azure.azurelib.core.animatable.model.CoreBakedGeoModel; import mod.azure.azurelib.core.animatable.model.CoreGeoBone; @@ -16,11 +19,11 @@ import mod.azure.azurelib.core.keyframe.BoneAnimationQueue; import mod.azure.azurelib.core.state.BoneSnapshot; import mod.azure.azurelib.core.utils.Interpolations; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; +/** + * @deprecated + */ +@Deprecated(forRemoval = true) public class AnimationProcessor { private static final Logger LOGGER = LoggerFactory.getLogger(AnimationProcessor.class); @@ -56,9 +59,9 @@ public Queue buildAnimationQueue(T animatable, RawAnimation raw if (animation == null) { LOGGER.warn( - "Unable to find animation: {} for {}", - stage.animationName(), - animatable.getClass().getSimpleName() + "Unable to find animation: {} for {}", + stage.animationName(), + animatable.getClass().getSimpleName() ); return null; } else { @@ -81,12 +84,12 @@ public Queue buildAnimationQueue(T animatable, RawAnimation raw * remaining bones */ public void tickAnimation( - T animatable, - CoreGeoModel model, - AnimatableManager animatableManager, - double animTime, - AnimationState event, - boolean crashWhenCantFindBone + T animatable, + CoreGeoModel model, + AnimatableManager animatableManager, + double animTime, + AnimationState event, + boolean crashWhenCantFindBone ) { Map boneSnapshots = updateBoneSnapshots(animatableManager.getBoneSnapshotCollection()); @@ -119,13 +122,13 @@ public void tickAnimation( if (rotXPoint != null && rotYPoint != null && rotZPoint != null) { bone.setRotX( - (float) EasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() + (float) EasingType.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() ); bone.setRotY( - (float) EasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() + (float) EasingType.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() ); bone.setRotZ( - (float) EasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() + (float) EasingType.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() ); snapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); snapshot.startRotAnim(); @@ -164,18 +167,18 @@ public void tickAnimation( saveSnapshot.stopRotAnim(animTime); double percentageReset = Math.min( - (animTime - saveSnapshot.getLastResetRotationTick()) / resetTickLength, - 1 + (animTime - saveSnapshot.getLastResetRotationTick()) / resetTickLength, + 1 ); bone.setRotX( - (float) Interpolations.lerp(saveSnapshot.getRotX(), initialSnapshot.getRotX(), percentageReset) + (float) Interpolations.lerp(saveSnapshot.getRotX(), initialSnapshot.getRotX(), percentageReset) ); bone.setRotY( - (float) Interpolations.lerp(saveSnapshot.getRotY(), initialSnapshot.getRotY(), percentageReset) + (float) Interpolations.lerp(saveSnapshot.getRotY(), initialSnapshot.getRotY(), percentageReset) ); bone.setRotZ( - (float) Interpolations.lerp(saveSnapshot.getRotZ(), initialSnapshot.getRotZ(), percentageReset) + (float) Interpolations.lerp(saveSnapshot.getRotZ(), initialSnapshot.getRotZ(), percentageReset) ); if (percentageReset >= 1) @@ -190,30 +193,30 @@ public void tickAnimation( saveSnapshot.stopPosAnim(animTime); double percentageReset = Math.min( - (animTime - saveSnapshot.getLastResetPositionTick()) / resetTickLength, - 1 + (animTime - saveSnapshot.getLastResetPositionTick()) / resetTickLength, + 1 ); bone.setPosX( - (float) Interpolations.lerp( - saveSnapshot.getOffsetX(), - initialSnapshot.getOffsetX(), - percentageReset - ) + (float) Interpolations.lerp( + saveSnapshot.getOffsetX(), + initialSnapshot.getOffsetX(), + percentageReset + ) ); bone.setPosY( - (float) Interpolations.lerp( - saveSnapshot.getOffsetY(), - initialSnapshot.getOffsetY(), - percentageReset - ) + (float) Interpolations.lerp( + saveSnapshot.getOffsetY(), + initialSnapshot.getOffsetY(), + percentageReset + ) ); bone.setPosZ( - (float) Interpolations.lerp( - saveSnapshot.getOffsetZ(), - initialSnapshot.getOffsetZ(), - percentageReset - ) + (float) Interpolations.lerp( + saveSnapshot.getOffsetZ(), + initialSnapshot.getOffsetZ(), + percentageReset + ) ); if (percentageReset >= 1) @@ -228,21 +231,30 @@ public void tickAnimation( saveSnapshot.stopScaleAnim(animTime); double percentageReset = Math.min( - (animTime - saveSnapshot.getLastResetScaleTick()) / resetTickLength, - 1 + (animTime - saveSnapshot.getLastResetScaleTick()) / resetTickLength, + 1 ); bone.setScaleX( - (float) Interpolations.lerp(saveSnapshot.getScaleX(), initialSnapshot.getScaleX(), - percentageReset) + (float) Interpolations.lerp( + saveSnapshot.getScaleX(), + initialSnapshot.getScaleX(), + percentageReset + ) ); bone.setScaleY( - (float) Interpolations.lerp(saveSnapshot.getScaleY(), initialSnapshot.getScaleY(), - percentageReset) + (float) Interpolations.lerp( + saveSnapshot.getScaleY(), + initialSnapshot.getScaleY(), + percentageReset + ) ); bone.setScaleZ( - (float) Interpolations.lerp(saveSnapshot.getScaleZ(), initialSnapshot.getScaleZ(), - percentageReset) + (float) Interpolations.lerp( + saveSnapshot.getScaleZ(), + initialSnapshot.getScaleZ(), + percentageReset + ) ); if (percentageReset >= 1) @@ -327,8 +339,7 @@ public void preAnimationSetup(T animatable, double animTime) { * {@link GeoAnimatable} */ public record QueuedAnimation( - Animation animation, - Animation.LoopType loopType - ) { - } + Animation animation, + Animation.LoopType loopType + ) {} } diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java index 5e3d2fba2..4e0d90671 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/AnimationState.java @@ -1,25 +1,27 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.object.DataTicket; -import mod.azure.azurelib.core.object.PlayState; import java.util.Map; import java.util.Objects; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.object.DataTicket; +import mod.azure.azurelib.core.object.PlayState; + /** * Animation state handler for end-users.
    * This is where users would set their selected animation to play, stop the controller, or any number of other * animation-related actions. + * + * @deprecated */ +@Deprecated(forRemoval = true) public class AnimationState { private final T animatable; @@ -33,7 +35,9 @@ public class AnimationState { private final boolean isMoving; private final Map, Object> extraData = new Object2ObjectOpenHashMap<>(); + public double animationTick; + protected AnimationController controller; public AnimationState(T animatable, float limbSwing, float limbSwingAmount, float partialTick, boolean isMoving) { @@ -174,9 +178,9 @@ public boolean isCurrentAnimation(RawAnimation animation) { */ public boolean isCurrentAnimationStage(String name) { return getController().getCurrentAnimation() != null && getController().getCurrentAnimation() - .animation() - .name() - .equals(name); + .animation() + .name() + .equals(name); } /** diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java b/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java index c3dd6cbdb..d2dd236da 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/ContextAwareAnimatableManager.java @@ -1,25 +1,27 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; -import mod.azure.azurelib.core.animatable.GeoAnimatable; -import mod.azure.azurelib.core.object.DataTicket; -import mod.azure.azurelib.core.state.BoneSnapshot; import org.jetbrains.annotations.Nullable; import java.util.Map; +import mod.azure.azurelib.core.animatable.GeoAnimatable; +import mod.azure.azurelib.core.object.DataTicket; +import mod.azure.azurelib.core.state.BoneSnapshot; + /** * Context-aware wrapper for {@link AnimatableManager}.
    * This can be used for things like perspective-dependent animation handling and other similar functionality.
    * This relies entirely on data present in {@link AnimatableManager#extraData} saved to this manager to determine * context + * + * @deprecated */ +@Deprecated(forRemoval = true) public abstract class ContextAwareAnimatableManager extends AnimatableManager { private final Map> managers; diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java b/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java index 7d52da261..4f5ba381b 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/EasingType.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; @@ -10,14 +8,15 @@ import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; -import mod.azure.azurelib.core.keyframe.AnimationPoint; -import mod.azure.azurelib.core.keyframe.Keyframe; -import mod.azure.azurelib.core.utils.Interpolations; import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import mod.azure.azurelib.core.keyframe.AnimationPoint; +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.utils.Interpolations; + /** * Functional interface defining an easing function.
    * {@code value} is the easing value provided from the keyframe's {@link Keyframe#easingArgs()}
    @@ -25,6 +24,8 @@ * For more information on easings, see:
    * Easings.net
    * Cubic-Bezier.com
    + * + * @deprecated */ @FunctionalInterface public interface EasingType { @@ -158,8 +159,8 @@ static Double2DoubleFunction linear(Double2DoubleFunction function) { */ static double catmullRom(double n) { return (0.5f * (2.0f * (n + 1) + ((n + 2) - n) * 1 - + (2.0f * n - 5.0f * (n + 1) + 4.0f * (n + 2) - (n + 3)) * 1 - + (3.0f * (n + 1) - n - 3.0f * (n + 2) + (n + 3)) * 1)); + + (2.0f * n - 5.0f * (n + 1) + 4.0f * (n + 2) - (n + 3)) * 1 + + (3.0f * (n + 1) - n - 3.0f * (n + 2) + (n + 3)) * 1)); } /** @@ -393,9 +394,9 @@ default double apply(AnimationPoint animationPoint, Double easingValue, double l return (float) animationPoint.animationEndValue(); return Interpolations.lerp( - animationPoint.animationStartValue(), - animationPoint.animationEndValue(), - buildTransformer(easingValue).apply(lerpValue) + animationPoint.animationStartValue(), + animationPoint.animationEndValue(), + buildTransformer(easingValue).apply(lerpValue) ); } } diff --git a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java index d5ef9a6f7..a0b1e0426 100644 --- a/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core/animation/RawAnimation.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.animation; @@ -25,14 +23,16 @@ *

    {@code
      * RawAnimation.begin().thenPlay("action.open_box").thenLoop("state.stay_open")
      * }
    + * + * @deprecated */ +@Deprecated(forRemoval = true) public final class RawAnimation { private final List animationList = new ObjectArrayList<>(); // Private constructor to force usage of factory for logical operations - private RawAnimation() { - } + private RawAnimation() {} /** * Start a new RawAnimation instance. This is the start point for creating an animation chain. @@ -155,12 +155,12 @@ public int hashCode() { * This is an entry object representing a single animation stage of the final compiled animation. */ public record Stage( - String animationName, - Animation.LoopType loopType, - int additionalTicks + String animationName, + Animation.LoopType loopType, + int additionalTicks ) { - static final String WAIT = "internal.wait"; + public static final String WAIT = "internal.wait"; public Stage(String animationName, Animation.LoopType loopType) { this(animationName, loopType, 0); diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPoint.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPoint.java index 2ebd53460..12ff3ae33 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPoint.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPoint.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; @@ -17,18 +15,18 @@ * @param keyFrame The {@code Nullable} Keyframe */ public record AnimationPoint( - Keyframe keyFrame, - double currentTick, - double transitionLength, - double animationStartValue, - double animationEndValue + Keyframe keyFrame, + double currentTick, + double transitionLength, + double animationStartValue, + double animationEndValue ) { @Override public String toString() { return "Tick: " + this.currentTick + - " | Transition Length: " + this.transitionLength + - " | Start Value: " + this.animationStartValue + - " | End Value: " + this.animationEndValue; + " | Transition Length: " + this.transitionLength + + " | Start Value: " + this.animationStartValue + + " | End Value: " + this.animationEndValue; } } diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPointQueue.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPointQueue.java index be0d1fe8b..847468036 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPointQueue.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/AnimationPointQueue.java @@ -1,17 +1,15 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; -import mod.azure.azurelib.core.animation.AnimationController; - import java.io.Serial; import java.util.LinkedList; +import mod.azure.azurelib.core.animation.AnimationController; + /** * An {@link AnimationPoint} queue holds a queue of {@code AnimationPoints} which are used in the * {@link AnimationController} to lerp between values diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimation.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimation.java index e3b5b38e1..5c7a26efa 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimation.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimation.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; @@ -19,9 +17,8 @@ * @param scaleKeyFrames The deserialized scale {@code Keyframe} stack */ public record BoneAnimation( - String boneName, - KeyframeStack> rotationKeyFrames, - KeyframeStack> positionKeyFrames, - KeyframeStack> scaleKeyFrames -) { -} + String boneName, + KeyframeStack> rotationKeyFrames, + KeyframeStack> positionKeyFrames, + KeyframeStack> scaleKeyFrames +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimationQueue.java index 5904f694e..9c4a62d87 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimationQueue.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/BoneAnimationQueue.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; @@ -16,30 +14,30 @@ * onto their respective queues to be used for transformations in rendering */ public record BoneAnimationQueue( - CoreGeoBone bone, - AnimationPointQueue rotationXQueue, - AnimationPointQueue rotationYQueue, - AnimationPointQueue rotationZQueue, - AnimationPointQueue positionXQueue, - AnimationPointQueue positionYQueue, - AnimationPointQueue positionZQueue, - AnimationPointQueue scaleXQueue, - AnimationPointQueue scaleYQueue, - AnimationPointQueue scaleZQueue + CoreGeoBone bone, + AnimationPointQueue rotationXQueue, + AnimationPointQueue rotationYQueue, + AnimationPointQueue rotationZQueue, + AnimationPointQueue positionXQueue, + AnimationPointQueue positionYQueue, + AnimationPointQueue positionZQueue, + AnimationPointQueue scaleXQueue, + AnimationPointQueue scaleYQueue, + AnimationPointQueue scaleZQueue ) { public BoneAnimationQueue(CoreGeoBone bone) { this( - bone, - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue(), - new AnimationPointQueue() + bone, + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue(), + new AnimationPointQueue() ); } @@ -53,11 +51,11 @@ public BoneAnimationQueue(CoreGeoBone bone) { * @param endValue The value of the point at the end of its transition */ public void addPosXPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.positionXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -72,11 +70,11 @@ public void addPosXPoint( * @param endValue The value of the point at the end of its transition */ public void addPosYPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.positionYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -91,11 +89,11 @@ public void addPosYPoint( * @param endValue The value of the point at the end of its transition */ public void addPosZPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.positionZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -116,34 +114,34 @@ public void addPosZPoint( * new point */ public void addNextPosition( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - BoneSnapshot startSnapshot, - AnimationPoint nextXPoint, - AnimationPoint nextYPoint, - AnimationPoint nextZPoint + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + BoneSnapshot startSnapshot, + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint ) { addPosXPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getOffsetX(), - nextXPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getOffsetX(), + nextXPoint.animationStartValue() ); addPosYPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getOffsetY(), - nextYPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getOffsetY(), + nextYPoint.animationStartValue() ); addPosZPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getOffsetZ(), - nextZPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getOffsetZ(), + nextZPoint.animationStartValue() ); } @@ -157,11 +155,11 @@ public void addNextPosition( * @param endValue The value of the point at the end of its transition */ public void addScaleXPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.scaleXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -176,11 +174,11 @@ public void addScaleXPoint( * @param endValue The value of the point at the end of its transition */ public void addScaleYPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.scaleYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -195,11 +193,11 @@ public void addScaleYPoint( * @param endValue The value of the point at the end of its transition */ public void addScaleZPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.scaleZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -220,34 +218,34 @@ public void addScaleZPoint( * new point */ public void addNextScale( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - BoneSnapshot startSnapshot, - AnimationPoint nextXPoint, - AnimationPoint nextYPoint, - AnimationPoint nextZPoint + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + BoneSnapshot startSnapshot, + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint ) { addScaleXPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getScaleX(), - nextXPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getScaleX(), + nextXPoint.animationStartValue() ); addScaleYPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getScaleY(), - nextYPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getScaleY(), + nextYPoint.animationStartValue() ); addScaleZPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getScaleZ(), - nextZPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getScaleZ(), + nextZPoint.animationStartValue() ); } @@ -261,11 +259,11 @@ public void addNextScale( * @param endValue The value of the point at the end of its transition */ public void addRotationXPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.rotationXQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -280,11 +278,11 @@ public void addRotationXPoint( * @param endValue The value of the point at the end of its transition */ public void addRotationYPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.rotationYQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -299,11 +297,11 @@ public void addRotationYPoint( * @param endValue The value of the point at the end of its transition */ public void addRotationZPoint( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - double startValue, - double endValue + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + double startValue, + double endValue ) { this.rotationZQueue.add(new AnimationPoint(keyFrame, lerpedTick, transitionLength, startValue, endValue)); } @@ -325,35 +323,35 @@ public void addRotationZPoint( * new point */ public void addNextRotation( - Keyframe keyFrame, - double lerpedTick, - double transitionLength, - BoneSnapshot startSnapshot, - BoneSnapshot initialSnapshot, - AnimationPoint nextXPoint, - AnimationPoint nextYPoint, - AnimationPoint nextZPoint + Keyframe keyFrame, + double lerpedTick, + double transitionLength, + BoneSnapshot startSnapshot, + BoneSnapshot initialSnapshot, + AnimationPoint nextXPoint, + AnimationPoint nextYPoint, + AnimationPoint nextZPoint ) { addRotationXPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getRotX() - initialSnapshot.getRotX(), - nextXPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getRotX() - initialSnapshot.getRotX(), + nextXPoint.animationStartValue() ); addRotationYPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getRotY() - initialSnapshot.getRotY(), - nextYPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getRotY() - initialSnapshot.getRotY(), + nextYPoint.animationStartValue() ); addRotationZPoint( - keyFrame, - lerpedTick, - transitionLength, - startSnapshot.getRotZ() - initialSnapshot.getRotZ(), - nextZPoint.animationStartValue() + keyFrame, + lerpedTick, + transitionLength, + startSnapshot.getRotZ() - initialSnapshot.getRotZ(), + nextZPoint.animationStartValue() ); } diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/Keyframe.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/Keyframe.java index 89f663a16..891b804a3 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/Keyframe.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/Keyframe.java @@ -1,19 +1,18 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core.animation.EasingType; -import mod.azure.azurelib.core.math.IValue; import java.util.List; import java.util.Objects; +import mod.azure.azurelib.core.animation.EasingType; +import mod.azure.azurelib.core.math.IValue; + /** * Animation keyframe data * @@ -24,11 +23,11 @@ * @param easingArgs The arguments to provide to the easing calculation */ public record Keyframe( - double length, - T startValue, - T endValue, - EasingType easingType, - List easingArgs + double length, + T startValue, + T endValue, + EasingType easingType, + List easingArgs ) { public Keyframe(double length, T startValue, T endValue) { diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeLocation.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeLocation.java index aa287dae6..152ceb28e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeLocation.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeLocation.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; @@ -14,7 +12,6 @@ * @param startTick The animation tick time at the start of this {@code Keyframe} */ public record KeyframeLocation>( - T keyframe, - double startTick -) { -} + T keyframe, + double startTick +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeStack.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeStack.java index 91e3bbc88..34e395108 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeStack.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/KeyframeStack.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe; @@ -15,9 +13,9 @@ * Stores a triplet of {@link Keyframe Keyframes} in an ordered stack */ public record KeyframeStack>( - List xKeyframes, - List yKeyframes, - List zKeyframes + List xKeyframes, + List yKeyframes, + List zKeyframes ) { public KeyframeStack() { diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java index ab024e7cb..870589815 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/CustomInstructionKeyframeEvent.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event; @@ -14,14 +12,17 @@ /** * The {@link KeyFrameEvent} specific to the {@link AnimationController#customKeyframeHandler}.
    * Called when a custom instruction keyframe is encountered + * + * @deprecated Use {@link mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent} instead. */ +@Deprecated(forRemoval = true) public class CustomInstructionKeyframeEvent extends KeyFrameEvent { public CustomInstructionKeyframeEvent( - T entity, - double animationTick, - AnimationController controller, - CustomInstructionKeyframeData customInstructionKeyframeData + T entity, + double animationTick, + AnimationController controller, + CustomInstructionKeyframeData customInstructionKeyframeData ) { super(entity, animationTick, controller, customInstructionKeyframeData); } diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java index 8f8002a42..36e7e4f82 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/KeyFrameEvent.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event; @@ -11,6 +9,7 @@ import mod.azure.azurelib.core.animation.AnimationController; import mod.azure.azurelib.core.keyframe.Keyframe; import mod.azure.azurelib.core.keyframe.event.data.KeyFrameData; +import mod.azure.azurelib.core2.animation.event.AzKeyframeEvent; /** * The base class for {@link Keyframe} events.
    @@ -19,7 +18,9 @@ * @see CustomInstructionKeyframeEvent * @see ParticleKeyframeEvent * @see SoundKeyframeEvent + * @deprecated Use {@link AzKeyframeEvent} instead. */ +@Deprecated(forRemoval = true) public abstract class KeyFrameEvent { private final T animatable; diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java index 08aade003..bdc096098 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/ParticleKeyframeEvent.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event; @@ -14,14 +12,17 @@ /** * The {@link KeyFrameEvent} specific to the {@link AnimationController#particleKeyframeHandler}.
    * Called when a particle instruction keyframe is encountered + * + * @deprecated Use {@link mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent} instead. */ +@Deprecated(forRemoval = true) public class ParticleKeyframeEvent extends KeyFrameEvent { public ParticleKeyframeEvent( - T animatable, - double animationTick, - AnimationController controller, - ParticleKeyframeData particleKeyFrameData + T animatable, + double animationTick, + AnimationController controller, + ParticleKeyframeData particleKeyFrameData ) { super(animatable, animationTick, controller, particleKeyFrameData); } diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java index 01ecf9758..b61df3a96 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/SoundKeyframeEvent.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event; @@ -14,7 +12,10 @@ /** * The {@link KeyFrameEvent} specific to the {@link AnimationController#soundKeyframeHandler}.
    * Called when a sound instruction keyframe is encountered + * + * @deprecated Use {@link mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent} instead. */ +@Deprecated(forRemoval = true) public class SoundKeyframeEvent extends KeyFrameEvent { /** @@ -26,10 +27,10 @@ public class SoundKeyframeEvent extends KeyFrameEvent controller, - SoundKeyframeData keyFrameData + T entity, + double animationTick, + AnimationController controller, + SoundKeyframeData keyFrameData ) { super(entity, animationTick, controller, keyFrameData); } diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/CustomInstructionKeyframeData.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/CustomInstructionKeyframeData.java index 0d23c6d34..f07750361 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/CustomInstructionKeyframeData.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/CustomInstructionKeyframeData.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event.data; -import mod.azure.azurelib.core.keyframe.Keyframe; - import java.util.Objects; +import mod.azure.azurelib.core.keyframe.Keyframe; + /** * Custom instruction {@link Keyframe} instruction holder */ diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/KeyFrameData.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/KeyFrameData.java index 148a17e5d..2572cd91b 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/KeyFrameData.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/KeyFrameData.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event.data; -import mod.azure.azurelib.core.keyframe.Keyframe; - import java.util.Objects; +import mod.azure.azurelib.core.keyframe.Keyframe; + /** * Base class for custom {@link Keyframe} events.
    * diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/ParticleKeyframeData.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/ParticleKeyframeData.java index d9722f898..75b8d807a 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/ParticleKeyframeData.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/ParticleKeyframeData.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event.data; -import mod.azure.azurelib.core.keyframe.Keyframe; - import java.util.Objects; +import mod.azure.azurelib.core.keyframe.Keyframe; + /** * Particle {@link Keyframe} instruction holder */ diff --git a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/SoundKeyframeData.java b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/SoundKeyframeData.java index 5279e2edd..f7dc21846 100644 --- a/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/SoundKeyframeData.java +++ b/common/src/main/java/mod/azure/azurelib/core/keyframe/event/data/SoundKeyframeData.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.keyframe.event.data; -import mod.azure.azurelib.core.keyframe.Keyframe; - import java.util.Objects; +import mod.azure.azurelib.core.keyframe.Keyframe; + /** * Sound {@link Keyframe} instruction holder */ diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Constant.java b/common/src/main/java/mod/azure/azurelib/core/math/Constant.java index ddf2e2d58..ef029f3c6 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Constant.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Constant.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Group.java b/common/src/main/java/mod/azure/azurelib/core/math/Group.java index a236f8962..29cd49e4c 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Group.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Group.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/IValue.java b/common/src/main/java/mod/azure/azurelib/core/math/IValue.java index d915a17f2..6b1383d29 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/IValue.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/IValue.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/MathBuilder.java b/common/src/main/java/mod/azure/azurelib/core/math/MathBuilder.java index 25e954c27..a936d60ad 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/MathBuilder.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/MathBuilder.java @@ -1,12 +1,16 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import mod.azure.azurelib.common.internal.common.AzureLibException; import mod.azure.azurelib.core.math.functions.Function; import mod.azure.azurelib.core.math.functions.classic.*; @@ -19,19 +23,12 @@ import mod.azure.azurelib.core.math.functions.rounding.Trunc; import mod.azure.azurelib.core.math.functions.utility.*; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * Math builder This class is responsible for parsing math expressions provided by user in a string to an {@link IValue} * which can be used to compute some value dynamically using different math operators, variables and functions. It works * by first breaking down given string into a list of tokens and then putting them together in a binary tree-like - * {@link IValue}. - * TODO: maybe implement constant pool (to reuse same values)? - * TODO: maybe pre-compute constant expressions? + * {@link IValue}. TODO: maybe implement constant pool (to reuse same values)? TODO: maybe pre-compute constant + * expressions? */ public class MathBuilder { @@ -127,8 +124,8 @@ public String[] breakdown(String expression) throws AzureLibException { /* Amount of left and right brackets should be the same */ if (left != right) { throw new AzureLibException( - "Given expression '" + expression - + "' has more uneven amount of parenthesis, there are " + left + " open and " + right + " closed!" + "Given expression '" + expression + + "' has more uneven amount of parenthesis, there are " + left + " open and " + right + " closed!" ); } @@ -156,8 +153,8 @@ public List breakdownChars(String[] chars) { boolean isFirst = size == 0 && buffer.isEmpty(); boolean isOperatorBehind = size > 0 - && (this.isOperator(symbols.get(size - 1)) || symbols.get(size - 1).equals(",")) - && buffer.isEmpty(); + && (this.isOperator(symbols.get(size - 1)) || symbols.get(size - 1).equals(",")) + && buffer.isEmpty(); if (isFirst || isOperatorBehind) { buffer += s; @@ -289,9 +286,9 @@ public IValue parseSymbols(List symbols) throws Exception { Operation operation = this.operationForOperator((String) symbols.get(lastOp)); return new Operator( - operation, - this.parseSymbols(symbols.subList(0, lastOp)), - this.parseSymbols(symbols.subList(lastOp + 1, size)) + operation, + this.parseSymbols(symbols.subList(0, lastOp)), + this.parseSymbols(symbols.subList(lastOp + 1, size)) ); } @@ -366,9 +363,9 @@ protected IValue tryTernary(List symbols) throws Exception { if (questions == colons && question > 0 && question + 1 < colon && colon < size - 1) { return new Ternary( - this.parseSymbols(symbols.subList(0, question)), - this.parseSymbols(symbols.subList(question + 1, colon)), - this.parseSymbols(symbols.subList(colon + 1, size)) + this.parseSymbols(symbols.subList(0, question)), + this.parseSymbols(symbols.subList(question + 1, colon)), + this.parseSymbols(symbols.subList(colon + 1, size)) ); } diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Negate.java b/common/src/main/java/mod/azure/azurelib/core/math/Negate.java index c8ad7354e..e8a5b0785 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Negate.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Negate.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Operation.java b/common/src/main/java/mod/azure/azurelib/core/math/Operation.java index a5e4c5a30..10b710099 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Operation.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Operation.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; @@ -12,30 +10,34 @@ /** * Operation enumeration This enumeration provides different hardcoded enumerations of default math operators such - * addition, substraction, multiplication, division, modulo and power. - * TODO: maybe convert to classes (for the sake of API)? + * addition, substraction, multiplication, division, modulo and power. TODO: maybe convert to classes (for the sake of + * API)? */ public enum Operation { ADD("+", 1) { + @Override public double calculate(double a, double b) { return a + b; } }, SUB("-", 1) { + @Override public double calculate(double a, double b) { return a - b; } }, MUL("*", 2) { + @Override public double calculate(double a, double b) { return a * b; } }, DIV("/", 2) { + @Override public double calculate(double a, double b) { /* To avoid any exceptions */ @@ -43,60 +45,70 @@ public double calculate(double a, double b) { } }, MOD("%", 2) { + @Override public double calculate(double a, double b) { return a % b; } }, POW("^", 3) { + @Override public double calculate(double a, double b) { return Math.pow(a, b); } }, AND("&&", 5) { + @Override public double calculate(double a, double b) { return a != 0 && b != 0 ? 1 : 0; } }, OR("||", 5) { + @Override public double calculate(double a, double b) { return a != 0 || b != 0 ? 1 : 0; } }, LESS("<", 5) { + @Override public double calculate(double a, double b) { return a < b ? 1 : 0; } }, LESS_THAN("<=", 5) { + @Override public double calculate(double a, double b) { return a <= b ? 1 : 0; } }, GREATER_THAN(">=", 5) { + @Override public double calculate(double a, double b) { return a >= b ? 1 : 0; } }, GREATER(">", 5) { + @Override public double calculate(double a, double b) { return a > b ? 1 : 0; } }, EQUALS("==", 5) { + @Override public double calculate(double a, double b) { return equals(a, b) ? 1 : 0; } }, NOT_EQUALS("!=", 5) { + @Override public double calculate(double a, double b) { return !equals(a, b) ? 1 : 0; @@ -115,6 +127,7 @@ public double calculate(double a, double b) { * String-ified name of this operation */ public final String sign; + /** * Value of this operation in relation to other operations (i.e precedence importance) */ diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Operator.java b/common/src/main/java/mod/azure/azurelib/core/math/Operator.java index e4b50651e..5c8fb94e2 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Operator.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Operator.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Ternary.java b/common/src/main/java/mod/azure/azurelib/core/math/Ternary.java index 764460b30..3c2c3033a 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Ternary.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Ternary.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/Variable.java b/common/src/main/java/mod/azure/azurelib/core/math/Variable.java index b877e78af..d063b01fc 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/Variable.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/Variable.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/Function.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/Function.java index 9b0679342..845513e7a 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/Function.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/Function.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions; @@ -22,10 +20,10 @@ public abstract class Function implements IValue { protected Function(IValue[] values, String name) throws Exception { if (values.length < this.getRequiredArguments()) { String message = String.format( - "Function '%s' requires at least %s arguments. %s are given!", - this.getName(), - this.getRequiredArguments(), - values.length + "Function '%s' requires at least %s arguments. %s are given!", + this.getName(), + this.getRequiredArguments(), + values.length ); throw new Exception(message); diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ACos.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ACos.java index f05dca068..8386ec30e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ACos.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ACos.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ASin.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ASin.java index a91726528..d4f1a640f 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ASin.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ASin.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan.java index 5c0da958e..409e58660 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan2.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan2.java index 4357a8118..ad484f32b 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan2.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/ATan2.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Abs.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Abs.java index 6e2c4da4f..f13177d45 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Abs.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Abs.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Cos.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Cos.java index 0ccd43ca8..9e6a051f7 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Cos.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Cos.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Exp.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Exp.java index d6d29f55f..2a69cbb29 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Exp.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Exp.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Ln.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Ln.java index 647f5db93..d7ca8b645 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Ln.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Ln.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Mod.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Mod.java index bb21e645f..e5c1c2012 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Mod.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Mod.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pi.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pi.java index 1d0d8eaf2..907d74938 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pi.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pi.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pow.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pow.java index 12ee336f5..532183325 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pow.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Pow.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sin.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sin.java index a55531a60..243194293 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sin.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sin.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sqrt.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sqrt.java index 0329f16ad..31661858d 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sqrt.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/classic/Sqrt.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.classic; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Clamp.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Clamp.java index 8f8d35dbb..9cc2ccc05 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Clamp.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Clamp.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.limit; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Max.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Max.java index 575ba4577..3c38c63f6 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Max.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Max.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.limit; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Min.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Min.java index 753696f85..a2c2d9830 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Min.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/limit/Min.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.limit; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Ceil.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Ceil.java index c95fdbcdd..dbecf3ba8 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Ceil.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Ceil.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.rounding; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Floor.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Floor.java index f4c042fd5..d71637316 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Floor.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Floor.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.rounding; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Round.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Round.java index 61deed22e..27ecd7e8e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Round.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Round.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.rounding; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Trunc.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Trunc.java index 486d0b391..d81fd55fc 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Trunc.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/rounding/Trunc.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.rounding; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRoll.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRoll.java index 6aa65cad8..df12b4299 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRoll.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRoll.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRollInteger.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRollInteger.java index 6a1af5ab8..d5d92b9cf 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRollInteger.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/DieRollInteger.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/HermiteBlend.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/HermiteBlend.java index a2be1f341..097989541 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/HermiteBlend.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/HermiteBlend.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Lerp.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Lerp.java index ff2a7f48d..9a30fe42e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Lerp.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Lerp.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/LerpRotate.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/LerpRotate.java index 2d58605aa..ff2198d74 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/LerpRotate.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/LerpRotate.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Random.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Random.java index 588f4c029..34ab843ed 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Random.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/Random.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/RandomInteger.java b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/RandomInteger.java index a0d75b624..587ddf5b3 100644 --- a/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/RandomInteger.java +++ b/common/src/main/java/mod/azure/azurelib/core/math/functions/utility/RandomInteger.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.math.functions.utility; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/LazyVariable.java b/common/src/main/java/mod/azure/azurelib/core/molang/LazyVariable.java index c35fa9d99..27869155d 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/LazyVariable.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/LazyVariable.java @@ -1,16 +1,14 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang; -import mod.azure.azurelib.core.math.Variable; - import java.util.function.DoubleSupplier; +import mod.azure.azurelib.core.math.Variable; + /** * Lazy override of Variable, to allow for deferred value calculation.
    * Optimises rendering as values are not touched until needed (if at all) diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/MolangException.java b/common/src/main/java/mod/azure/azurelib/core/molang/MolangException.java index ec0ab8eb0..3ad3f53a5 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/MolangException.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/MolangException.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/MolangParser.java b/common/src/main/java/mod/azure/azurelib/core/molang/MolangParser.java index 31e3059cb..cb95791a8 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/MolangParser.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/MolangParser.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang; @@ -10,6 +8,12 @@ import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.function.DoubleSupplier; + import mod.azure.azurelib.core.math.Constant; import mod.azure.azurelib.core.math.IValue; import mod.azure.azurelib.core.math.MathBuilder; @@ -20,11 +24,6 @@ import mod.azure.azurelib.core.molang.functions.CosDegrees; import mod.azure.azurelib.core.molang.functions.SinDegrees; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.function.DoubleSupplier; - /** * Utility class for parsing and utilising MoLang functions and expressions * @@ -103,8 +102,8 @@ public static MolangValue parseExpression(String expression) throws MolangExcept * Parse a single Molang statement */ protected static MolangValue parseOneLine( - String expression, - MolangCompoundValue currentStatement + String expression, + MolangCompoundValue currentStatement ) throws MolangException { if (expression.startsWith(RETURN)) { try { @@ -118,8 +117,8 @@ protected static MolangValue parseOneLine( List symbols = INSTANCE.breakdownChars(INSTANCE.breakdown(expression)); if ( - symbols.size() >= 3 && symbols.get(0) instanceof String name && INSTANCE.isVariable(symbols.get(0)) - && symbols.get(1).equals("=") + symbols.size() >= 3 && symbols.get(0) instanceof String name && INSTANCE.isVariable(symbols.get(0)) + && symbols.get(1).equals("=") ) { symbols = symbols.subList(2, symbols.size()); LazyVariable variable; @@ -249,7 +248,7 @@ public double getAsDouble() { * * @param name The name of the variable to get * @return The registered {@code LazyVariable} instance, or a newly registered instance if one wasn't registered - * previously + * previously */ @Override public LazyVariable getVariable(String name) { diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/MolangQueries.java b/common/src/main/java/mod/azure/azurelib/core/molang/MolangQueries.java index fbcdac346..b56f7d4c4 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/MolangQueries.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/MolangQueries.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangCompoundValue.java b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangCompoundValue.java index 08f5c1f10..92bfdc124 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangCompoundValue.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangCompoundValue.java @@ -1,20 +1,19 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang.expressions; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import mod.azure.azurelib.core.molang.LazyVariable; import java.util.List; import java.util.Map; import java.util.StringJoiner; +import mod.azure.azurelib.core.molang.LazyVariable; + /** * An extension of the {@link MolangValue} class, allowing for compound expressions. */ diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangValue.java b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangValue.java index 5fe2d0b1e..3cf7d0e54 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangValue.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangValue.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang.expressions; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangVariableHolder.java b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangVariableHolder.java index ad5cfd1a5..00207e6ed 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangVariableHolder.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/expressions/MolangVariableHolder.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang.expressions; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/functions/CosDegrees.java b/common/src/main/java/mod/azure/azurelib/core/molang/functions/CosDegrees.java index 6ac470e0e..204baffa2 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/functions/CosDegrees.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/functions/CosDegrees.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang.functions; diff --git a/common/src/main/java/mod/azure/azurelib/core/molang/functions/SinDegrees.java b/common/src/main/java/mod/azure/azurelib/core/molang/functions/SinDegrees.java index cb7d22d1e..fbc8e2ff8 100644 --- a/common/src/main/java/mod/azure/azurelib/core/molang/functions/SinDegrees.java +++ b/common/src/main/java/mod/azure/azurelib/core/molang/functions/SinDegrees.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.molang.functions; diff --git a/common/src/main/java/mod/azure/azurelib/core/object/Axis.java b/common/src/main/java/mod/azure/azurelib/core/object/Axis.java index 44787163b..9e3b00162 100644 --- a/common/src/main/java/mod/azure/azurelib/core/object/Axis.java +++ b/common/src/main/java/mod/azure/azurelib/core/object/Axis.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.object; diff --git a/common/src/main/java/mod/azure/azurelib/core/object/Color.java b/common/src/main/java/mod/azure/azurelib/core/object/Color.java index a79d17644..cb5ba31b3 100644 --- a/common/src/main/java/mod/azure/azurelib/core/object/Color.java +++ b/common/src/main/java/mod/azure/azurelib/core/object/Color.java @@ -4,11 +4,43 @@ */ package mod.azure.azurelib.core.object; +import com.mojang.datafixers.util.Either; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import java.util.List; + /** * Color holder object for storing a packed int argb value. */ public record Color(int argbInt) { + public static Codec RGBA_CODEC = RecordCodecBuilder.create((instance) -> { // float? + return instance.group( + Codec.INT.fieldOf("r").forGetter(Color::getRed), + Codec.INT.fieldOf("g").forGetter(Color::getGreen), + Codec.INT.fieldOf("b").forGetter(Color::getBlue), + Codec.INT.fieldOf("a").orElse(255).forGetter(Color::getAlpha) + ).apply(instance, Color::ofRGBA); + }); + + public static Codec STRING_CODEC = Codec.STRING.comapFlatMap( + Color::tryHexString, + Color::toString + ); + + public static final Codec INT_CODEC = Codec.INT.xmap( + Color::new, + color -> color.argbInt + ); + + public static final Codec CODEC = Codec.either(STRING_CODEC, RGBA_CODEC) + .comapFlatMap( + either -> either.map(DataResult::success, DataResult::success), + Either::left + ); + public static final Color WHITE = new Color(0xFFFFFFFF); public static final Color LIGHT_GRAY = new Color(0xFFC0C0C0); @@ -61,10 +93,10 @@ public static Color ofRGB(int r, int g, int b) { */ public static Color ofRGBA(float r, float g, float b, float a) { return ofRGBA( - (int) (r * 255f + 0.5), - (int) (g * 255f + 0.5f), - (int) (b * 255f + 0.5f), - (int) (a * 255f + 0.5f) + (int) (r * 255f + 0.5), + (int) (g * 255f + 0.5f), + (int) (b * 255f + 0.5f), + (int) (a * 255f + 0.5f) ); } @@ -136,6 +168,34 @@ public static int HSBtoARGB(float hue, float saturation, float brightness) { return 0xFF000000 | (r << 16) | (g << 8) | b; } + /** + * Creates a new {@code Color} instance from a hexadecimal color + */ + public static Color ofHexString(String hexColor) { + if (hexColor.startsWith("#")) { + hexColor = hexColor.substring(1); + } + if (hexColor.length() == 3) { + StringBuilder expanded = new StringBuilder(); + for (char c : hexColor.toCharArray()) { + expanded.append(c).append(c); + } + hexColor = expanded.toString(); + } + return new Color(Integer.parseInt(hexColor, 16)); + } + + /** + * Creates a new {@code Color} instance from a hexadecimal color + */ + public static DataResult tryHexString(String hexColor) { + try { + return DataResult.success(ofHexString(hexColor)); + } catch (Exception err) { + return DataResult.error(err::toString); + } + } + public int getColor() { return this.argbInt; } @@ -172,6 +232,10 @@ public float getBlueFloat() { return getBlue() / 255f; } + public List getList() { + return List.of(getRed(), getGreen(), getBlue(), getAlpha()); + } + /** * Returns a brighter variant of the same color.
    * @@ -196,10 +260,10 @@ public Color brighter(double factor) { b = i; return ofRGBA( - Math.min((int) (r / (1 / factor)), 255), - Math.min((int) (g / (1 / factor)), 255), - Math.min((int) (b / (1 / factor)), 255), - getAlpha() + Math.min((int) (r / (1 / factor)), 255), + Math.min((int) (g / (1 / factor)), 255), + Math.min((int) (b / (1 / factor)), 255), + getAlpha() ); } @@ -212,10 +276,10 @@ public Color brighter(double factor) { */ public Color darker(float factor) { return ofRGBA( - Math.max((int) (getRed() * (1 / factor)), 0), - Math.max((int) (getGreen() * (1 / factor)), 0), - Math.max((int) (getBlue() * (1 / factor)), 0), - getAlpha() + Math.max((int) (getRed() * (1 / factor)), 0), + Math.max((int) (getGreen() * (1 / factor)), 0), + Math.max((int) (getBlue() * (1 / factor)), 0), + getAlpha() ); } diff --git a/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java b/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java index f5bc93e16..51fd26cc2 100644 --- a/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java +++ b/common/src/main/java/mod/azure/azurelib/core/object/DataTicket.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.object; @@ -12,7 +10,10 @@ /** * Ticket object to define a typed data object + * + * @deprecated */ +@Deprecated(forRemoval = true) public class DataTicket { private final String id; diff --git a/common/src/main/java/mod/azure/azurelib/core/object/PlayState.java b/common/src/main/java/mod/azure/azurelib/core/object/PlayState.java index 36f77de0c..a6a1a5e22 100644 --- a/common/src/main/java/mod/azure/azurelib/core/object/PlayState.java +++ b/common/src/main/java/mod/azure/azurelib/core/object/PlayState.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.object; diff --git a/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java b/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java index 43c581425..403fabc54 100644 --- a/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java +++ b/common/src/main/java/mod/azure/azurelib/core/state/BoneSnapshot.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ @@ -15,6 +13,8 @@ * A state monitoring class for a given {@link CoreGeoBone}.
    * Transformations applied to the bone is monitored by the {@link AnimationProcessor} in the course of animations, and * stored here for monitoring. + * + * @deprecated */ public class BoneSnapshot { diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java b/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java index 828ba20fc..4524f3dcc 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/Interpolation.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; @@ -10,24 +8,28 @@ public enum Interpolation { LINEAR("linear") { + @Override public float interpolate(float a, float b, float x) { return Interpolations.lerp(a, b, x); } }, QUAD_IN("quad_in") { + @Override public float interpolate(float a, float b, float x) { return a + (b - a) * x * x; } }, QUAD_OUT("quad_out") { + @Override public float interpolate(float a, float b, float x) { return a - (b - a) * x * (x - 2); } }, QUAD_INOUT("quad_inout") { + @Override public float interpolate(float a, float b, float x) { x *= 2; @@ -41,12 +43,14 @@ public float interpolate(float a, float b, float x) { } }, CUBIC_IN("cubic_in") { + @Override public float interpolate(float a, float b, float x) { return a + (b - a) * x * x * x; } }, CUBIC_OUT("cubic_out") { + @Override public float interpolate(float a, float b, float x) { x -= 1; @@ -54,6 +58,7 @@ public float interpolate(float a, float b, float x) { } }, CUBIC_INOUT("cubic_inout") { + @Override public float interpolate(float a, float b, float x) { x *= 2; @@ -67,18 +72,31 @@ public float interpolate(float a, float b, float x) { } }, EXP_IN("exp_in") { + @Override public float interpolate(float a, float b, float x) { return a + (b - a) * (float) Math.pow(2, 10 * (x - 1)); } }, EXP_OUT("exp_out") { + @Override public float interpolate(float a, float b, float x) { return a + (b - a) * (float) (-Math.pow(2, -10 * x) + 1); } }, + CATMULLROM("catmullrom") { + + @Override + public float interpolate(float a, float b, float x) { + return 0.5f * ((2 * a) + + (-(a - (b - a)) + b) * x + + (2 * (a - (b - a)) - 5 * a + 4 * b - (b + (b - a))) * (x * x) + + (-(a - (b - a)) + 3 * a - 3 * b + (b + (b - a))) * (x * x * x)); + } + }, EXP_INOUT("exp_inout") { + @Override public float interpolate(float a, float b, float x) { if (x == 0) diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/Interpolations.java b/common/src/main/java/mod/azure/azurelib/core/utils/Interpolations.java index b17c9f1c1..6b414d69e 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/Interpolations.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/Interpolations.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/JsonUtils.java b/common/src/main/java/mod/azure/azurelib/core/utils/JsonUtils.java index afaeaada2..4d3a95901 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/JsonUtils.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/JsonUtils.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/MathHelper.java b/common/src/main/java/mod/azure/azurelib/core/utils/MathHelper.java index 2650a5e6b..3c28ce431 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/MathHelper.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/MathHelper.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/MathUtils.java b/common/src/main/java/mod/azure/azurelib/core/utils/MathUtils.java index 4e21ba43a..b83d1f92f 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/MathUtils.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/MathUtils.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; diff --git a/common/src/main/java/mod/azure/azurelib/core/utils/Timer.java b/common/src/main/java/mod/azure/azurelib/core/utils/Timer.java index 460ced003..0753773bf 100644 --- a/common/src/main/java/mod/azure/azurelib/core/utils/Timer.java +++ b/common/src/main/java/mod/azure/azurelib/core/utils/Timer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.core.utils; @@ -10,7 +8,9 @@ public class Timer { private final long duration; + private boolean enabled; + private long time; public Timer(long duration) { diff --git a/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java b/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java new file mode 100644 index 000000000..79e7d127d --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/AzResourceCache.java @@ -0,0 +1,59 @@ +package mod.azure.azurelib.core2; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; + +import java.util.Locale; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.BiConsumer; +import java.util.function.Function; + +/** + * AzResourceCache is an abstract base class designed for managing and loading mod resources asynchronously. This class + * provides helper functions for loading and processing resource files of a specific type and storing them in a cache. + */ +public abstract class AzResourceCache { + + private static final Set EXCLUDED_NAMESPACES = ObjectOpenHashSet.of( + "moreplayermodels", + "customnpcs", + "creeperoverhaul", + "geckolib", + "gunsrpg", + "born_in_chaos_v1", + "neoforge" + ); + + protected final CompletableFuture loadResources( + Executor executor, + ResourceManager resourceManager, + String type, + Function loader, + BiConsumer map + ) { + return CompletableFuture.supplyAsync( + () -> resourceManager.listResources(type, fileName -> fileName.toString().endsWith(".json")), + executor + ) + .thenApplyAsync(resources -> { + var tasks = new Object2ObjectOpenHashMap>(); + + for (var resource : resources.keySet()) { + tasks.put(resource, CompletableFuture.supplyAsync(() -> loader.apply(resource), executor)); + } + + return tasks; + }, executor) + .thenAcceptAsync(tasks -> { + for (var entry : tasks.entrySet()) { + if (!EXCLUDED_NAMESPACES.contains(entry.getKey().getNamespace().toLowerCase(Locale.ROOT))) { + map.accept(entry.getKey(), entry.getValue().join()); + } + } + }, executor); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationContext.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationContext.java new file mode 100644 index 000000000..c98ab4493 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationContext.java @@ -0,0 +1,71 @@ +package mod.azure.azurelib.core2.animation; + +import mod.azure.azurelib.core2.animation.cache.AzBoneCache; + +/** + * The {@code AzAnimationContext} class provides a context for managing animation-related state and behaviors for + * animatable objects of type {@code T}. It serves as the central point of interaction between the animation system, + * configuration settings, and the animated object itself. + * + * @param The type of the animatable object that this context operates on. + */ +public class AzAnimationContext { + + private final AzBoneCache boneCache; + + private final AzAnimatorConfig config; + + private final AzAnimationTimer timer; + + // Package-private for mutability purposes. + T animatable; + + public AzAnimationContext( + AzBoneCache boneCache, + AzAnimatorConfig config, + AzAnimationTimer timer + ) { + this.boneCache = boneCache; + this.config = config; + this.timer = timer; + } + + /** + * Returns the current animatable instance associated with this animation context. + * + * @return The animatable instance of type {@code T}. + */ + public T animatable() { + return animatable; + } + + /** + * Returns the bone cache associated with the animation context. The bone cache is responsible for storing and + * managing bone-related data and transformations used during animations. + * + * @return The {@link AzBoneCache} instance managing bone data and transformations for animations. + */ + public AzBoneCache boneCache() { + return boneCache; + } + + /** + * Returns the animation configuration associated with this animation context. The configuration defines behavior + * such as bone reset speed, handling of missing bones, and whether animations should play while the game is paused. + * + * @return The {@link AzAnimatorConfig} instance containing the animation settings for this context. + */ + public AzAnimatorConfig config() { + return config; + } + + /** + * Returns the animation timer associated with the animation context. The timer is used to track animation progress + * over time and manage timing adjustments based on game state, such as pausing and resuming. + * + * @return The {@link AzAnimationTimer} instance responsible for animation timing. + */ + public AzAnimationTimer timer() { + return timer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java new file mode 100644 index 000000000..55fc7fd5d --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimationTimer.java @@ -0,0 +1,92 @@ +package mod.azure.azurelib.core2.animation; + +import net.minecraft.client.Minecraft; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; + +/** + * AzAnimationTimer is responsible for managing animation progression based on game events and time deltas. It keeps + * track of the current animation time and ensures smooth transitions during various game states, such as pausing and + * resuming.
    + * The class relies on the provided {@link AzAnimatorConfig} for configurable behaviors, such as whether animations + * continue during game pauses or specific error handling preferences. + */ +public class AzAnimationTimer { + + private final AzAnimatorConfig config; + + // Remnants from GeoModel. + private double animTime; + + private double lastGameTickTime; + + private boolean wasPausedLastFrame; + + /** + * Constructs a new instance of AzAnimationTimer with the given configuration. + * + * @param config The configuration settings used to configure the animation timer. It includes parameters such as + * bone reset time, behavior during game pause, and whether to crash if a bone is missing. + */ + public AzAnimationTimer(AzAnimatorConfig config) { + this.config = config; + } + + /** + * Updates the animation timer by calculating the time delta since the last frame and applying it to the internal + * animation time. This method handles game pause states and adjusts the time calculations accordingly.
    + * Behavior: If the game is paused: + *
      + *
    • Sets an internal flag to indicate the paused state.
    • + *
    • Returns immediately if animations should not play while paused.
    • + *
    + * If transitioning from paused to unpaused: + *
      + *
    • Resets the frame delta to prevent large time skips in animations.
    • + *
    + * Accumulates the computed time delta into the animation time tracker to control the progression of animations. + */ + public void tick() { + var minecraft = Minecraft.getInstance(); + var currentRenderTick = RenderUtils.getCurrentTick(); + + if (minecraft.isPaused()) { + if (!wasPausedLastFrame) { + // If this is the first frame of the game pause time, we need to set a flag. + this.wasPausedLastFrame = true; + } + + if (!config.shouldPlayAnimationsWhileGamePaused()) { + // If we cannot play animations while the game is paused, then return early. + return; + } + } + + // Compute the delta render tick for this frame. This calculation by default does not account for the game + // pause state, which means that the difference here could be massive by the time the player unpauses. + var deltaRenderTick = currentRenderTick - lastGameTickTime; + + if (wasPausedLastFrame && !minecraft.isPaused()) { + // If this is the first frame of the game play time, we need to set a flag and adjust the deltaRenderTick. + this.wasPausedLastFrame = false; + // To account for the deltaRenderTick being massive on exiting the game pause state, we simply set + // it to 0. This will result in no difference being added to animTime, allowing animations to + // continue right where it left off. + deltaRenderTick = 0; + } + + // Add the deltaRenderTick to animTime. animTime is what controls the progress of animations. + this.animTime += deltaRenderTick; + this.lastGameTickTime = currentRenderTick; + } + + /** + * Retrieves the current animation time. + * + * @return The current animation time as a double value, representing the accumulated time used for the progression + * of animations. + */ + public double getAnimTime() { + return animTime; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java new file mode 100644 index 000000000..1cdd38679 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimator.java @@ -0,0 +1,135 @@ +package mod.azure.azurelib.core2.animation; + +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +import mod.azure.azurelib.common.internal.common.AzureLibException; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.MolangQueries; +import mod.azure.azurelib.core2.animation.cache.AzBakedAnimationCache; +import mod.azure.azurelib.core2.animation.cache.AzBoneCache; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimation; +import mod.azure.azurelib.core2.model.AzBakedModel; + +/** + * The {@code AzAnimator} class is an abstract base class for managing animations for various types of objects such as + * entities, blocks, or items. It provides a reusable structure for animating objects, allowing the integration of a + * variety of animation controllers and custom animations. + * + * @param The type of object this animator will animate (e.g., an entity, block entity, or item stack). + */ +public abstract class AzAnimator { + + private final AzAnimationContext reusableContext; + + // Holds animation controllers. + private final AzAnimationControllerContainer animationControllerContainer; + + public boolean reloadAnimations; + + protected AzAnimator() { + this(AzAnimatorConfig.defaultConfig()); + } + + protected AzAnimator(AzAnimatorConfig config) { + this.animationControllerContainer = new AzAnimationControllerContainer<>(); + + var boneCache = new AzBoneCache(); + var timer = new AzAnimationTimer(config); + + this.reusableContext = new AzAnimationContext<>(boneCache, config, timer); + } + + public abstract void registerControllers(AzAnimationControllerContainer animationControllerContainer); + + public abstract @NotNull ResourceLocation getAnimationLocation(T animatable); + + public void animate(T animatable, float partialTicks) { + reusableContext.animatable = animatable; + + var boneCache = reusableContext.boneCache(); + var timer = reusableContext.timer(); + + timer.tick(); + + preAnimationSetup(animatable, timer.getAnimTime()); + + if (!boneCache.isEmpty()) { + + for (var controller : animationControllerContainer.getAll()) { + controller.update(); + } + + this.reloadAnimations = false; + + boneCache.update(reusableContext); + } + + setCustomAnimations(animatable, partialTicks); + } + + /** + * Apply transformations and settings prior to acting on any animation-related functionality + */ + protected void preAnimationSetup(T animatable, double animTime) { + applyMolangQueries(animatable, animTime); + } + + protected void applyMolangQueries(T animatable, double animTime) { + var level = Objects.requireNonNull(Minecraft.getInstance().level); + var parser = MolangParser.INSTANCE; + + parser.setMemoizedValue(MolangQueries.LIFE_TIME, () -> animTime / 20d); + parser.setMemoizedValue(MolangQueries.ACTOR_COUNT, level::getEntityCount); + parser.setMemoizedValue(MolangQueries.TIME_OF_DAY, () -> level.getDayTime() / 24000f); + parser.setMemoizedValue(MolangQueries.MOON_PHASE, level::getMoonPhase); + } + + /** + * Sets custom animations for the given animatable object. This method is used to define and configure specific + * animations unique to the context of the animatable and the current render state. + * + * @param animatable The object for which custom animations are being set. + * @param partialTicks The partial tick time used for interpolating animations smoothly between frames. + */ + public void setCustomAnimations(T animatable, float partialTicks) {} + + public void setActiveModel(AzBakedModel model) { + var modelChanged = reusableContext.boneCache().setActiveModel(model); + + if (modelChanged) { + // If the model changed, we need to clear the bone animation queue cache for every controller. + // TODO: We shouldn't have to remember to do this. If the baked model changes, then the bone cache + // should be re-instantiated. If the bone cache is re-instantiated, then so should the bone animation + // queue caches. + animationControllerContainer.getAll() + .forEach(controller -> controller.boneAnimationQueueCache().clear()); + } + } + + /** + * Get the baked animation object used for rendering from the given resource path + */ + public AzBakedAnimation getAnimation(T animatable, String name) { + var location = getAnimationLocation(animatable); + var bakedAnimations = AzBakedAnimationCache.getInstance().getNullable(location); + + if (bakedAnimations == null) { + throw new AzureLibException(location, "Unable to find animation."); + } + + return bakedAnimations.getAnimation(name); + } + + public AzAnimationContext context() { + return reusableContext; + } + + public AzAnimationControllerContainer getAnimationControllerContainer() { + return animationControllerContainer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java new file mode 100644 index 000000000..dd5f2ec05 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorAccessor.java @@ -0,0 +1,37 @@ +package mod.azure.azurelib.core2.animation; + +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +/** + * The {@code AzAnimatorAccessor} interface provides a mechanism to associate and manage an {@link AzAnimator} instance + * with a target object. This enables retrieval and manipulation of animator instances that are specific to the target + * object. + * + * @param The type of the target object that the animator applies to. + */ +public interface AzAnimatorAccessor { + + @Nullable + AzAnimator getAnimatorOrNull(); + + void setAnimator(AzAnimator animator); + + default Optional> getAnimator() { + return Optional.ofNullable(getAnimatorOrNull()); + } + + @SuppressWarnings("unchecked") + static AzAnimatorAccessor cast(T target) { + return (AzAnimatorAccessor) target; + } + + static AzAnimator getOrNull(T target) { + return cast(target).getAnimatorOrNull(); + } + + static Optional> get(T target) { + return Optional.ofNullable(getOrNull(target)); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorConfig.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorConfig.java new file mode 100644 index 000000000..48f499ca4 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzAnimatorConfig.java @@ -0,0 +1,108 @@ +package mod.azure.azurelib.core2.animation; + +/** + * The {@code AzAnimatorConfig} record encapsulates configuration settings related to the animation system of the + * AzureLib framework. It provides customizable options for controlling animation behavior and error handling. This + * configuration is used to determine runtime behaviors such as whether animations should continue while the game is + * paused, whether the system should throw an error if a bone in the animation structure is missing, and the duration it + * takes to reset bone transformations. + * + * @param boneResetTime The specified time duration (in ticks or seconds) for resetting bones to + * their default transformations when animations are interrupted. + * @param crashIfBoneMissing Specifies whether the system will throw an exception if an expected bone + * in the animation is not found during runtime. + * @param shouldPlayAnimationsWhileGamePaused Indicates whether animations should continue playing when the game is + * paused. + */ +public record AzAnimatorConfig( + double boneResetTime, + boolean crashIfBoneMissing, + boolean shouldPlayAnimationsWhileGamePaused +) { + + /** + * Creates a new instance of the {@link Builder} to configure and build an {@code AzAnimatorConfig}. + * + * @return A new {@code Builder} instance for constructing an {@code AzAnimatorConfig}. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Returns a default {@link AzAnimatorConfig} instance with predefined settings. The default configuration typically + * includes settings such as: + *
      + *
    • A bone reset time of 1 tick/second.
    • + *
    • Disabling the feature to crash if a bone is missing.
    • + *
    • Disabling animations while the game is paused.
    • + *
    + * + * @return The default configuration instance of {@code AzAnimatorConfig}, built with default values. + */ + public static AzAnimatorConfig defaultConfig() { + return builder().build(); + } + + public static class Builder { + + private double boneResetTime; + + private boolean crashIfBoneMissing; + + private boolean shouldPlayAnimationsWhileGamePaused; + + private Builder() { + this.boneResetTime = 1; + this.crashIfBoneMissing = false; + this.shouldPlayAnimationsWhileGamePaused = false; + } + + /** + * Configures the builder to crash if a required bone is missing during animation setup. + * + * @return The current Builder instance for method chaining. + */ + public Builder crashIfBoneMissing() { + this.crashIfBoneMissing = true; + return this; + } + + /** + * Configures the builder to enable animations to play even when the game is paused. + * + * @return The current Builder instance for method chaining. + */ + public Builder shouldPlayAnimationsWhileGamePaused() { + this.shouldPlayAnimationsWhileGamePaused = true; + return this; + } + + /** + * Sets the bone reset time duration. This value determines how long it takes to reset bones to their default + * state after an animation is completed. + * + * @param boneResetTime The duration (in seconds) for bone reset time. + * @return The current Builder instance to allow method chaining. + */ + public Builder withBoneResetTime(double boneResetTime) { + this.boneResetTime = boneResetTime; + return this; + } + + /** + * Constructs a new {@link AzAnimatorConfig} instance with the specified configuration parameters defined in the + * Builder. The configuration includes options for bone reset timing, error handling when bones are missing, and + * animation playback behavior during game pause state. + * + * @return A new {@code AzAnimatorConfig} instance containing the configured settings. + */ + public AzAnimatorConfig build() { + return new AzAnimatorConfig( + boneResetTime, + crashIfBoneMissing, + shouldPlayAnimationsWhileGamePaused + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java new file mode 100644 index 000000000..ef179cbdc --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzBoneAnimationUpdateUtil.java @@ -0,0 +1,107 @@ +package mod.azure.azurelib.core2.animation; + +import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; +import mod.azure.azurelib.core2.animation.easing.AzEasingType; +import mod.azure.azurelib.core2.animation.easing.AzEasingUtil; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; + +public class AzBoneAnimationUpdateUtil { + + /** + * Updates the position of the given bone by interpolating the position values from the animation queue and applying + * the specified easing type. The method also updates the snapshot offsets and flags the bone's position as changed. + * + * @param boneAnimation The animation queue containing position data for the bone. + * @param bone The bone whose position is being updated. + * @param easingType The easing type used for interpolating the position values. + * @param snapshot The snapshot used to store the updated position offsets and start animations. + */ + public static void updatePositions( + AzBoneAnimationQueue boneAnimation, + AzBone bone, + AzEasingType easingType, + AzBoneSnapshot snapshot + ) { + var posXPoint = boneAnimation.positionXQueue().poll(); + var posYPoint = boneAnimation.positionYQueue().poll(); + var posZPoint = boneAnimation.positionZQueue().poll(); + + if (posXPoint != null && posYPoint != null && posZPoint != null) { + bone.setPosX((float) AzEasingUtil.lerpWithOverride(posXPoint, easingType)); + bone.setPosY((float) AzEasingUtil.lerpWithOverride(posYPoint, easingType)); + bone.setPosZ((float) AzEasingUtil.lerpWithOverride(posZPoint, easingType)); + snapshot.updateOffset(bone.getPosX(), bone.getPosY(), bone.getPosZ()); + snapshot.startPosAnim(); + bone.markPositionAsChanged(); + } + } + + /** + * Updates the rotation of the specified bone by interpolating the rotation values from the animation queue and + * applying the specified easing type. The method also updates the snapshot rotation values, starts the rotation + * animation, and marks the bone's rotation as changed. + * + * @param boneAnimation The animation queue containing rotation data for the bone. + * @param bone The bone whose rotation is being updated. + * @param easingType The easing type used for interpolating the rotation values. + * @param initialSnapshot The initial snapshot containing the original rotation offsets. + * @param snapshot The snapshot used to store the updated rotation values and start animations. + */ + public static void updateRotations( + AzBoneAnimationQueue boneAnimation, + AzBone bone, + AzEasingType easingType, + AzBoneSnapshot initialSnapshot, + AzBoneSnapshot snapshot + ) { + var rotXPoint = boneAnimation.rotationXQueue().poll(); + var rotYPoint = boneAnimation.rotationYQueue().poll(); + var rotZPoint = boneAnimation.rotationZQueue().poll(); + + if (rotXPoint != null && rotYPoint != null && rotZPoint != null) { + bone.setRotX( + (float) AzEasingUtil.lerpWithOverride(rotXPoint, easingType) + initialSnapshot.getRotX() + ); + bone.setRotY( + (float) AzEasingUtil.lerpWithOverride(rotYPoint, easingType) + initialSnapshot.getRotY() + ); + bone.setRotZ( + (float) AzEasingUtil.lerpWithOverride(rotZPoint, easingType) + initialSnapshot.getRotZ() + ); + snapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); + snapshot.startRotAnim(); + bone.markRotationAsChanged(); + } + } + + /** + * Updates the scale of the specified bone by interpolating the scale values from the animation queue and applying + * the specified easing type. The method also updates the snapshot with the new scale values, starts the scale + * animation, and marks the bone's scale as changed. + * + * @param boneAnimation The animation queue containing scale data for the bone. + * @param bone The bone whose scale is being updated. + * @param easingType The easing type used for interpolating the scale values. + * @param snapshot The snapshot used to store the updated scale values and start animations. + */ + public static void updateScale( + AzBoneAnimationQueue boneAnimation, + AzBone bone, + AzEasingType easingType, + AzBoneSnapshot snapshot + ) { + var scaleXPoint = boneAnimation.scaleXQueue().poll(); + var scaleYPoint = boneAnimation.scaleYQueue().poll(); + var scaleZPoint = boneAnimation.scaleZQueue().poll(); + + if (scaleXPoint != null && scaleYPoint != null && scaleZPoint != null) { + bone.setScaleX((float) AzEasingUtil.lerpWithOverride(scaleXPoint, easingType)); + bone.setScaleY((float) AzEasingUtil.lerpWithOverride(scaleYPoint, easingType)); + bone.setScaleZ((float) AzEasingUtil.lerpWithOverride(scaleZPoint, easingType)); + snapshot.updateScale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); + snapshot.startScaleAnim(); + bone.markScaleAsChanged(); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java b/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java new file mode 100644 index 000000000..4749ab02e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/AzCachedBoneUpdateUtil.java @@ -0,0 +1,160 @@ +package mod.azure.azurelib.core2.animation; + +import java.util.Map; + +import mod.azure.azurelib.core.utils.Interpolations; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; + +public class AzCachedBoneUpdateUtil { + + /** + * Updates the cached position of a given bone by interpolating its offsets towards its initial snapshot. Stops + * ongoing position animations if necessary and updates the bone's position based on the reset percentage. + * + * @param bone the bone whose position is to be updated + * @param boneSnapshots a map containing snapshots of bones by their names + * @param animTime the current animation time + * @param resetTickLength the duration over which the position reset occurs + */ + public static void updateCachedBonePosition( + AzBone bone, + Map boneSnapshots, + double animTime, + double resetTickLength + ) { + if (bone.hasPositionChanged()) { + return; + } + + var initialSnapshot = bone.getInitialAzSnapshot(); + var saveSnapshot = boneSnapshots.get(bone.getName()); + + if (saveSnapshot.isPosAnimInProgress()) { + saveSnapshot.stopPosAnim(animTime); + } + + var percentageReset = Math.min( + (animTime - saveSnapshot.getLastResetPositionTick()) / resetTickLength, + 1 + ); + + bone.setPosX( + (float) Interpolations.lerp( + saveSnapshot.getOffsetX(), + initialSnapshot.getOffsetX(), + percentageReset + ) + ); + bone.setPosY( + (float) Interpolations.lerp( + saveSnapshot.getOffsetY(), + initialSnapshot.getOffsetY(), + percentageReset + ) + ); + bone.setPosZ( + (float) Interpolations.lerp( + saveSnapshot.getOffsetZ(), + initialSnapshot.getOffsetZ(), + percentageReset + ) + ); + + if (percentageReset >= 1) { + saveSnapshot.updateOffset(bone.getPosX(), bone.getPosY(), bone.getPosZ()); + } + } + + /** + * Updates the cached rotation of a given bone by interpolating its rotation values towards its initial snapshot. + * Stops any ongoing rotation animations if necessary and updates the bone's rotation based on the reset percentage. + * + * @param bone the bone whose rotation is to be updated + * @param boneSnapshots a map containing snapshots of bones by their names + * @param animTime the current animation time + * @param resetTickLength the duration over which the rotation reset occurs + */ + public static void updateCachedBoneRotation( + AzBone bone, + Map boneSnapshots, + double animTime, + double resetTickLength + ) { + if (bone.hasRotationChanged()) { + return; + } + + var initialSnapshot = bone.getInitialAzSnapshot(); + var saveSnapshot = boneSnapshots.get(bone.getName()); + + if (saveSnapshot.isRotAnimInProgress()) { + saveSnapshot.stopRotAnim(animTime); + } + + double percentageReset = Math.min( + (animTime - saveSnapshot.getLastResetRotationTick()) / resetTickLength, + 1 + ); + + bone.setRotX( + (float) Interpolations.lerp(saveSnapshot.getRotX(), initialSnapshot.getRotX(), percentageReset) + ); + bone.setRotY( + (float) Interpolations.lerp(saveSnapshot.getRotY(), initialSnapshot.getRotY(), percentageReset) + ); + bone.setRotZ( + (float) Interpolations.lerp(saveSnapshot.getRotZ(), initialSnapshot.getRotZ(), percentageReset) + ); + + if (percentageReset >= 1) { + saveSnapshot.updateRotation(bone.getRotX(), bone.getRotY(), bone.getRotZ()); + } + } + + /** + * Updates the cached scale of a given bone by interpolating its scale values towards its initial snapshot. Stops + * any ongoing scale animations if necessary and updates the bone's scale based on the reset percentage. + * + * @param bone the bone whose scale is to be updated + * @param boneSnapshots a map containing snapshots of bones by their names + * @param animTime the current animation time + * @param resetTickLength the duration over which the scale reset occurs + */ + public static void updateCachedBoneScale( + AzBone bone, + Map boneSnapshots, + double animTime, + double resetTickLength + ) { + if (bone.hasScaleChanged()) { + return; + } + + var initialSnapshot = bone.getInitialAzSnapshot(); + var saveSnapshot = boneSnapshots.get(bone.getName()); + + if (saveSnapshot.isScaleAnimInProgress()) { + saveSnapshot.stopScaleAnim(animTime); + } + + double percentageReset = Math.min( + (animTime - saveSnapshot.getLastResetScaleTick()) / resetTickLength, + 1 + ); + + bone.setScaleX( + (float) Interpolations.lerp(saveSnapshot.getScaleX(), initialSnapshot.getScaleX(), percentageReset) + ); + bone.setScaleY( + (float) Interpolations.lerp(saveSnapshot.getScaleY(), initialSnapshot.getScaleY(), percentageReset) + ); + bone.setScaleZ( + (float) Interpolations.lerp(saveSnapshot.getScaleZ(), initialSnapshot.getScaleZ(), percentageReset) + ); + + if (percentageReset >= 1) { + saveSnapshot.updateScale(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java new file mode 100644 index 000000000..970df94c2 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBakedAnimationCache.java @@ -0,0 +1,55 @@ +package mod.azure.azurelib.core2.animation.cache; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import mod.azure.azurelib.common.internal.common.loading.FileLoader; +import mod.azure.azurelib.core2.AzResourceCache; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; + +/** + * AzBakedAnimationCache is a singleton cache to manage and store preloaded animation data of type + * {@link AzBakedAnimations}. It is an extension of {@link AzResourceCache} and provides mechanisms for managing + * animation resources in Minecraft modding. Aimed at efficient storage and retrieval, as well as background processing + * of animation data.
    + * Features: + *
      + *
    • Supports asynchronous loading of animation resources from the in-memory {@code ResourceManager}. + *
    • Caches animation data keyed by {@link ResourceLocation}. + *
    • Provides access to the cached animations or null values for non-existent records.
    • + *
    + */ +public class AzBakedAnimationCache extends AzResourceCache { + + private static final AzBakedAnimationCache INSTANCE = new AzBakedAnimationCache(); + + public static AzBakedAnimationCache getInstance() { + return INSTANCE; + } + + private final Map bakedAnimations; + + private AzBakedAnimationCache() { + this.bakedAnimations = new Object2ObjectOpenHashMap<>(); + } + + public CompletableFuture loadAnimations(Executor backgroundExecutor, ResourceManager resourceManager) { + return loadResources( + backgroundExecutor, + resourceManager, + "animations", + resource -> FileLoader.loadAzAnimationsFile(resource, resourceManager), + bakedAnimations::put + ); + } + + public @Nullable AzBakedAnimations getNullable(ResourceLocation resourceLocation) { + return bakedAnimations.get(resourceLocation); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java new file mode 100644 index 000000000..5dabea181 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzBoneCache.java @@ -0,0 +1,88 @@ +package mod.azure.azurelib.core2.animation.cache; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +import java.util.Map; +import java.util.Objects; + +import mod.azure.azurelib.core2.animation.AzAnimationContext; +import mod.azure.azurelib.core2.animation.AzCachedBoneUpdateUtil; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; + +/** + * The AzBoneCache class is responsible for managing the state and cache of bones in a baked model. It provides + * functionality for updating animation contexts, managing snapshots of bone states, and resetting transformation + * markers in preparation for rendering. + */ +public class AzBoneCache { + + private AzBakedModel bakedModel; + + private final Map boneSnapshotsByName; + + public AzBoneCache() { + this.bakedModel = AzBakedModel.EMPTY; + this.boneSnapshotsByName = new Object2ObjectOpenHashMap<>(); + } + + public boolean setActiveModel(AzBakedModel model) { + var willModelChange = !Objects.equals(bakedModel, model); + this.bakedModel = model; + + if (willModelChange) { + snapshot(); + } + + return willModelChange; + } + + public void update(AzAnimationContext context) { + var config = context.config(); + var timer = context.timer(); + var animTime = timer.getAnimTime(); + var boneSnapshots = getBoneSnapshotsByName(); + var resetTickLength = config.boneResetTime(); + + // Updates the cached bone snapshots (only if they have changed). + for (var bone : bakedModel.getBonesByName().values()) { + AzCachedBoneUpdateUtil.updateCachedBoneRotation(bone, boneSnapshots, animTime, resetTickLength); + AzCachedBoneUpdateUtil.updateCachedBonePosition(bone, boneSnapshots, animTime, resetTickLength); + AzCachedBoneUpdateUtil.updateCachedBoneScale(bone, boneSnapshots, animTime, resetTickLength); + } + + resetBoneTransformationMarkers(); + } + + /** + * Reset the transformation markers applied to each {@link AzBone} ready for the next render frame + */ + private void resetBoneTransformationMarkers() { + bakedModel.getBonesByName().values().forEach(AzBone::resetStateChanges); + } + + /** + * Create new bone {@link AzBoneSnapshot} based on the bone's initial snapshot for the currently registered + * {@link AzBone AzBones}, filtered by the bones already present in the master snapshots map + */ + private void snapshot() { + boneSnapshotsByName.clear(); + + for (var bone : bakedModel.getBonesByName().values()) { + boneSnapshotsByName.put(bone.getName(), AzBoneSnapshot.copy(bone.getInitialAzSnapshot())); + } + } + + public AzBakedModel getBakedModel() { + return bakedModel; + } + + public Map getBoneSnapshotsByName() { + return boneSnapshotsByName; + } + + public boolean isEmpty() { + return bakedModel.getBonesByName().isEmpty(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentifiableItemStackAnimatorCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentifiableItemStackAnimatorCache.java new file mode 100644 index 000000000..41a487519 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentifiableItemStackAnimatorCache.java @@ -0,0 +1,42 @@ +package mod.azure.azurelib.core2.animation.cache; + +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; + +/** + * The AzIdentifiableItemStackAnimatorCache class is a singleton utility for managing a cache of {@link ItemStack} + * objects, each associated with a unique identifier (UUID). This class provides functionality to register and retrieve + * item animators that apply to specific {@link ItemStack}s using their respective UUIDs. + */ +public class AzIdentifiableItemStackAnimatorCache { + + private static final AzIdentifiableItemStackAnimatorCache INSTANCE = new AzIdentifiableItemStackAnimatorCache(); + + // TODO: Purge animators periodically. + private static final Map ANIMATORS_BY_UUID = new HashMap<>(); + + public static AzIdentifiableItemStackAnimatorCache getInstance() { + return INSTANCE; + } + + private AzIdentifiableItemStackAnimatorCache() {} + + public void add(ItemStack itemStack, AzItemAnimator animator) { + var uuid = itemStack.get(AzureLib.AZ_ID.get()); + + if (uuid != null) { + ANIMATORS_BY_UUID.computeIfAbsent(uuid, ($) -> animator); + } + } + + public @Nullable AzItemAnimator getOrNull(UUID uuid) { + return uuid == null ? null : ANIMATORS_BY_UUID.get(uuid); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentityRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentityRegistry.java new file mode 100644 index 000000000..8bb40d979 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/cache/AzIdentityRegistry.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.core2.animation.cache; + +import net.minecraft.world.item.Item; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * The AzIdentityRegistry class provides functionality to register and check the identity of items. This class maintains + * a static registry of unique items, allowing you to determine if a specific item has been registered. + */ +public class AzIdentityRegistry { + + private static final Set IDENTITY_OF_ITEMS = new HashSet<>(); + + /** + * Registers one or more items into a static identity set, ensuring that the items are stored for identity tracking. + * + * @param first The first non-null item to be registered. This parameter is mandatory. + * @param rest A varargs array of additional items to register. These items can be null, but null values will not + * be added to the identity set. + */ + public static void register(@NotNull Item first, Item... rest) { + IDENTITY_OF_ITEMS.add(first); + IDENTITY_OF_ITEMS.addAll(Arrays.asList(rest)); + } + + /** + * Checks if the specified item exists in the identity set. + * + * @param item The item to check for identity. Must not be null. + * @return true if the item exists in the identity set, false otherwise. + */ + public static boolean hasIdentity(Item item) { + return IDENTITY_OF_ITEMS.contains(item); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAbstractAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAbstractAnimationController.java new file mode 100644 index 000000000..061bef3ee --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAbstractAnimationController.java @@ -0,0 +1,33 @@ +package mod.azure.azurelib.core2.animation.controller; + +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.sequence.AzAnimationSequence; + +// TODO: This will eventually be usable in common-side code once animations are moved from assets to data. +public class AzAbstractAnimationController { + + private final String name; + + protected AzAnimationSequence currentSequence; + + protected AzDispatchSide currentSequenceOrigin; + + protected AzAbstractAnimationController(String name) { + this.name = name; + } + + public String name() { + return name; + } + + /** + * Checks whether the last animation that was playing on this controller has finished or not.
    + * This will return true if the controller has had an animation set previously, and it has finished playing and + * isn't going to loop or proceed to another animation.
    + * + * @return Whether the previous animation finished or not + */ + public boolean hasAnimationFinished() { + return currentSequence != null; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java new file mode 100644 index 000000000..659087d7e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationController.java @@ -0,0 +1,215 @@ +package mod.azure.azurelib.core2.animation.controller; + +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyframeCallbacks; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyframeManager; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPauseState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPlayState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationStopState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationTransitionState; +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.sequence.AzAnimationSequence; +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; +import mod.azure.azurelib.core2.animation.property.AzAnimationProperties; + +/** + * The actual controller that handles the playing and usage of animations, including their various keyframes and + * instruction markers. Each controller can only play a single animation at a time - for example you may have one + * controller to animate walking, one to control attacks, one to control size, etc. + */ +public class AzAnimationController extends AzAbstractAnimationController { + + protected static final Logger LOGGER = LoggerFactory.getLogger(AzAnimationController.class); + + public static AzAnimationControllerBuilder builder(AzAnimator animator, String name) { + return new AzAnimationControllerBuilder<>(animator, name); + } + + private final AzAnimationControllerTimer controllerTimer; + + private final AzAnimationQueue animationQueue; + + private final AzAnimationControllerStateMachine stateMachine; + + private final AzAnimator animator; + + private final AzBoneAnimationQueueCache boneAnimationQueueCache; + + private final AzBoneSnapshotCache boneSnapshotCache; + + private final AzKeyframeManager keyframeManager; + + protected AzQueuedAnimation currentAnimation; + + private AzAnimationProperties animationProperties; + + AzAnimationController( + String name, + AzAnimator animator, + AzAnimationProperties animationProperties, + AzKeyframeCallbacks keyframeCallbacks + ) { + super(name); + + this.animator = animator; + this.controllerTimer = new AzAnimationControllerTimer<>(this); + this.animationProperties = animationProperties; + + this.animationQueue = new AzAnimationQueue(); + this.boneAnimationQueueCache = new AzBoneAnimationQueueCache<>(animator.context().boneCache()); + this.boneSnapshotCache = new AzBoneSnapshotCache(); + this.keyframeManager = new AzKeyframeManager<>( + this, + boneAnimationQueueCache, + boneSnapshotCache, + keyframeCallbacks + ); + + var stateHolder = new AzAnimationControllerStateMachine.StateHolder( + new AzAnimationPlayState<>(), + new AzAnimationPauseState<>(), + new AzAnimationStopState<>(), + new AzAnimationTransitionState<>() + ); + + this.stateMachine = new AzAnimationControllerStateMachine<>(stateHolder, this, animator.context()); + } + + @Override + public boolean hasAnimationFinished() { + return super.hasAnimationFinished() && stateMachine.isStopped(); + } + + public List tryCreateAnimationQueue(T animatable, AzAnimationSequence sequence) { + var stages = sequence.stages(); + var animations = new ArrayList(); + + for (var stage : stages) { + var animation = animator.getAnimation(animatable, stage.name()); + + if (animation == null) { + LOGGER.warn( + "Unable to find animation: {} for {}", + stage.name(), + animatable.getClass().getSimpleName() + ); + return List.of(); + } else { + animations.add(new AzQueuedAnimation(animation, stage.properties().playBehavior())); + } + } + + return animations; + } + + public void setAnimation(T animatable, AzAnimationSequence sequence) { + if (sequence == null || sequence.stages().isEmpty()) { + stateMachine.stop(); + return; + } + + if (!sequence.equals(currentSequence)) { + var animations = tryCreateAnimationQueue(animatable, sequence); + + if (!animations.isEmpty()) { + animationQueue.clear(); + animationQueue.addAll(animations); + this.currentSequence = sequence; + stateMachine.transition(); + return; + } + + stateMachine.stop(); + } + } + + /** + * This method is called every frame in order to populate the animation point queues, and process animation state + * logic. + */ + public void update() { + // Adjust the tick before making any updates. + controllerTimer.update(); + // Run state machine updates. + stateMachine.update(); + // Update bone animation queue cache. + boneAnimationQueueCache.update(animationProperties.easingType()); + } + + public void run(AzDispatchSide originSide, AzAnimationSequence sequence) { + if (currentSequenceOrigin == AzDispatchSide.SERVER && originSide == AzDispatchSide.CLIENT) { + if (!hasAnimationFinished()) { + // If we're playing a server-side sequence, ignore client-side sequences. + return; + } + } + + this.currentSequenceOrigin = originSide; + + if (stateMachine.isStopped()) { + stateMachine.transition(); + } + + if (sequence != null) { + if (currentSequence == null || !currentSequence.equals(sequence)) { + this.currentAnimation = null; + } + + var animatable = animator.context().animatable(); + setAnimation(animatable, sequence); + } + } + + public AzAnimationProperties animationProperties() { + return animationProperties; + } + + public void setAnimationProperties(AzAnimationProperties animationProperties) { + this.animationProperties = animationProperties; + } + + public AzAnimationQueue animationQueue() { + return animationQueue; + } + + public AzBoneAnimationQueueCache boneAnimationQueueCache() { + return boneAnimationQueueCache; + } + + public AzBoneSnapshotCache boneSnapshotCache() { + return boneSnapshotCache; + } + + public AzAnimationControllerTimer controllerTimer() { + return controllerTimer; + } + + public @Nullable AzQueuedAnimation currentAnimation() { + return currentAnimation; + } + + public AzKeyframeManager keyframeManager() { + return keyframeManager; + } + + public AzAnimationControllerStateMachine stateMachine() { + return stateMachine; + } + + public void setCurrentAnimation(AzQueuedAnimation currentAnimation) { + this.currentAnimation = currentAnimation; + + if (currentAnimation == null) { + this.currentSequence = null; + this.currentSequenceOrigin = null; + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerBuilder.java new file mode 100644 index 000000000..a7e1a4030 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerBuilder.java @@ -0,0 +1,65 @@ +package mod.azure.azurelib.core2.animation.controller; + +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyframeCallbacks; +import mod.azure.azurelib.core2.animation.easing.AzEasingType; +import mod.azure.azurelib.core2.animation.property.AzAnimationProperties; + +/** + * A builder class to construct {@link AzAnimationController} instances for managing animations in {@link AzAnimator}. + * This provides a fluent API to configure properties such as animation speed, keyframe callbacks, easing type, + * transition length, and triggerable animations. + * + * @param The type of object that the animation controller will operate on. + */ +public class AzAnimationControllerBuilder { + + private final AzAnimator animator; + + private final String name; + + private AzAnimationProperties animationProperties; + + private AzKeyframeCallbacks keyframeCallbacks; + + public AzAnimationControllerBuilder(AzAnimator animator, String name) { + this.animator = animator; + this.name = name; + this.animationProperties = AzAnimationProperties.DEFAULT; + this.keyframeCallbacks = AzKeyframeCallbacks.noop(); + } + + public AzAnimationControllerBuilder setAnimationSpeed(double animationSpeed) { + animationProperties = animationProperties.withAnimationSpeed(animationSpeed); + return this; + } + + public AzAnimationControllerBuilder setKeyframeCallbacks(@NotNull AzKeyframeCallbacks keyframeCallbacks) { + Objects.requireNonNull(keyframeCallbacks); + this.keyframeCallbacks = keyframeCallbacks; + return this; + } + + public AzAnimationControllerBuilder setEasingType(AzEasingType easingType) { + animationProperties = animationProperties.withEasingType(easingType); + return this; + } + + public AzAnimationControllerBuilder setTransitionLength(int transitionLength) { + animationProperties = animationProperties.withTransitionLength(transitionLength); + return this; + } + + public AzAnimationController build() { + return new AzAnimationController<>( + name, + animator, + animationProperties, + keyframeCallbacks + ); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerContainer.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerContainer.java new file mode 100644 index 000000000..e34db7834 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerContainer.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.core2.animation.controller; + +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Map; + +/** + * A container class for managing a collection of {@link AzAnimationController} instances. Provides methods to add, + * retrieve, and access animation controllers by their names. + * + * @param the type of the animation data or state managed by {@link AzAnimationController}. + */ +public class AzAnimationControllerContainer { + + private final Map> animationControllersByName; + + public AzAnimationControllerContainer() { + this.animationControllersByName = new Object2ObjectArrayMap<>(); + } + + @SafeVarargs + public final void add(AzAnimationController controller, AzAnimationController... controllers) { + animationControllersByName.put(controller.name(), controller); + + for (var extraController : controllers) { + animationControllersByName.put(extraController.name(), extraController); + } + } + + public @Nullable AzAnimationController getOrNull(String controllerName) { + return animationControllersByName.get(controllerName); + } + + public Collection> getAll() { + return animationControllersByName.values(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerTimer.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerTimer.java new file mode 100644 index 000000000..90b44d715 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationControllerTimer.java @@ -0,0 +1,48 @@ +package mod.azure.azurelib.core2.animation.controller; + +/** + * A timer utility that integrates directly with an {@link AzAnimationController} to track and adjust tick values for + * animation playback control, based on the controller's state and animation speed modifiers. + * + * @param The type of the animatable entity being controlled by the animation controller. + */ +public class AzAnimationControllerTimer { + + private final AzAnimationController animationController; + + private double adjustedTick; + + private double tickOffset; + + public AzAnimationControllerTimer(AzAnimationController animationController) { + this.animationController = animationController; + } + + /** + * Adjust a tick value depending on the controller's current state and speed modifier.
    + * Is used when starting a new animation, transitioning, and a few other key areas + */ + public void update() { + var stateMachine = animationController.stateMachine(); + var animContext = stateMachine.getContext().animationContext(); + var animationSpeed = animationController.animationProperties().animationSpeed(); + var tick = animContext.timer().getAnimTime(); + + adjustedTick = animationSpeed * Math.max(tick - tickOffset, 0); + } + + public void reset() { + var stateMachine = animationController.stateMachine(); + var animContext = stateMachine.getContext().animationContext(); + this.tickOffset = animContext.timer().getAnimTime(); + this.adjustedTick = 0; + } + + public double getAdjustedTick() { + return adjustedTick; + } + + public void addToAdjustedTick(double adjustedTick) { + this.adjustedTick += adjustedTick; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java new file mode 100644 index 000000000..4180d6ab3 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzAnimationQueue.java @@ -0,0 +1,52 @@ +package mod.azure.azurelib.core2.animation.controller; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.Queue; + +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; + +/** + * Represents a queue of animations to be processed in a sequential manner. This class manages a collection of + * {@link AzQueuedAnimation} objects, allowing animations to be queued, retrieved, and cleared efficiently. It ensures + * that animations are processed in the order they are added.
    + *
    + * The queue supports operations to inspect the next animation without removal, retrieve and remove the next animation, + * add individual or multiple animations, and clear the entire queue. Additionally, it provides a method to determine if + * the queue is empty. + */ +public class AzAnimationQueue { + + private final Queue animationQueue; + + public AzAnimationQueue() { + this.animationQueue = new LinkedList<>(); + } + + public void add(@NotNull AzQueuedAnimation queuedAnimation) { + animationQueue.add(queuedAnimation); + } + + public void addAll(@NotNull Collection queuedAnimations) { + animationQueue.addAll(queuedAnimations); + } + + public @Nullable AzQueuedAnimation peek() { + return animationQueue.peek(); + } + + public @Nullable AzQueuedAnimation next() { + return animationQueue.poll(); + } + + public void clear() { + animationQueue.clear(); + } + + public boolean isEmpty() { + return animationQueue.isEmpty(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java new file mode 100644 index 000000000..62d10f4a2 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneAnimationQueueCache.java @@ -0,0 +1,62 @@ +package mod.azure.azurelib.core2.animation.controller; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Map; + +import mod.azure.azurelib.core2.animation.AzBoneAnimationUpdateUtil; +import mod.azure.azurelib.core2.animation.cache.AzBoneCache; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimationQueue; +import mod.azure.azurelib.core2.animation.easing.AzEasingType; + +/** + * The AzBoneAnimationQueueCache class is responsible for managing and updating animation queues for bones. It acts as a + * cache that maps bone names to their respective animation queues, enabling efficient updates and access. + * + * @param the type of the animatable object used in the animation context + */ +public class AzBoneAnimationQueueCache { + + private final Map boneAnimationQueues; + + private final AzBoneCache boneCache; + + public AzBoneAnimationQueueCache(AzBoneCache boneCache) { + this.boneAnimationQueues = new Object2ObjectOpenHashMap<>(); + this.boneCache = boneCache; + } + + public void update(AzEasingType easingType) { + var boneSnapshots = boneCache.getBoneSnapshotsByName(); + + for (var boneAnimation : boneAnimationQueues.values()) { + var bone = boneAnimation.bone(); + var snapshot = boneSnapshots.get(bone.getName()); + var initialSnapshot = bone.getInitialAzSnapshot(); + + AzBoneAnimationUpdateUtil.updateRotations(boneAnimation, bone, easingType, initialSnapshot, snapshot); + AzBoneAnimationUpdateUtil.updatePositions(boneAnimation, bone, easingType, snapshot); + AzBoneAnimationUpdateUtil.updateScale(boneAnimation, bone, easingType, snapshot); + } + } + + public Collection values() { + return boneAnimationQueues.values(); + } + + public @Nullable AzBoneAnimationQueue getOrNull(String boneName) { + var bone = boneCache.getBakedModel().getBoneOrNull(boneName); + + if (bone == null) { + return null; + } + + return boneAnimationQueues.computeIfAbsent(boneName, $ -> new AzBoneAnimationQueue(bone)); + } + + public void clear() { + boneAnimationQueues.clear(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneSnapshotCache.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneSnapshotCache.java new file mode 100644 index 000000000..a9b07bf34 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/AzBoneSnapshotCache.java @@ -0,0 +1,54 @@ +package mod.azure.azurelib.core2.animation.controller; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Map; + +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; + +/** + * A cache system for managing and storing {@link AzBoneSnapshot} objects related to specific animations and their + * corresponding bone animations. This class is designed to optimize the retrieval and utilization of bone snapshots + * during animation interpolation (lerping).
    + *
    + * The cache works by filtering and storing relevant {@code AzBoneSnapshot} instances for a given + * {@link AzQueuedAnimation}, based on the associated bone animations defined within the animation. It ensures that only + * the required snapshots are cached, reducing redundancy and improving performance during animation processing. + */ +public class AzBoneSnapshotCache { + + private final Map boneSnapshots; + + public AzBoneSnapshotCache() { + this.boneSnapshots = new Object2ObjectOpenHashMap<>(); + } + + /** + * Cache the relevant {@link AzBoneSnapshot AzBoneSnapshots} for the current {@link AzQueuedAnimation} for animation + * lerping + * + * @param animation The {@code QueuedAnimation} to filter {@code BoneSnapshots} for + * @param snapshots The master snapshot collection to pull filter from + */ + public void put(AzQueuedAnimation animation, Collection snapshots) { + if (animation.animation().boneAnimations() == null) { + return; + } + + for (var snapshot : snapshots) { + for (var boneAnimation : animation.animation().boneAnimations()) { + if (boneAnimation.boneName().equals(snapshot.getBone().getName())) { + boneSnapshots.put(boneAnimation.boneName(), AzBoneSnapshot.copy(snapshot)); + break; + } + } + } + } + + public @Nullable AzBoneSnapshot getOrNull(String name) { + return boneSnapshots.get(name); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAbstractKeyframeExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAbstractKeyframeExecutor.java new file mode 100644 index 000000000..d0ae22e12 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAbstractKeyframeExecutor.java @@ -0,0 +1,79 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import java.util.List; + +import mod.azure.azurelib.core.keyframe.AnimationPoint; +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.keyframe.KeyframeLocation; +import mod.azure.azurelib.core.math.Constant; +import mod.azure.azurelib.core.math.IValue; +import mod.azure.azurelib.core.object.Axis; + +/** + * AzAbstractKeyframeExecutor is a base class designed to handle animations and transitions between keyframes in a + * generic and reusable fashion. It provides the foundational logic for determining the current state of an animation + * based on the tick time and computing the animation's required values. + */ +public class AzAbstractKeyframeExecutor { + + protected AzAbstractKeyframeExecutor() {} + + /** + * Convert a {@link KeyframeLocation} to an {@link AnimationPoint} + */ + protected AzAnimationPoint getAnimationPointAtTick( + List> frames, + double tick, + boolean isRotation, + Axis axis + ) { + var location = getCurrentKeyframeLocation(frames, tick); + var currentFrame = location.keyframe(); + var startValue = currentFrame.startValue().get(); + var endValue = currentFrame.endValue().get(); + + if (isRotation) { + if (!(currentFrame.startValue() instanceof Constant)) { + startValue = Math.toRadians(startValue); + + if (axis == Axis.X || axis == Axis.Y) { + startValue *= -1; + } + } + + if (!(currentFrame.endValue() instanceof Constant)) { + endValue = Math.toRadians(endValue); + + if (axis == Axis.X || axis == Axis.Y) { + endValue *= -1; + } + } + } + + return new AzAnimationPoint(currentFrame, location.startTick(), currentFrame.length(), startValue, endValue); + } + + /** + * Returns the {@link Keyframe} relevant to the current tick time + * + * @param frames The list of {@code Keyframes} to filter through + * @param ageInTicks The current tick time + * @return A new {@code KeyframeLocation} containing the current {@code Keyframe} and the tick time used to find it + */ + protected AzKeyframeLocation> getCurrentKeyframeLocation( + List> frames, + double ageInTicks + ) { + var totalFrameTime = 0.0; + + for (var frame : frames) { + totalFrameTime += frame.length(); + + if (totalFrameTime > ageInTicks) { + return new AzKeyframeLocation<>(frame, (ageInTicks - (totalFrameTime - frame.length()))); + } + } + + return new AzKeyframeLocation<>(frames.get(frames.size() - 1), ageInTicks); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAnimationPoint.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAnimationPoint.java new file mode 100644 index 000000000..fdfdea732 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzAnimationPoint.java @@ -0,0 +1,27 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +/** + * Animation state record that holds the state of an animation at a given point + * + * @param currentTick The lerped tick time (current tick + partial tick) of the point + * @param transitionLength The length of time (in ticks) that the point should take to transition + * @param animationStartValue The start value to provide to the animation handling system + * @param animationEndValue The end value to provide to the animation handling system + * @param keyframe The {@code Nullable} Keyframe + */ +public record AzAnimationPoint( + AzKeyframe keyframe, + double currentTick, + double transitionLength, + double animationStartValue, + double animationEndValue +) { + + @Override + public String toString() { + return "Tick: " + this.currentTick + + " | Transition Length: " + this.transitionLength + + " | Start Value: " + this.animationStartValue + + " | End Value: " + this.animationEndValue; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimation.java new file mode 100644 index 000000000..22038db50 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimation.java @@ -0,0 +1,20 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.math.IValue; + +/** + * A record of a deserialized animation for a given bone.
    + * Responsible for holding the various {@link Keyframe Keyframes} for the bone's animation transformations + * + * @param boneName The name of the bone as listed in the {@code animation.json} + * @param rotationKeyframes The deserialized rotation {@code Keyframe} stack + * @param positionKeyframes The deserialized position {@code Keyframe} stack + * @param scaleKeyframes The deserialized scale {@code Keyframe} stack + */ +public record AzBoneAnimation( + String boneName, + AzKeyframeStack> rotationKeyframes, + AzKeyframeStack> positionKeyframes, + AzKeyframeStack> scaleKeyframes +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java new file mode 100644 index 000000000..546bc8621 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzBoneAnimationQueue.java @@ -0,0 +1,400 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import java.util.LinkedList; +import java.util.Queue; + +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; + +/** + * A bone pseudo-stack for bone animation positions, scales, and rotations. Animation points are calculated then pushed + * onto their respective queues to be used for transformations in rendering + */ +public record AzBoneAnimationQueue( + AzBone bone, + Queue rotationXQueue, + Queue rotationYQueue, + Queue rotationZQueue, + Queue positionXQueue, + Queue positionYQueue, + Queue positionZQueue, + Queue scaleXQueue, + Queue scaleYQueue, + Queue scaleZQueue +) { + + public AzBoneAnimationQueue(AzBone bone) { + // TODO: Optimize + this( + bone, + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>(), + new LinkedList<>() + ); + } + + /** + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#positionXQueue} + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addPosXPoint( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.positionXQueue.add(new AzAnimationPoint(keyframe, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#positionYQueue} + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addPosYPoint( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.positionYQueue.add(new AzAnimationPoint(keyframe, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#positionZQueue} + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addPosZPoint( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.positionZQueue.add(new AzAnimationPoint(keyframe, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new X, Y, and Z position {@link AzAnimationPoint} to their respective queues + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (base on the {@link AzAnimationController} + * @param startSnapshot The {@link AzBoneSnapshot} that serves as the starting positions relevant to the keyframe + * provided + * @param nextXPoint The X {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextYPoint The Y {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextZPoint The Z {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + */ + public void addNextPosition( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + AzBoneSnapshot startSnapshot, + AzAnimationPoint nextXPoint, + AzAnimationPoint nextYPoint, + AzAnimationPoint nextZPoint + ) { + addPosXPoint( + keyframe, + lerpedTick, + transitionLength, + startSnapshot.getOffsetX(), + nextXPoint.animationStartValue() + ); + addPosYPoint( + keyframe, + lerpedTick, + transitionLength, + startSnapshot.getOffsetY(), + nextYPoint.animationStartValue() + ); + addPosZPoint( + keyframe, + lerpedTick, + transitionLength, + startSnapshot.getOffsetZ(), + nextZPoint.animationStartValue() + ); + } + + /** + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#scaleXQueue} + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addScaleXPoint( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.scaleXQueue.add(new AzAnimationPoint(keyframe, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#scaleYQueue} + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addScaleYPoint( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.scaleYQueue.add(new AzAnimationPoint(keyframe, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#scaleZQueue} + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addScaleZPoint( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.scaleZQueue.add(new AzAnimationPoint(keyframe, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new X, Y, and Z scale {@link AzAnimationPoint} to their respective queues + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (base on the {@link AzAnimationController} + * @param startSnapshot The {@link AzBoneSnapshot} that serves as the starting scales relevant to the keyframe + * provided + * @param nextXPoint The X {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextYPoint The Y {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextZPoint The Z {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + */ + public void addNextScale( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + AzBoneSnapshot startSnapshot, + AzAnimationPoint nextXPoint, + AzAnimationPoint nextYPoint, + AzAnimationPoint nextZPoint + ) { + addScaleXPoint( + keyframe, + lerpedTick, + transitionLength, + startSnapshot.getScaleX(), + nextXPoint.animationStartValue() + ); + addScaleYPoint( + keyframe, + lerpedTick, + transitionLength, + startSnapshot.getScaleY(), + nextYPoint.animationStartValue() + ); + addScaleZPoint( + keyframe, + lerpedTick, + transitionLength, + startSnapshot.getScaleZ(), + nextZPoint.animationStartValue() + ); + } + + /** + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#rotationXQueue} + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addRotationXPoint( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.rotationXQueue.add(new AzAnimationPoint(keyframe, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#rotationYQueue} + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addRotationYPoint( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.rotationYQueue.add(new AzAnimationPoint(keyframe, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new {@link AzAnimationPoint} to the {@link AzBoneAnimationQueue#rotationZQueue} + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (based on the {@link AzAnimationController}) + * @param startValue The value of the point at the start of its transition + * @param endValue The value of the point at the end of its transition + */ + public void addRotationZPoint( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + double startValue, + double endValue + ) { + this.rotationZQueue.add(new AzAnimationPoint(keyframe, lerpedTick, transitionLength, startValue, endValue)); + } + + /** + * Add a new X, Y, and Z scale {@link AzAnimationPoint} to their respective queues + * + * @param keyframe The {@code Nullable} Keyframe relevant to the animation point + * @param lerpedTick The lerped time (current tick + partial tick) that the point starts at + * @param transitionLength The length of the transition (base on the {@link AzAnimationController} + * @param startSnapshot The {@link AzBoneSnapshot} that serves as the starting rotations relevant to the keyframe + * provided + * @param initialSnapshot The {@link AzBoneSnapshot} that serves as the unmodified rotations of the bone + * @param nextXPoint The X {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextYPoint The Y {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + * @param nextZPoint The Z {@code AnimationPoint} that is next in the queue, to serve as the end value of the + * new point + */ + public void addNextRotation( + AzKeyframe keyframe, + double lerpedTick, + double transitionLength, + AzBoneSnapshot startSnapshot, + AzBoneSnapshot initialSnapshot, + AzAnimationPoint nextXPoint, + AzAnimationPoint nextYPoint, + AzAnimationPoint nextZPoint + ) { + addRotationXPoint( + keyframe, + lerpedTick, + transitionLength, + startSnapshot.getRotX() - initialSnapshot.getRotX(), + nextXPoint.animationStartValue() + ); + addRotationYPoint( + keyframe, + lerpedTick, + transitionLength, + startSnapshot.getRotY() - initialSnapshot.getRotY(), + nextYPoint.animationStartValue() + ); + addRotationZPoint( + keyframe, + lerpedTick, + transitionLength, + startSnapshot.getRotZ() - initialSnapshot.getRotZ(), + nextZPoint.animationStartValue() + ); + } + + /** + * Add an X, Y, and Z position {@link AzAnimationPoint} to their respective queues + * + * @param xPoint The x position {@code AnimationPoint} to add + * @param yPoint The y position {@code AnimationPoint} to add + * @param zPoint The z position {@code AnimationPoint} to add + */ + public void addPositions(AzAnimationPoint xPoint, AzAnimationPoint yPoint, AzAnimationPoint zPoint) { + this.positionXQueue.add(xPoint); + this.positionYQueue.add(yPoint); + this.positionZQueue.add(zPoint); + } + + /** + * Add an X, Y, and Z scale {@link AzAnimationPoint} to their respective queues + * + * @param xPoint The x scale {@code AnimationPoint} to add + * @param yPoint The y scale {@code AnimationPoint} to add + * @param zPoint The z scale {@code AnimationPoint} to add + */ + public void addScales(AzAnimationPoint xPoint, AzAnimationPoint yPoint, AzAnimationPoint zPoint) { + this.scaleXQueue.add(xPoint); + this.scaleYQueue.add(yPoint); + this.scaleZQueue.add(zPoint); + } + + /** + * Add an X, Y, and Z rotation {@link AzAnimationPoint} to their respective queues + * + * @param xPoint The x rotation {@code AnimationPoint} to add + * @param yPoint The y rotation {@code AnimationPoint} to add + * @param zPoint The z rotation {@code AnimationPoint} to add + */ + public void addRotations(AzAnimationPoint xPoint, AzAnimationPoint yPoint, AzAnimationPoint zPoint) { + this.rotationXQueue.add(xPoint); + this.rotationYQueue.add(yPoint); + this.rotationZQueue.add(zPoint); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframe.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframe.java new file mode 100644 index 000000000..211d473b9 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframe.java @@ -0,0 +1,57 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +import java.util.List; +import java.util.Objects; + +import mod.azure.azurelib.core.math.IValue; +import mod.azure.azurelib.core2.animation.easing.AzEasingType; +import mod.azure.azurelib.core2.animation.easing.AzEasingTypes; + +/** + * Animation keyframe data + * + * @param length The length (in ticks) the keyframe lasts for + * @param startValue The value to start the keyframe's transformation with + * @param endValue The value to end the keyframe's transformation with + * @param easingType The {@code EasingType} to use for transformations + * @param easingArgs The arguments to provide to the easing calculation + */ +public record AzKeyframe( + double length, + T startValue, + T endValue, + AzEasingType easingType, + List easingArgs +) { + + public AzKeyframe(double length, T startValue, T endValue) { + this(length, startValue, endValue, AzEasingTypes.LINEAR); + } + + public AzKeyframe(double length, T startValue, T endValue, AzEasingType easingType) { + this(length, startValue, endValue, easingType, new ObjectArrayList<>(0)); + } + + @Override + public int hashCode() { + return Objects.hash(this.length, this.startValue, this.endValue, this.easingType, this.easingArgs); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + + if (obj == null || getClass() != obj.getClass()) + return false; + + return hashCode() == obj.hashCode(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeCallbackHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeCallbackHandler.java new file mode 100644 index 000000000..25142e732 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeCallbackHandler.java @@ -0,0 +1,127 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Set; + +import mod.azure.azurelib.core.keyframe.event.data.KeyFrameData; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; +import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; +import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; + +/** + * AzKeyframeCallbackHandler acts as a handler for managing animation keyframe events such as sound, particle, or custom + * events during a specific animation. It works in conjunction with an animation controller and a set of keyframe + * callbacks, executing them as appropriate based on the animation's progress.
    + * This class is generic and operates on a user-defined animatable type to handle various keyframe events related to + * animations. + * + * @param the type of the animatable object being handled + */ +// TODO: reduce the boilerplate of the specialized handle functions in this class. +public class AzKeyframeCallbackHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(AzKeyframeCallbackHandler.class); + + private final AzAnimationController animationController; + + private final Set executedKeyframes; + + private final AzKeyframeCallbacks keyframeCallbacks; + + public AzKeyframeCallbackHandler( + AzAnimationController animationController, + AzKeyframeCallbacks keyframeCallbacks + ) { + this.animationController = animationController; + this.executedKeyframes = new ObjectOpenHashSet<>(); + this.keyframeCallbacks = keyframeCallbacks; + } + + public void handle(T animatable, double adjustedTick) { + handleSoundKeyframes(animatable, adjustedTick); + handleParticleKeyframes(animatable, adjustedTick); + handleCustomKeyframes(animatable, adjustedTick); + } + + private void handleCustomKeyframes(T animatable, double adjustedTick) { + var customKeyframeHandler = keyframeCallbacks.customKeyframeHandler(); + var customInstructions = currentAnimation().animation().keyframes().customInstructions(); + + for (var keyframeData : customInstructions) { + if (adjustedTick >= keyframeData.getStartTick() && executedKeyframes.add(keyframeData)) { + if (customKeyframeHandler == null) { + LOGGER.warn( + "Custom Instruction Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + animationController.name() + ); + break; + } + + customKeyframeHandler.handle( + new AzCustomInstructionKeyframeEvent<>(animatable, adjustedTick, animationController, keyframeData) + ); + } + } + } + + private void handleParticleKeyframes(T animatable, double adjustedTick) { + var particleKeyframeHandler = keyframeCallbacks.particleKeyframeHandler(); + var particleInstructions = currentAnimation().animation().keyframes().particles(); + + for (var keyframeData : particleInstructions) { + if (adjustedTick >= keyframeData.getStartTick() && executedKeyframes.add(keyframeData)) { + if (particleKeyframeHandler == null) { + LOGGER.warn( + "Particle Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + animationController.name() + ); + break; + } + + particleKeyframeHandler.handle( + new AzParticleKeyframeEvent<>(animatable, adjustedTick, animationController, keyframeData) + ); + } + } + } + + private void handleSoundKeyframes(T animatable, double adjustedTick) { + var soundKeyframeHandler = keyframeCallbacks.soundKeyframeHandler(); + var soundInstructions = currentAnimation().animation().keyframes().sounds(); + + for (var keyframeData : soundInstructions) { + if (adjustedTick >= keyframeData.getStartTick() && executedKeyframes.add(keyframeData)) { + if (soundKeyframeHandler == null) { + LOGGER.warn( + "Sound Keyframe found for {} -> {}, but no keyframe handler registered", + animatable.getClass().getSimpleName(), + animationController.name() + ); + break; + } + + soundKeyframeHandler.handle( + new AzSoundKeyframeEvent<>(animatable, adjustedTick, animationController, keyframeData) + ); + } + } + } + + /** + * Clear the {@link KeyFrameData} cache in preparation for the next animation + */ + public void reset() { + executedKeyframes.clear(); + } + + private AzQueuedAnimation currentAnimation() { + return animationController.currentAnimation(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeCallbacks.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeCallbacks.java new file mode 100644 index 000000000..cf6ff6d52 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeCallbacks.java @@ -0,0 +1,106 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.animation.controller.keyframe.handler.AzCustomKeyframeHandler; +import mod.azure.azurelib.core2.animation.controller.keyframe.handler.AzParticleKeyframeHandler; +import mod.azure.azurelib.core2.animation.controller.keyframe.handler.AzSoundKeyframeHandler; +import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; +import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; +import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; + +/** + * The AzKeyframeCallbacks class manages callbacks for different types of keyframe events, enabling the handling of + * sound, particle, and custom-defined keyframe instructions during an animation sequence. + * + * @param The type of entity or object this keyframe callback interacts with. + */ +public class AzKeyframeCallbacks { + + private static final AzKeyframeCallbacks NO_OP = new AzKeyframeCallbacks<>(null, null, null); + + @SuppressWarnings("unchecked") + public static AzKeyframeCallbacks noop() { + return (AzKeyframeCallbacks) NO_OP; + } + + private final @Nullable AzCustomKeyframeHandler customKeyframeHandler; + + private final @Nullable AzParticleKeyframeHandler particleKeyframeHandler; + + private final @Nullable AzSoundKeyframeHandler soundKeyframeHandler; + + private AzKeyframeCallbacks( + @Nullable AzCustomKeyframeHandler customKeyframeHandler, + @Nullable AzParticleKeyframeHandler particleKeyframeHandler, + @Nullable AzSoundKeyframeHandler soundKeyframeHandler + ) { + this.customKeyframeHandler = customKeyframeHandler; + this.particleKeyframeHandler = particleKeyframeHandler; + this.soundKeyframeHandler = soundKeyframeHandler; + } + + public @Nullable AzCustomKeyframeHandler customKeyframeHandler() { + return customKeyframeHandler; + } + + public @Nullable AzParticleKeyframeHandler particleKeyframeHandler() { + return particleKeyframeHandler; + } + + public @Nullable AzSoundKeyframeHandler soundKeyframeHandler() { + return soundKeyframeHandler; + } + + public static Builder builder() { + return new Builder<>(); + } + + public static class Builder { + + private @Nullable AzCustomKeyframeHandler customKeyframeHandler; + + private @Nullable AzParticleKeyframeHandler particleKeyframeHandler; + + private @Nullable AzSoundKeyframeHandler soundKeyframeHandler; + + private Builder() {} + + /** + * Applies the given {@link AzSoundKeyframeHandler} to this controller, for handling {@link AzSoundKeyframeEvent + * sound keyframe instructions}. + * + * @return this + */ + public Builder setSoundKeyframeHandler(AzSoundKeyframeHandler soundHandler) { + this.soundKeyframeHandler = soundHandler; + return this; + } + + /** + * Applies the given {@link AzParticleKeyframeHandler} to this controller, for handling + * {@link AzParticleKeyframeEvent particle keyframe instructions}. + * + * @return this + */ + public Builder setParticleKeyframeHandler(AzParticleKeyframeHandler particleHandler) { + this.particleKeyframeHandler = particleHandler; + return this; + } + + /** + * Applies the given {@link AzCustomKeyframeHandler} to this controller, for handling + * {@link AzCustomInstructionKeyframeEvent sound keyframe instructions}. + * + * @return this + */ + public Builder setCustomInstructionKeyframeHandler(AzCustomKeyframeHandler customInstructionHandler) { + this.customKeyframeHandler = customInstructionHandler; + return this; + } + + public AzKeyframeCallbacks build() { + return new AzKeyframeCallbacks<>(customKeyframeHandler, particleKeyframeHandler, soundKeyframeHandler); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeExecutor.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeExecutor.java new file mode 100644 index 000000000..fc32ec276 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeExecutor.java @@ -0,0 +1,127 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import org.jetbrains.annotations.NotNull; + +import java.util.NoSuchElementException; + +import mod.azure.azurelib.core.math.IValue; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.MolangQueries; +import mod.azure.azurelib.core.object.Axis; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; +import mod.azure.azurelib.core2.animation.primitive.AzQueuedAnimation; + +/** + * AzKeyframeExecutor is a specialized implementation of {@link AzAbstractKeyframeExecutor}, designed to handle + * keyframe-based animations for animatable objects. It delegates animation control to an {@link AzAnimationController} + * and manages bone animation queues through an {@link AzBoneAnimationQueueCache}.
    + * This class processes and applies transformations such as rotation, position, and scale to bone animations, based on + * the current tick time and the keyframes associated with each bone animation. + * + * @param The type of the animatable object to which the keyframe animations will be applied + */ +public class AzKeyframeExecutor extends AzAbstractKeyframeExecutor { + + private final AzAnimationController animationController; + + private final AzBoneAnimationQueueCache boneAnimationQueueCache; + + public AzKeyframeExecutor( + AzAnimationController animationController, + AzBoneAnimationQueueCache boneAnimationQueueCache + ) { + this.animationController = animationController; + this.boneAnimationQueueCache = boneAnimationQueueCache; + } + + /** + * Handle the current animation's state modifications and translations + * + * @param crashWhenCantFindBone Whether the controller should throw an exception when unable to find the required + * bone, or continue with the remaining bones + */ + public void execute(@NotNull AzQueuedAnimation currentAnimation, T animatable, boolean crashWhenCantFindBone) { + var keyframeCallbackHandler = animationController.keyframeManager().keyframeCallbackHandler(); + var controllerTimer = animationController.controllerTimer(); + var transitionLength = animationController.animationProperties().transitionLength(); + + final double finalAdjustedTick = controllerTimer.getAdjustedTick(); + + MolangParser.INSTANCE.setMemoizedValue(MolangQueries.ANIM_TIME, () -> finalAdjustedTick / 20d); + + for (var boneAnimation : currentAnimation.animation().boneAnimations()) { + var boneAnimationQueue = boneAnimationQueueCache.getOrNull(boneAnimation.boneName()); + + if (boneAnimationQueue == null) { + if (crashWhenCantFindBone) { + throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); + } + + continue; + } + + var rotationKeyframes = boneAnimation.rotationKeyframes(); + var positionKeyframes = boneAnimation.positionKeyframes(); + var scaleKeyframes = boneAnimation.scaleKeyframes(); + var adjustedTick = controllerTimer.getAdjustedTick(); + + updateRotation(rotationKeyframes, boneAnimationQueue, adjustedTick); + updatePosition(positionKeyframes, boneAnimationQueue, adjustedTick); + updateScale(scaleKeyframes, boneAnimationQueue, adjustedTick); + } + + // TODO: Is this correct??? + controllerTimer.addToAdjustedTick(transitionLength); + + keyframeCallbackHandler.handle(animatable, controllerTimer.getAdjustedTick()); + } + + private void updateRotation( + AzKeyframeStack> keyframes, + AzBoneAnimationQueue queue, + double adjustedTick + ) { + if (keyframes.xKeyframes().isEmpty()) { + return; + } + + var x = getAnimationPointAtTick(keyframes.xKeyframes(), adjustedTick, true, Axis.X); + var y = getAnimationPointAtTick(keyframes.yKeyframes(), adjustedTick, true, Axis.Y); + var z = getAnimationPointAtTick(keyframes.zKeyframes(), adjustedTick, true, Axis.Z); + + queue.addRotations(x, y, z); + } + + private void updatePosition( + AzKeyframeStack> keyframes, + AzBoneAnimationQueue queue, + double adjustedTick + ) { + if (keyframes.xKeyframes().isEmpty()) { + return; + } + + var x = getAnimationPointAtTick(keyframes.xKeyframes(), adjustedTick, false, Axis.X); + var y = getAnimationPointAtTick(keyframes.yKeyframes(), adjustedTick, false, Axis.Y); + var z = getAnimationPointAtTick(keyframes.zKeyframes(), adjustedTick, false, Axis.Z); + + queue.addPositions(x, y, z); + } + + private void updateScale( + AzKeyframeStack> keyframes, + AzBoneAnimationQueue queue, + double adjustedTick + ) { + if (keyframes.xKeyframes().isEmpty()) { + return; + } + + var x = getAnimationPointAtTick(keyframes.xKeyframes(), adjustedTick, false, Axis.X); + var y = getAnimationPointAtTick(keyframes.yKeyframes(), adjustedTick, false, Axis.Y); + var z = getAnimationPointAtTick(keyframes.zKeyframes(), adjustedTick, false, Axis.Z); + + queue.addScales(x, y, z); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeLocation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeLocation.java new file mode 100644 index 000000000..b0e8df457 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeLocation.java @@ -0,0 +1,14 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import mod.azure.azurelib.core.keyframe.Keyframe; + +/** + * A named pair object that stores a {@link Keyframe} and a double representing a temporally placed {@code Keyframe} + * + * @param keyframe The {@code Keyframe} at the tick time + * @param startTick The animation tick time at the start of this {@code Keyframe} + */ +public record AzKeyframeLocation>( + T keyframe, + double startTick +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeManager.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeManager.java new file mode 100644 index 000000000..10c706196 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeManager.java @@ -0,0 +1,47 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; +import mod.azure.azurelib.core2.animation.controller.AzBoneSnapshotCache; + +/** + * AzKeyframeManager is responsible for managing the keyframe-related operations in an animation system. It coordinates + * the execution, transition, and callback handling of animation keyframes through its associated components. + * + * @param the type of the animatable object being handled + */ +public class AzKeyframeManager { + + private final AzKeyframeCallbackHandler keyframeCallbackHandler; + + private final AzKeyframeExecutor keyframeExecutor; + + private final AzKeyframeTransitioner keyframeTransitioner; + + public AzKeyframeManager( + AzAnimationController animationController, + AzBoneAnimationQueueCache boneAnimationQueueCache, + AzBoneSnapshotCache boneSnapshotCache, + AzKeyframeCallbacks keyframeCallbacks + ) { + this.keyframeCallbackHandler = new AzKeyframeCallbackHandler<>(animationController, keyframeCallbacks); + this.keyframeExecutor = new AzKeyframeExecutor<>(animationController, boneAnimationQueueCache); + this.keyframeTransitioner = new AzKeyframeTransitioner<>( + animationController, + boneAnimationQueueCache, + boneSnapshotCache + ); + } + + public AzKeyframeCallbackHandler keyframeCallbackHandler() { + return keyframeCallbackHandler; + } + + public AzKeyframeExecutor keyframeExecutor() { + return keyframeExecutor; + } + + public AzKeyframeTransitioner keyframeTransitioner() { + return keyframeTransitioner; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeStack.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeStack.java new file mode 100644 index 000000000..c11a21529 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeStack.java @@ -0,0 +1,43 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + +import java.util.List; + +/** + * Stores a triplet of {@link AzKeyframe Keyframes} in an ordered stack + */ +public record AzKeyframeStack>( + List xKeyframes, + List yKeyframes, + List zKeyframes +) { + + public AzKeyframeStack() { + this(new ObjectArrayList<>(), new ObjectArrayList<>(), new ObjectArrayList<>()); + } + + public static > AzKeyframeStack from(AzKeyframeStack otherStack) { + return new AzKeyframeStack<>(otherStack.xKeyframes, otherStack.yKeyframes, otherStack.zKeyframes); + } + + public double getLastKeyframeTime() { + double xTime = 0; + double yTime = 0; + double zTime = 0; + + for (T frame : xKeyframes()) { + xTime += frame.length(); + } + + for (T frame : yKeyframes()) { + yTime += frame.length(); + } + + for (T frame : zKeyframes()) { + zTime += frame.length(); + } + + return Math.max(xTime, Math.max(yTime, zTime)); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeTransitioner.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeTransitioner.java new file mode 100644 index 000000000..250cb60f5 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/AzKeyframeTransitioner.java @@ -0,0 +1,125 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe; + +import java.util.Map; +import java.util.NoSuchElementException; + +import mod.azure.azurelib.core.math.IValue; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.MolangQueries; +import mod.azure.azurelib.core.object.Axis; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzBoneAnimationQueueCache; +import mod.azure.azurelib.core2.animation.controller.AzBoneSnapshotCache; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneSnapshot; + +/** + * AzKeyframeTransitioner is a specialized class for executing smooth animations and transitions between keyframes for + * bones in an animation system. It utilizes animation controllers, bone animation queue caches, and bone snapshot + * caches to manage and apply transitions for rotation, position, and scale of bones. + * + * @param The type of the animation data handled by the associated animation controller. + */ +public class AzKeyframeTransitioner extends AzAbstractKeyframeExecutor { + + private final AzAnimationController animationController; + + private final AzBoneAnimationQueueCache boneAnimationQueueCache; + + private final AzBoneSnapshotCache boneSnapshotCache; + + public AzKeyframeTransitioner( + AzAnimationController animationController, + AzBoneAnimationQueueCache boneAnimationQueueCache, + AzBoneSnapshotCache boneSnapshotCache + ) { + this.animationController = animationController; + this.boneAnimationQueueCache = boneAnimationQueueCache; + this.boneSnapshotCache = boneSnapshotCache; + } + + public void transition(Map bones, boolean crashWhenCantFindBone, double adjustedTick) { + var currentAnimation = animationController.currentAnimation(); + var transitionLength = animationController.animationProperties().transitionLength(); + + MolangParser.INSTANCE.setValue(MolangQueries.ANIM_TIME, () -> 0); + + for (var boneAnimation : currentAnimation.animation().boneAnimations()) { + var bone = bones.get(boneAnimation.boneName()); + + if (bone == null) { + if (crashWhenCantFindBone) + throw new NoSuchElementException("Could not find bone: " + boneAnimation.boneName()); + + continue; + } + + var queue = boneAnimationQueueCache.getOrNull(boneAnimation.boneName()); + var snapshot = boneSnapshotCache.getOrNull(boneAnimation.boneName()); + + var rotationKeyframes = boneAnimation.rotationKeyframes(); + var positionKeyframes = boneAnimation.positionKeyframes(); + var scaleKeyframes = boneAnimation.scaleKeyframes(); + + transitionRotation(adjustedTick, rotationKeyframes, queue, transitionLength, snapshot, bone); + transitionPosition(adjustedTick, positionKeyframes, queue, transitionLength, snapshot); + transitionScale(adjustedTick, scaleKeyframes, queue, transitionLength, snapshot); + } + } + + private void transitionRotation( + double adjustedTick, + AzKeyframeStack> keyframes, + AzBoneAnimationQueue queue, + double transitionLength, + AzBoneSnapshot snapshot, + AzBone bone + ) { + if (keyframes.xKeyframes().isEmpty()) { + return; + } + + var initialSnapshot = bone.getInitialAzSnapshot(); + var x = getAnimationPointAtTick(keyframes.xKeyframes(), 0, true, Axis.X); + var y = getAnimationPointAtTick(keyframes.yKeyframes(), 0, true, Axis.Y); + var z = getAnimationPointAtTick(keyframes.zKeyframes(), 0, true, Axis.Z); + + queue.addNextRotation(null, adjustedTick, transitionLength, snapshot, initialSnapshot, x, y, z); + } + + private void transitionPosition( + double adjustedTick, + AzKeyframeStack> keyframes, + AzBoneAnimationQueue queue, + double transitionLength, + AzBoneSnapshot snapshot + ) { + if (keyframes.xKeyframes().isEmpty()) { + return; + } + + var x = getAnimationPointAtTick(keyframes.xKeyframes(), 0, false, Axis.X); + var y = getAnimationPointAtTick(keyframes.yKeyframes(), 0, false, Axis.Y); + var z = getAnimationPointAtTick(keyframes.zKeyframes(), 0, false, Axis.Z); + + queue.addNextPosition(null, adjustedTick, transitionLength, snapshot, x, y, z); + } + + private void transitionScale( + double adjustedTick, + AzKeyframeStack> keyframes, + AzBoneAnimationQueue queue, + double transitionLength, + AzBoneSnapshot snapshot + ) { + if (keyframes.xKeyframes().isEmpty()) { + return; + } + + var x = getAnimationPointAtTick(keyframes.xKeyframes(), 0, false, Axis.X); + var y = getAnimationPointAtTick(keyframes.yKeyframes(), 0, false, Axis.Y); + var z = getAnimationPointAtTick(keyframes.zKeyframes(), 0, false, Axis.Z); + + queue.addNextScale(null, adjustedTick, transitionLength, snapshot, x, y, z); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzCustomKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzCustomKeyframeHandler.java new file mode 100644 index 000000000..02a5b4907 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzCustomKeyframeHandler.java @@ -0,0 +1,14 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe.handler; + +import mod.azure.azurelib.core2.animation.event.AzCustomInstructionKeyframeEvent; + +/** + * A handler for pre-defined custom instruction keyframes. When the keyframe is encountered, the + * {@link AzCustomKeyframeHandler#handle(AzCustomInstructionKeyframeEvent)} method will be called. You can then take + * whatever action you want at this point. + */ +@FunctionalInterface +public interface AzCustomKeyframeHandler { + + void handle(AzCustomInstructionKeyframeEvent event); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzParticleKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzParticleKeyframeHandler.java new file mode 100644 index 000000000..48ea313a9 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzParticleKeyframeHandler.java @@ -0,0 +1,14 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe.handler; + +import mod.azure.azurelib.core2.animation.event.AzParticleKeyframeEvent; + +/** + * A handler for when a predefined particle keyframe is hit. When the keyframe is encountered, the + * {@link AzParticleKeyframeHandler#handle(AzParticleKeyframeEvent)} method will be called. Spawn the particles/effects + * of your choice at this time. + */ +@FunctionalInterface +public interface AzParticleKeyframeHandler { + + void handle(AzParticleKeyframeEvent event); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzSoundKeyframeHandler.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzSoundKeyframeHandler.java new file mode 100644 index 000000000..e8cf45c5c --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/keyframe/handler/AzSoundKeyframeHandler.java @@ -0,0 +1,14 @@ +package mod.azure.azurelib.core2.animation.controller.keyframe.handler; + +import mod.azure.azurelib.core2.animation.event.AzSoundKeyframeEvent; + +/** + * A handler for when a predefined sound keyframe is hit. When the keyframe is encountered, the + * {@link AzSoundKeyframeHandler#handle(AzSoundKeyframeEvent)} method will be called. Play the sound(s) of your choice + * at this time. + */ +@FunctionalInterface +public interface AzSoundKeyframeHandler { + + void handle(AzSoundKeyframeEvent event); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/AzAnimationState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/AzAnimationState.java new file mode 100644 index 000000000..56e2c8ad1 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/AzAnimationState.java @@ -0,0 +1,41 @@ +package mod.azure.azurelib.core2.animation.controller.state; + +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; +import mod.azure.azurelib.core2.util.state.State; + +/** + * Represents an abstract animation state within the {@link AzAnimationControllerStateMachine}. Each concrete + * implementation of this class defines specific behavior for managing animations during state transitions.
    + *
    + * The animation state lifecycle consists of three primary methods: + *
      + *
    • {@code onEnter}: Invoked when the state is entered. This method is used for initializing the state.
    • + *
    • {@code onUpdate}: Should be implemented by subclasses to define the behavior during the state's execution.
    • + *
    • {@code onExit}: Invoked when transitioning out of the state. This method is used for cleanup or + * finalization.
    • + *
    + * + * @param the type of the animation context associated with this state + */ +public abstract class AzAnimationState implements State> { + + private boolean isActive; + + protected AzAnimationState() { + this.isActive = false; + } + + @Override + public void onEnter(AzAnimationControllerStateMachine.Context context) { + this.isActive = true; + } + + public boolean isActive() { + return isActive; + } + + @Override + public void onExit(AzAnimationControllerStateMachine.Context context) { + this.isActive = false; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java new file mode 100644 index 000000000..0b50e0ea6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPauseState.java @@ -0,0 +1,25 @@ +package mod.azure.azurelib.core2.animation.controller.state.impl; + +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; + +/** + * Represents the paused state in the animation state machine. This state ensures no updates are applied to the + * animation while it is paused, maintaining its current state until it is transitioned back to a play or stop state. + * + * @param the type of animation managed by the state + */ +public final class AzAnimationPauseState extends AzAnimationPlayState { + + public AzAnimationPauseState() {} + + @Override + public void onEnter(AzAnimationControllerStateMachine.Context context) { + // Do nothing, because the pause state shouldn't reset on enter. + } + + @Override + public void onUpdate(AzAnimationControllerStateMachine.Context context) { + super.onUpdate(context); + // Pause state does not need to do anything. + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java new file mode 100644 index 000000000..001b03d65 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationPlayState.java @@ -0,0 +1,89 @@ +package mod.azure.azurelib.core2.animation.controller.state.impl; + +import mod.azure.azurelib.core2.animation.controller.state.AzAnimationState; +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; + +/** + * Represents a "play" state in an animation state machine. This state is responsible for managing the playing of + * animations either by starting from the beginning or playing subsequent animations. It ensures that the animation + * progresses based on the controller's timer and handles transitions when animations complete.
    + *
    + * Inherits general animation state behavior such as lifecycle management from {@link AzAnimationState}. + * + * @param the type of animation being managed + */ +public class AzAnimationPlayState extends AzAnimationState { + + public AzAnimationPlayState() {} + + @Override + public void onEnter(AzAnimationControllerStateMachine.Context context) { + super.onEnter(context); + var controller = context.animationController(); + var controllerTimer = controller.controllerTimer(); + + controllerTimer.reset(); + } + + @Override + public void onUpdate(AzAnimationControllerStateMachine.Context context) { + var controller = context.animationController(); + var controllerTimer = controller.controllerTimer(); + var currentAnimation = controller.currentAnimation(); + + if (currentAnimation == null) { + // If the current animation is null, we should try to play the next animation. + tryPlayNextOrStop(context); + return; + } + + currentAnimation.playBehavior().onUpdate(context); + + // At this point we have an animation currently playing. We need to query if that animation has finished. + + var animContext = context.animationContext(); + var animatable = animContext.animatable(); + var hasAnimationFinished = controllerTimer.getAdjustedTick() >= currentAnimation.animation().length(); + + if (hasAnimationFinished) { + currentAnimation.playBehavior().onFinish(context); + } + + if (context.stateMachine().isStopped()) { + // Nothing more to do at this point since we can't play the animation again, so return. + return; + } + + // The animation is still running at this point, proceed with updating the bones according to keyframes. + + var keyframeManager = controller.keyframeManager(); + var keyframeExecutor = keyframeManager.keyframeExecutor(); + var crashWhenCantFindBone = animContext.config().crashIfBoneMissing(); + + keyframeExecutor.execute(currentAnimation, animatable, crashWhenCantFindBone); + } + + private void tryPlayNextOrStop(AzAnimationControllerStateMachine.Context context) { + var controller = context.animationController(); + var stateMachine = context.stateMachine(); + var keyframeManager = controller.keyframeManager(); + var keyframeCallbackHandler = keyframeManager.keyframeCallbackHandler(); + + keyframeCallbackHandler.reset(); + + var animationQueue = controller.animationQueue(); + var nextAnimation = animationQueue.peek(); + var canPlayNextSuccessfully = nextAnimation != null; + + if (!canPlayNextSuccessfully) { + // If we can't play the next animation for some reason, then there's nothing to play. + // So we should put the state machine in the 'stop' state. + stateMachine.stop(); + return; + } + + // If we can play the next animation successfully, then let's do that. + stateMachine.transition(); + controller.setCurrentAnimation(nextAnimation); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationStopState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationStopState.java new file mode 100644 index 000000000..77c2d9327 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationStopState.java @@ -0,0 +1,25 @@ +package mod.azure.azurelib.core2.animation.controller.state.impl; + +import mod.azure.azurelib.core2.animation.controller.state.AzAnimationState; +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; + +/** + * Represents the "stop" state in an animation state machine. This state is responsible for halting any ongoing + * animations and putting the animation controller into a minimal responsibility state where no further updates or + * actions are performed until a new state transition occurs.
    + *
    + * This state is typically used when an animation sequence has fully completed and no
    + *
    + * Inherits the general animation state behavior and lifecycle from {@link AzAnimationState}. + * + * @param the type of animation context associated with the state machine + */ +public final class AzAnimationStopState extends AzAnimationState { + + public AzAnimationStopState() {} + + @Override + public void onUpdate(AzAnimationControllerStateMachine.Context context) { + // Stop state does not need to do anything. + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java new file mode 100644 index 000000000..92e832b42 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/impl/AzAnimationTransitionState.java @@ -0,0 +1,74 @@ +package mod.azure.azurelib.core2.animation.controller.state.impl; + +import mod.azure.azurelib.core2.animation.controller.state.AzAnimationState; +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; + +/** + * Represents a transition state in an animation state machine. This state is responsible for managing the transition + * between animations, including handling setup, updates, and transitioning to the appropriate play state when the + * transition is complete. The `AzAnimationTransitionState` extends the functionality of `AzAnimationState` to implement + * the behavior specific to transitioning between animations. It resets timers, initializes animations, and updates + * keyframes to create smooth transitions. + * + * @param the type of the animation context associated with this state + */ +public final class AzAnimationTransitionState extends AzAnimationState { + + public AzAnimationTransitionState() {} + + @Override + public void onEnter(AzAnimationControllerStateMachine.Context context) { + super.onEnter(context); + prepareTransition(context); + } + + @Override + public void onUpdate(AzAnimationControllerStateMachine.Context context) { + var controller = context.animationController(); + var controllerTimer = controller.controllerTimer(); + var animContext = context.animationContext(); + + var stateMachine = context.stateMachine(); + var boneCache = animContext.boneCache(); + + var transitionLength = controller.animationProperties().transitionLength(); + var hasFinishedTransitioning = controllerTimer.getAdjustedTick() >= transitionLength; + + if (hasFinishedTransitioning) { + // If we've exceeded the amount of time we should be transitioning, then switch to play state. + stateMachine.play(); + return; + } + + if (controller.currentAnimation() != null) { + var bones = boneCache.getBakedModel().getBonesByName(); + var crashWhenCantFindBone = animContext.config().crashIfBoneMissing(); + var keyframeTransitioner = controller.keyframeManager().keyframeTransitioner(); + + keyframeTransitioner.transition(bones, crashWhenCantFindBone, controllerTimer.getAdjustedTick()); + } + } + + private void prepareTransition(AzAnimationControllerStateMachine.Context context) { + var animContext = context.animationContext(); + var boneCache = animContext.boneCache(); + var controller = context.animationController(); + var boneSnapshotCache = controller.boneSnapshotCache(); + var controllerTimer = controller.controllerTimer(); + + controllerTimer.reset(); + controller.keyframeManager().keyframeCallbackHandler().reset(); + + var nextAnimation = controller.animationQueue().next(); + + if (nextAnimation == null) { + return; + } + + controller.setCurrentAnimation(nextAnimation); + + var snapshots = boneCache.getBoneSnapshotsByName(); + + boneSnapshotCache.put(nextAnimation, snapshots.values()); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java new file mode 100644 index 000000000..aaf4e4c3b --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/controller/state/machine/AzAnimationControllerStateMachine.java @@ -0,0 +1,105 @@ +package mod.azure.azurelib.core2.animation.controller.state.machine; + +import mod.azure.azurelib.core2.animation.AzAnimationContext; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.state.AzAnimationState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPauseState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationPlayState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationStopState; +import mod.azure.azurelib.core2.animation.controller.state.impl.AzAnimationTransitionState; +import mod.azure.azurelib.core2.util.state.StateMachine; +import mod.azure.azurelib.core2.util.state.StateMachineContext; + +/** + * A state machine for managing animation controller states, providing functionality to transition between play, pause, + * stop, and transition states. It is generic and supports handling context and states specific to animations. + * + * @param the type of the animation the state machine controls + */ +public class AzAnimationControllerStateMachine extends StateMachine, AzAnimationState> { + + private final StateHolder stateHolder; + + public AzAnimationControllerStateMachine( + StateHolder stateHolder, + AzAnimationController animationController, + AzAnimationContext animationContext + ) { + super(stateHolder.stopState()); + this.stateHolder = stateHolder; + getContext().stateMachine = this; + getContext().animationController = animationController; + getContext().animationContext = animationContext; + } + + @Override + public Context createContext() { + return new Context<>(); + } + + public void update() { + super.update(getContext()); + } + + public void pause() { + setState(stateHolder.pauseState); + } + + public void play() { + setState(stateHolder.playState); + } + + public void transition() { + setState(stateHolder.transitionState); + } + + public void stop() { + setState(stateHolder.stopState); + } + + public boolean isPlaying() { + return getState() == stateHolder.playState; + } + + public boolean isPaused() { + return getState() == stateHolder.pauseState; + } + + public boolean isStopped() { + return getState() == stateHolder.stopState; + } + + public boolean isTransitioning() { + return getState() == stateHolder.transitionState; + } + + public record StateHolder( + AzAnimationPlayState playState, + AzAnimationPauseState pauseState, + AzAnimationStopState stopState, + AzAnimationTransitionState transitionState + ) {} + + public static class Context implements StateMachineContext { + + private AzAnimationContext animationContext; + + private AzAnimationController animationController; + + private AzAnimationControllerStateMachine stateMachine; + + private Context() {} + + public AzAnimationContext animationContext() { + return animationContext; + } + + public AzAnimationController animationController() { + return animationController; + } + + public AzAnimationControllerStateMachine stateMachine() { + return stateMachine; + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchSide.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchSide.java new file mode 100644 index 000000000..f96472321 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/AzDispatchSide.java @@ -0,0 +1,47 @@ +package mod.azure.azurelib.core2.animation.dispatch; + +import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.util.StringRepresentable; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +/** + * This enum represents the dispatch side for animation commands, which can either be client-side or server-side. It is + * used as part of the AzureLib animation system for identifying where an animation command originates from or should be + * executed.
    + * Each enum constant has an associated unique identifier for easy lookup and transmission across the network. This + * mapping is also used within codecs for serialization and deserialization purposes. + */ +public enum AzDispatchSide implements StringRepresentable { + + CLIENT(0), + SERVER(1); + + private static final Map ID_TO_ENUM_MAP = new Int2ObjectArrayMap<>(); + + static { + // Populate the map for quick lookup + for (AzDispatchSide side : values()) { + ID_TO_ENUM_MAP.put(side.id, side); + } + } + + private final int id; + + AzDispatchSide(int id) { + this.id = id; + } + + public static final StreamCodec CODEC = StreamCodec.of( + (buf, val) -> buf.writeByte(val.id), + buf -> ID_TO_ENUM_MAP.get((int) buf.readByte()) + ); + + @Override + public @NotNull String getSerializedName() { + return name(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzCommand.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzCommand.java new file mode 100644 index 000000000..c743c96a4 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzCommand.java @@ -0,0 +1,160 @@ +package mod.azure.azurelib.core2.animation.dispatch.command; + +import mod.azure.azurelib.core2.animation.play_behavior.AzPlayBehavior; +import mod.azure.azurelib.core2.animation.play_behavior.AzPlayBehaviors; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.network.packet.AzBlockEntityDispatchCommandPacket; +import mod.azure.azurelib.common.internal.common.network.packet.AzEntityDispatchCommandPacket; +import mod.azure.azurelib.common.internal.common.network.packet.AzItemStackDispatchCommandPacket; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzAction; +import mod.azure.azurelib.core2.util.codec.AzListStreamCodec; + +/** + * Represents a command structure used to dispatch a sequence of actions in the animation system. This class primarily + * serves as a container for a list of {@link AzAction} instances that define specific operations or behaviors to be + * executed.
    + * The class provides support for building complex dispatch commands by leveraging the hierarchical builder system, + * enabling customization of animation-related functionality. + */ +public record AzCommand(List actions) { + + public static final StreamCodec CODEC = StreamCodec.composite( + new AzListStreamCodec<>(AzAction.CODEC), + AzCommand::actions, + AzCommand::new + ); + + public static AzRootCommandBuilder builder() { + return new AzRootCommandBuilder(); + } + + public static AzCommand compose(Collection commands) { + if (commands.isEmpty()) { + throw new IllegalArgumentException("Attempted to compose an empty collection of commands."); + } else if (commands.size() == 1) { + return commands.iterator().next(); + } + + return new AzCommand( + commands.stream() + .flatMap(command -> command.actions().stream()) + .toList() + ); + } + + public static AzCommand compose(AzCommand first, AzCommand second, AzCommand... others) { + var allCommands = new ArrayList(); + + allCommands.add(first); + allCommands.add(second); + Collections.addAll(allCommands, others); + + return compose(allCommands); + } + + public static AzCommand create(String controllerName, String animationName) { + return create(controllerName, animationName, AzPlayBehaviors.PLAY_ONCE); + } + + /** + * Creates a dispatch command to play a specified animation on a given controller. + * + * @param controllerName the name of the animation controller on which the animation should be played + * @param animationName the name of the animation to be played on the specified controller + * @param playBehavior the play behavior for the animation to use + * @return an instance of {@code AzCommand} representing the command to play the desired animation + */ + public static AzCommand create(String controllerName, String animationName, AzPlayBehavior playBehavior) { + return builder() + .playSequence( + controllerName, + sequenceBuilder -> sequenceBuilder.queue(animationName, props -> props.withPlayBehavior(playBehavior)) + ) + .build(); + } + + /** + * Sends animation commands for the specified entity based on the configured dispatch origin. The method determines + * whether the command should proceed, logs a warning if it cannot, and dispatches the animation commands either + * from the client or the server side. + * + * @param entity the target {@link Entity} for which the animation commands are dispatched. + */ + public void sendForEntity(Entity entity) { + if (entity.level().isClientSide()) { + dispatchFromClient(entity); + } else { + var entityId = entity.getId(); + var packet = new AzEntityDispatchCommandPacket(entityId, this); + Services.NETWORK.sendToTrackingEntityAndSelf(packet, entity); + } + } + + /** + * Sends animation commands for the specified block entity based on the configured dispatch origin. The method + * determines whether the command should proceed, logs a warning if it cannot, and dispatches the animation commands + * either from the client or the server side. + * + * @param entity the target {@link BlockEntity} for which the animation commands are dispatched. + */ + public void sendForBlockEntity(BlockEntity entity) { + if (entity.getLevel().isClientSide()) { + dispatchFromClient(entity); + } else { + var entityBlockPos = entity.getBlockPos(); + var packet = new AzBlockEntityDispatchCommandPacket(entityBlockPos, this); + Services.NETWORK.sendToEntitiesTrackingChunk(packet, (ServerLevel) entity.getLevel(), entityBlockPos); + } + } + + /** + * Sends animation commands for the specified item based on the configured dispatch origin. The method determines + * whether the command can proceed, assigns a unique identifier to the item if required, and dispatches the + * animation commands either from the client or the server side. + * + * @param entity the {@link Entity} associated with the {@link ItemStack}. + * @param itemStack the {@link ItemStack} on which the animation commands are dispatched. + */ + public void sendForItem(Entity entity, ItemStack itemStack) { + if (entity.level().isClientSide()) { + dispatchFromClient(entity); + } else { + var uuid = itemStack.get(AzureLib.AZ_ID.get()); + + if (uuid == null) { + AzureLib.LOGGER.warn( + "Could not find item stack UUID during dispatch. Did you forget to register an identity for the item? Item: {}, Item Stack: {}", + itemStack.getItem(), + itemStack + ); + return; + } + + var packet = new AzItemStackDispatchCommandPacket(uuid, this); + Services.NETWORK.sendToTrackingEntityAndSelf(packet, entity); + } + } + + private void dispatchFromClient(T animatable) { + var animator = AzAnimatorAccessor.getOrNull(animatable); + + if (animator != null) { + actions.forEach(action -> action.handle(AzDispatchSide.CLIENT, animator)); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzCommandBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzCommandBuilder.java new file mode 100644 index 000000000..3f795109e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzCommandBuilder.java @@ -0,0 +1,19 @@ +package mod.azure.azurelib.core2.animation.dispatch.command; + +import java.util.ArrayList; +import java.util.List; + +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzAction; + +public abstract class AzCommandBuilder { + + protected final List actions; + + protected AzCommandBuilder() { + this.actions = new ArrayList<>(); + } + + public AzCommand build() { + return new AzCommand(actions); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzRootCommandBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzRootCommandBuilder.java new file mode 100644 index 000000000..e91e753f5 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/AzRootCommandBuilder.java @@ -0,0 +1,58 @@ +package mod.azure.azurelib.core2.animation.dispatch.command; + +import java.util.function.UnaryOperator; + +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAllAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootPlayAnimationSequenceAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootSetAnimationSpeedAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootSetEasingTypeAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootSetTransitionSpeedAction; +import mod.azure.azurelib.core2.animation.dispatch.command.sequence.AzAnimationSequenceBuilder; +import mod.azure.azurelib.core2.animation.easing.AzEasingType; + +public class AzRootCommandBuilder extends AzCommandBuilder { + + public AzRootCommandBuilder append(AzCommand command) { + actions.addAll(command.actions()); + return this; + } + + public AzRootCommandBuilder cancelAll() { + actions.add(new AzRootCancelAllAction()); + return this; + } + + public AzRootCommandBuilder setEasingType(AzEasingType easingType) { + actions.add(new AzRootSetEasingTypeAction(easingType)); + return this; + } + + public AzRootCommandBuilder setSpeed(float speed) { + actions.add(new AzRootSetAnimationSpeedAction(speed)); + return this; + } + + public AzRootCommandBuilder setTransitionSpeed(float transitionSpeed) { + actions.add(new AzRootSetTransitionSpeedAction(transitionSpeed)); + return this; + } + + public AzRootCommandBuilder cancel(String controllerName) { + actions.add(new AzRootCancelAction(controllerName)); + return this; + } + + public AzRootCommandBuilder play(String controllerName, String animationName) { + return playSequence(controllerName, builder -> builder.queue(animationName)); + } + + public AzRootCommandBuilder playSequence( + String controllerName, + UnaryOperator builderUnaryOperator + ) { + var sequence = builderUnaryOperator.apply(new AzAnimationSequenceBuilder()).build(); + actions.add(new AzRootPlayAnimationSequenceAction(controllerName, sequence)); + return this; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/AzAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/AzAction.java new file mode 100644 index 000000000..f2cf42b40 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/AzAction.java @@ -0,0 +1,22 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action; + +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.action.codec.AzActionCodec; + +/** + * The AzAction interface serves as a base contract for defining actions that can be dispatched within the animation + * system. It provides methods for handling an action and retrieving its unique resource location identifier. + * Implementations of this interface encapsulate specific animation-related behaviors, allowing for the modification or + * control of animation states or properties within an {@link AzAnimator}. + */ +public interface AzAction { + + AzActionCodec CODEC = new AzActionCodec(); + + void handle(AzDispatchSide originSide, AzAnimator animator); + + ResourceLocation getResourceLocation(); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzActionCodec.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzActionCodec.java new file mode 100644 index 000000000..4e9be1500 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/codec/AzActionCodec.java @@ -0,0 +1,62 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.codec; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.registry.AzActionRegistry; + +/** + * The AzActionCodec class serves as an implementation of the {@link StreamCodec} interface specifically designed for + * encoding and decoding {@link AzAction} objects. This codec encodes and decodes AzAction instances using their + * associated resource locations and registered codecs within the {@link AzActionRegistry}.
    + * This class provides the necessary functionality to serialize an AzAction to a {@link FriendlyByteBuf} and deserialize + * it back, ensuring proper handling of resource location and associated data. It relies on the AzActionRegistry to + * dynamically retrieve the appropriate codec and handle the serialization or deserialization process.
    + * Use this implementation in scenarios where AzAction objects need to be serialized or deserialized for efficient data + * transmission or storage. + */ +public class AzActionCodec implements StreamCodec { + + @Override + public @NotNull AzAction decode(@NotNull FriendlyByteBuf byteBuf) { + var id = byteBuf.readShort(); + var codec = AzActionRegistry + .>getCodecOrNull(id); + + if (codec == null) { + throw new NullPointerException( + "Could not find action codec for a given action id while decoding data. ID: " + id + ); + } + + return codec.decode(byteBuf); + } + + @Override + public void encode(@NotNull FriendlyByteBuf byteBuf, @NotNull AzAction action) { + var resourceLocation = action.getResourceLocation(); + var id = AzActionRegistry.getIdOrNull(resourceLocation); + var codec = AzActionRegistry + .>getCodecOrNull(resourceLocation); + + if (id == null) { + throw new NullPointerException( + "Could not find action id for a given resource location while encoding data. Resource Location: " + + resourceLocation + ); + } + + byteBuf.writeShort(id); + + if (codec == null) { + throw new NullPointerException( + "Could not find action codec for a given resource location while encoding data. Resource Location: " + + resourceLocation + ", ID: " + id + ); + } + + codec.encode(byteBuf, action); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAction.java new file mode 100644 index 000000000..afd870287 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAction.java @@ -0,0 +1,74 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzAction; + +/** + * Represents an action that cancels the current animation of a specified animation controller in the animation system. + * This action is part of the root-level dispatch actions and interacts with a specific animation controller by name. + *
    + *
    + * An instance of this record is serialized and deserialized using the {@code CODEC}, and it is associated with a unique + * resource location defined by {@code RESOURCE_LOCATION}.
    + *
    + * When executed, the {@code handle} method ensures that the animation of the targeted controller is stopped by setting + * its current animation to {@code null}.
    + *
    + * This class is primarily used within the {@code AzAnimator} context where each animation controller is part of the + * animator's controller container.
    + *
    + * Implements: - {@link AzAction}: Allows the action to be dispatched within the animation system.
    + *
    + * Fields: + *
      + *
    • {@code controllerName}: The name of the animation controller which this action targets.
    • + *
    + *
    + *
    + * Constants: + *
      + *
    • {@code CODEC}: A codec for encoding and decoding this action during network communication.
    • + *
    • {@code RESOURCE_LOCATION}: A unique identifier for this action.
    • + *
    + *
    + *
    + * Methods: + *
      + *
    • {@code handle(AzAnimator animator)}: Stops the current animation of the specified controller within the + * animator's animation controller container.
    • + *
    • {@code getResourceLocation()}: Returns the unique resource location associated with this action.
    • + *
    + */ +public record AzRootCancelAction( + String controllerName +) implements AzAction { + + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, + AzRootCancelAction::controllerName, + AzRootCancelAction::new + ); + + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/cancel"); + + @Override + public void handle(AzDispatchSide originSide, AzAnimator animator) { + var controller = animator.getAnimationControllerContainer().getOrNull(controllerName); + + if (controller != null) { + controller.setCurrentAnimation(null); + } + } + + @Override + public ResourceLocation getResourceLocation() { + return RESOURCE_LOCATION; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAllAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAllAction.java new file mode 100644 index 000000000..2f1814664 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootCancelAllAction.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzAction; + +/** + * The AzRootCancelAllAction class implements the AzAction interface and defines an action that cancels all ongoing + * animations within an animator by setting the current animation of all controllers to null.
    + * This class is designed to work within a system that manages animations for objects using animation controllers. Once + * this action is handled, all animation controllers associated with a specific animator will have their current + * animations cleared. + */ +public class AzRootCancelAllAction implements AzAction { + + public static final StreamCodec CODEC = StreamCodec.unit( + new AzRootCancelAllAction() + ); + + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/cancel_all"); + + @Override + public void handle(AzDispatchSide originSide, AzAnimator animator) { + var controllerContainer = animator.getAnimationControllerContainer(); + var controllers = controllerContainer.getAll(); + + controllers.forEach(controller -> controller.setCurrentAnimation(null)); + } + + @Override + public ResourceLocation getResourceLocation() { + return RESOURCE_LOCATION; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootPlayAnimationSequenceAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootPlayAnimationSequenceAction.java new file mode 100644 index 000000000..2e3be04ee --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootPlayAnimationSequenceAction.java @@ -0,0 +1,42 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzAction; +import mod.azure.azurelib.core2.animation.dispatch.command.sequence.AzAnimationSequence; + +public record AzRootPlayAnimationSequenceAction( + String controllerName, + AzAnimationSequence sequence +) implements AzAction { + + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, + AzRootPlayAnimationSequenceAction::controllerName, + AzAnimationSequence.CODEC, + AzRootPlayAnimationSequenceAction::sequence, + AzRootPlayAnimationSequenceAction::new + ); + + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/play_animation_sequence"); + + @Override + public void handle(AzDispatchSide originSide, AzAnimator animator) { + var controller = animator.getAnimationControllerContainer().getOrNull(controllerName); + + if (controller != null) { + controller.run(originSide, sequence); + } + } + + @Override + public ResourceLocation getResourceLocation() { + return RESOURCE_LOCATION; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetAnimationSpeedAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetAnimationSpeedAction.java new file mode 100644 index 000000000..c8968aa97 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetAnimationSpeedAction.java @@ -0,0 +1,40 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzAction; + +public record AzRootSetAnimationSpeedAction( + double animationSpeed +) implements AzAction { + + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.DOUBLE, + AzRootSetAnimationSpeedAction::animationSpeed, + AzRootSetAnimationSpeedAction::new + ); + + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/set_animation_speed"); + + @Override + public void handle(AzDispatchSide originSide, AzAnimator animator) { + animator.getAnimationControllerContainer() + .getAll() + .forEach( + controller -> controller.setAnimationProperties( + controller.animationProperties().withAnimationSpeed(animationSpeed) + ) + ); + } + + @Override + public ResourceLocation getResourceLocation() { + return RESOURCE_LOCATION; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetEasingTypeAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetEasingTypeAction.java new file mode 100644 index 000000000..ea93135e1 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetEasingTypeAction.java @@ -0,0 +1,40 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzAction; +import mod.azure.azurelib.core2.animation.easing.AzEasingType; + +public record AzRootSetEasingTypeAction( + AzEasingType easingType +) implements AzAction { + + public static final StreamCodec CODEC = StreamCodec.composite( + AzEasingType.STREAM_CODEC, + AzRootSetEasingTypeAction::easingType, + AzRootSetEasingTypeAction::new + ); + + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/set_easing_type"); + + @Override + public void handle(AzDispatchSide originSide, AzAnimator animator) { + animator.getAnimationControllerContainer() + .getAll() + .forEach( + controller -> controller.setAnimationProperties( + controller.animationProperties().withEasingType(easingType) + ) + ); + } + + @Override + public ResourceLocation getResourceLocation() { + return RESOURCE_LOCATION; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetTransitionSpeedAction.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetTransitionSpeedAction.java new file mode 100644 index 000000000..8b0c7bdb7 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/impl/root/AzRootSetTransitionSpeedAction.java @@ -0,0 +1,47 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.dispatch.AzDispatchSide; +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzAction; + +/** + * The {@code AzRootSetTransitionSpeedAction} class implements the {@link AzAction} interface and represents an action + * that modifies the transition speed for an animator during an animation state. This action is intended for use within + * the animation system to adjust the transition timing of animations. This class provides a unique resource location + * identifier for this specific action and handles the logic required to apply the transition speed modification to the + * target {@link AzAnimator}. It utilizes {@link StreamCodec} for serialization and deserialization of this action. + */ +public record AzRootSetTransitionSpeedAction( + float transitionSpeed +) implements AzAction { + + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.FLOAT, + AzRootSetTransitionSpeedAction::transitionSpeed, + AzRootSetTransitionSpeedAction::new + ); + + public static final ResourceLocation RESOURCE_LOCATION = AzureLib.modResource("root/set_transition_speed"); + + @Override + public void handle(AzDispatchSide originSide, AzAnimator animator) { + animator.getAnimationControllerContainer() + .getAll() + .forEach( + controller -> controller.setAnimationProperties( + controller.animationProperties().withTransitionLength(transitionSpeed) + ) + ); + } + + @Override + public ResourceLocation getResourceLocation() { + return RESOURCE_LOCATION; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/registry/AzActionRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/registry/AzActionRegistry.java new file mode 100644 index 000000000..48b964c36 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/action/registry/AzActionRegistry.java @@ -0,0 +1,83 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.action.registry; + +import it.unimi.dsi.fastutil.objects.Object2ShortArrayMap; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +import mod.azure.azurelib.core2.animation.dispatch.command.action.AzAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootCancelAllAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootPlayAnimationSequenceAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootSetAnimationSpeedAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootSetEasingTypeAction; +import mod.azure.azurelib.core2.animation.dispatch.command.action.impl.root.AzRootSetTransitionSpeedAction; + +/** + * The AzActionRegistry class serves as a centralized registry for mapping {@link AzAction} implementations to their + * associated {@link ResourceLocation} identifiers and codecs. This registry enables efficient encoding, decoding, and + * dispatching of animation-related actions within the animation system.
    + * Key Responsibilities: + *
      + *
    • Maintain a bidirectional mapping between {@link ResourceLocation} identifiers and short integer IDs for efficient + * serialization/deserialization.
    • + *
    • Register {@link AzAction} implementations and their corresponding {@link StreamCodec} instances.
    • + *
    • Provide methods for retrieving codecs and IDs based on resource locations or integer IDs. + *
    + */ +public class AzActionRegistry { + + private static final Map RESOURCE_LOCATION_TO_ID = new Object2ShortArrayMap<>(); + + private static final Map> CODEC_BY_ID = + new HashMap<>(); + + private static short NEXT_FREE_ID = 0; + + static { + // Root actions + register(AzRootCancelAction.RESOURCE_LOCATION, AzRootCancelAction.CODEC); + register(AzRootCancelAllAction.RESOURCE_LOCATION, AzRootCancelAllAction.CODEC); + register(AzRootPlayAnimationSequenceAction.RESOURCE_LOCATION, AzRootPlayAnimationSequenceAction.CODEC); + register(AzRootSetAnimationSpeedAction.RESOURCE_LOCATION, AzRootSetAnimationSpeedAction.CODEC); + register(AzRootSetEasingTypeAction.RESOURCE_LOCATION, AzRootSetEasingTypeAction.CODEC); + register(AzRootSetTransitionSpeedAction.RESOURCE_LOCATION, AzRootSetTransitionSpeedAction.CODEC); + + // Controller actions + // TODO: + + // Animation actions + // TODO: + } + + public static @Nullable > T getCodecOrNull( + ResourceLocation resourceLocation + ) { + var id = RESOURCE_LOCATION_TO_ID.get(resourceLocation); + @SuppressWarnings("unchecked") + var codec = (T) CODEC_BY_ID.get(id); + return codec; + } + + public static @Nullable > T getCodecOrNull(short id) { + @SuppressWarnings("unchecked") + var codec = (T) CODEC_BY_ID.get(id); + return codec; + } + + public static @Nullable Short getIdOrNull(ResourceLocation resourceLocation) { + return RESOURCE_LOCATION_TO_ID.get(resourceLocation); + } + + private static
    void register( + ResourceLocation resourceLocation, + StreamCodec codec + ) { + var id = RESOURCE_LOCATION_TO_ID.computeIfAbsent(resourceLocation, ($) -> NEXT_FREE_ID++); + CODEC_BY_ID.put(id, codec); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/sequence/AzAnimationSequence.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/sequence/AzAnimationSequence.java new file mode 100644 index 000000000..cdff931f5 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/sequence/AzAnimationSequence.java @@ -0,0 +1,20 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.sequence; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; + +import java.util.List; + +import mod.azure.azurelib.core2.animation.dispatch.command.stage.AzAnimationStage; +import mod.azure.azurelib.core2.util.codec.AzListStreamCodec; + +public record AzAnimationSequence( + List stages +) { + + public static final StreamCodec CODEC = StreamCodec.composite( + new AzListStreamCodec<>(AzAnimationStage.CODEC), + AzAnimationSequence::stages, + AzAnimationSequence::new + ); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/sequence/AzAnimationSequenceBuilder.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/sequence/AzAnimationSequenceBuilder.java new file mode 100644 index 000000000..be862d7bb --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/sequence/AzAnimationSequenceBuilder.java @@ -0,0 +1,35 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.sequence; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.UnaryOperator; + +import mod.azure.azurelib.core2.animation.dispatch.command.stage.AzAnimationStage; +import mod.azure.azurelib.core2.animation.property.AzAnimationStageProperties; + +public class AzAnimationSequenceBuilder { + + private final List stages; + + public AzAnimationSequenceBuilder() { + this.stages = new ArrayList<>(); + } + + public AzAnimationSequenceBuilder queue(String animationName) { + stages.add(new AzAnimationStage(animationName, AzAnimationStageProperties.EMPTY)); + return this; + } + + public AzAnimationSequenceBuilder queue( + String animationName, + UnaryOperator builderUnaryOperator + ) { + var properties = builderUnaryOperator.apply(AzAnimationStageProperties.EMPTY); + stages.add(new AzAnimationStage(animationName, properties)); + return this; + } + + public AzAnimationSequence build() { + return new AzAnimationSequence(stages); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/stage/AzAnimationStage.java b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/stage/AzAnimationStage.java new file mode 100644 index 000000000..cbf0814b9 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/dispatch/command/stage/AzAnimationStage.java @@ -0,0 +1,22 @@ +package mod.azure.azurelib.core2.animation.dispatch.command.stage; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; + +import mod.azure.azurelib.core2.animation.property.AzAnimationStageProperties; + +public record AzAnimationStage( + String name, + AzAnimationStageProperties properties +) { + + public static final StreamCodec CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, + AzAnimationStage::name, + AzAnimationStageProperties.CODEC, + AzAnimationStage::properties, + AzAnimationStage::new + ); + +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingType.java b/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingType.java new file mode 100644 index 000000000..fb1262321 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingType.java @@ -0,0 +1,42 @@ +package mod.azure.azurelib.core2.animation.easing; + +import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; + +import java.util.Objects; + +import mod.azure.azurelib.core.utils.Interpolations; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzAnimationPoint; + +public interface AzEasingType { + + String name(); + + Double2DoubleFunction buildTransformer(Double value); + + StreamCodec STREAM_CODEC = StreamCodec.of( + (buf, val) -> buf.writeUtf(val.name()), + buf -> Objects.requireNonNull(AzEasingTypeRegistry.getOrNull(buf.readUtf())) + ); + + default double apply(AzAnimationPoint animationPoint) { + Double easingVariable = null; + + if (animationPoint.keyframe() != null && animationPoint.keyframe().easingArgs().size() > 0) + easingVariable = animationPoint.keyframe().easingArgs().get(0).get(); + + return apply(animationPoint, easingVariable, animationPoint.currentTick() / animationPoint.transitionLength()); + } + + default double apply(AzAnimationPoint animationPoint, Double easingValue, double lerpValue) { + if (animationPoint.currentTick() >= animationPoint.transitionLength()) + return (float) animationPoint.animationEndValue(); + + return Interpolations.lerp( + animationPoint.animationStartValue(), + animationPoint.animationEndValue(), + buildTransformer(easingValue).apply(lerpValue) + ); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingTypeLoader.java b/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingTypeLoader.java new file mode 100644 index 000000000..462f4bf27 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingTypeLoader.java @@ -0,0 +1,33 @@ +package mod.azure.azurelib.core2.animation.easing; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; + +import java.util.Locale; + +public class AzEasingTypeLoader { + + /** + * Retrieve an {@code EasingType} instance based on a {@link JsonElement}. Returns one of the default + * {@code EasingTypes} if the name matches, or any other registered {@code EasingType} with a matching name. + * + * @param json The {@code easing} {@link JsonElement} to attempt to parse. + * @return A usable {@code EasingType} instance + */ + public static AzEasingType fromJson(JsonElement json) { + if (!(json instanceof JsonPrimitive primitive) || !primitive.isString()) + return AzEasingTypes.LINEAR; + + return fromString(primitive.getAsString().toLowerCase(Locale.ROOT)); + } + + /** + * Get an existing {@code EasingType} from a given string, matching the string to its name. + * + * @param name The name of the easing function + * @return The relevant {@code EasingType}, or {@link AzEasingTypes#LINEAR} if none match + */ + public static AzEasingType fromString(String name) { + return AzEasingTypeRegistry.getOrDefault(name, AzEasingTypes.LINEAR); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingTypeRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingTypeRegistry.java new file mode 100644 index 000000000..2e2f46df8 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingTypeRegistry.java @@ -0,0 +1,56 @@ +package mod.azure.azurelib.core2.animation.easing; + +import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +public class AzEasingTypeRegistry { + + private static final Map EASING_TYPES = new HashMap<>(); + + /** + * Register an {@code EasingType} with AzureLib for handling animation transitions and value curves.
    + * MUST be called during mod construct
    + * It is recommended you don't call this directly, and instead call it via {@code AzureLibUtil#addCustomEasingType} + * + * @param name The name of the easing type + * @param transformer The {@code Double2DoubleFunction} to associate with the given name + * @return The {@code EasingType} you registered + */ + public static AzEasingType register(String name, Function transformer) { + return EASING_TYPES.computeIfAbsent(name, ($) -> new AzEasingType() { + + @Override + public String name() { + return name; + } + + @Override + public Double2DoubleFunction buildTransformer(Double value) { + return transformer.apply(value); + } + }); + } + + public static AzEasingType register(String name, AzEasingType easingType) { + return register(name, easingType::buildTransformer); + } + + public static AzEasingType getOrDefault(String name, @NotNull AzEasingType defaultValue) { + return EASING_TYPES.getOrDefault(name, defaultValue); + } + + public static @Nullable AzEasingType getOrNull(String name) { + return EASING_TYPES.get(name); + } + + public static Collection getValues() { + return Collections.unmodifiableCollection(EASING_TYPES.values()); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingTypes.java b/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingTypes.java new file mode 100644 index 000000000..b9c1d749e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingTypes.java @@ -0,0 +1,180 @@ +package mod.azure.azurelib.core2.animation.easing; + +public class AzEasingTypes { + + public static final AzEasingType NONE = AzEasingTypeRegistry.register( + "none", + value -> AzEasingUtil.easeIn(AzEasingUtil::linear) + ); + + public static final AzEasingType LINEAR = AzEasingTypeRegistry.register("linear", NONE); + + public static final AzEasingType STEP = AzEasingTypeRegistry.register( + "step", + value -> AzEasingUtil.easeIn(AzEasingUtil.step(value)) + ); + + public static final AzEasingType EASE_IN_SINE = AzEasingTypeRegistry.register( + "easeinsine", + value -> AzEasingUtil.easeIn(AzEasingUtil::sine) + ); + + public static final AzEasingType EASE_OUT_SINE = AzEasingTypeRegistry.register( + "easeoutsine", + value -> AzEasingUtil.easeOut(AzEasingUtil::sine) + ); + + public static final AzEasingType EASE_IN_OUT_SINE = AzEasingTypeRegistry.register( + "easeinoutsine", + value -> AzEasingUtil.easeInOut(AzEasingUtil::sine) + ); + + public static final AzEasingType EASE_IN_QUAD = AzEasingTypeRegistry.register( + "easeinquad", + value -> AzEasingUtil.easeIn(AzEasingUtil::quadratic) + ); + + public static final AzEasingType EASE_OUT_QUAD = AzEasingTypeRegistry.register( + "easeoutquad", + value -> AzEasingUtil.easeOut(AzEasingUtil::quadratic) + ); + + public static final AzEasingType EASE_IN_OUT_QUAD = AzEasingTypeRegistry.register( + "easeinoutquad", + value -> AzEasingUtil.easeInOut(AzEasingUtil::quadratic) + ); + + public static final AzEasingType EASE_IN_CUBIC = AzEasingTypeRegistry.register( + "easeincubic", + value -> AzEasingUtil.easeIn(AzEasingUtil::cubic) + ); + + public static final AzEasingType EASE_OUT_CUBIC = AzEasingTypeRegistry.register( + "easeoutcubic", + value -> AzEasingUtil.easeOut(AzEasingUtil::cubic) + ); + + public static final AzEasingType EASE_IN_OUT_CUBIC = AzEasingTypeRegistry.register( + "easeinoutcubic", + value -> AzEasingUtil.easeInOut(AzEasingUtil::cubic) + ); + + public static final AzEasingType EASE_IN_QUART = AzEasingTypeRegistry.register( + "easeinquart", + value -> AzEasingUtil.easeIn(AzEasingUtil.pow(4)) + ); + + public static final AzEasingType EASE_OUT_QUART = AzEasingTypeRegistry.register( + "easeoutquart", + value -> AzEasingUtil.easeOut(AzEasingUtil.pow(4)) + ); + + public static final AzEasingType EASE_IN_OUT_QUART = AzEasingTypeRegistry.register( + "easeinoutquart", + value -> AzEasingUtil.easeInOut(AzEasingUtil.pow(4)) + ); + + public static final AzEasingType EASE_IN_QUINT = AzEasingTypeRegistry.register( + "easeinquint", + value -> AzEasingUtil.easeIn(AzEasingUtil.pow(4)) + ); + + public static final AzEasingType EASE_OUT_QUINT = AzEasingTypeRegistry.register( + "easeoutquint", + value -> AzEasingUtil.easeOut(AzEasingUtil.pow(5)) + ); + + public static final AzEasingType EASE_IN_OUT_QUINT = AzEasingTypeRegistry.register( + "easeinoutquint", + value -> AzEasingUtil.easeInOut(AzEasingUtil.pow(5)) + ); + + public static final AzEasingType EASE_IN_EXPO = AzEasingTypeRegistry.register( + "easeinexpo", + value -> AzEasingUtil.easeIn(AzEasingUtil::exp) + ); + + public static final AzEasingType EASE_OUT_EXPO = AzEasingTypeRegistry.register( + "easeoutexpo", + value -> AzEasingUtil.easeOut(AzEasingUtil::exp) + ); + + public static final AzEasingType EASE_IN_OUT_EXPO = AzEasingTypeRegistry.register( + "easeinoutexpo", + value -> AzEasingUtil.easeInOut(AzEasingUtil::exp) + ); + + public static final AzEasingType EASE_IN_CIRC = AzEasingTypeRegistry.register( + "easeincirc", + value -> AzEasingUtil.easeIn(AzEasingUtil::circle) + ); + + public static final AzEasingType EASE_OUT_CIRC = AzEasingTypeRegistry.register( + "easeoutcirc", + value -> AzEasingUtil.easeOut(AzEasingUtil::circle) + ); + + public static final AzEasingType EASE_IN_OUT_CIRC = AzEasingTypeRegistry.register( + "easeinoutcirc", + value -> AzEasingUtil.easeInOut(AzEasingUtil::circle) + ); + + public static final AzEasingType EASE_IN_BACK = AzEasingTypeRegistry.register( + "easeinback", + value -> AzEasingUtil.easeIn(AzEasingUtil.back(value)) + ); + + public static final AzEasingType EASE_OUT_BACK = AzEasingTypeRegistry.register( + "easeoutback", + value -> AzEasingUtil.easeOut(AzEasingUtil.back(value)) + ); + + public static final AzEasingType EASE_IN_OUT_BACK = AzEasingTypeRegistry.register( + "easeinoutback", + value -> AzEasingUtil.easeInOut(AzEasingUtil.back(value)) + ); + + public static final AzEasingType EASE_IN_ELASTIC = AzEasingTypeRegistry.register( + "easeinelastic", + value -> AzEasingUtil.easeIn(AzEasingUtil.elastic(value)) + ); + + public static final AzEasingType EASE_OUT_ELASTIC = AzEasingTypeRegistry.register( + "easeoutelastic", + value -> AzEasingUtil.easeOut(AzEasingUtil.elastic(value)) + ); + + public static final AzEasingType EASE_IN_OUT_ELASTIC = AzEasingTypeRegistry.register( + "easeinoutelastic", + value -> AzEasingUtil.easeInOut(AzEasingUtil.elastic(value)) + ); + + public static final AzEasingType EASE_IN_BOUNCE = AzEasingTypeRegistry.register( + "easeinbounce", + value -> AzEasingUtil.easeIn(AzEasingUtil.bounce(value)) + ); + + public static final AzEasingType EASE_OUT_BOUNCE = AzEasingTypeRegistry.register( + "easeoutbounce", + value -> AzEasingUtil.easeOut(AzEasingUtil.bounce(value)) + ); + + public static final AzEasingType EASE_IN_OUT_BOUNCE = AzEasingTypeRegistry.register( + "easeinoutbounce", + value -> AzEasingUtil.easeInOut(AzEasingUtil.bounce(value)) + ); + + public static final AzEasingType CATMULLROM = AzEasingTypeRegistry.register( + "catmullrom", + value -> AzEasingUtil.easeInOut(AzEasingUtil::catmullRom) + ); + + public static AzEasingType random() { + var collection = AzEasingTypeRegistry.getValues(); + + return collection.stream() + .skip((int) (collection.size() * Math.random())) + .findFirst() + .orElse(null); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingUtil.java b/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingUtil.java new file mode 100644 index 000000000..7e2b6ca99 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/easing/AzEasingUtil.java @@ -0,0 +1,250 @@ +package mod.azure.azurelib.core2.animation.easing; + +import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction; + +import mod.azure.azurelib.core2.animation.controller.keyframe.AzAnimationPoint; + +public class AzEasingUtil { + + /** + * Returns an easing function running linearly. Functionally equivalent to no easing + */ + public static Double2DoubleFunction linear(Double2DoubleFunction function) { + return function; + } + + /** + * Performs a Catmull-Rom interpolation, used to get smooth interpolated motion between keyframes.
    + *
    CatmullRom#position + */ + public static double catmullRom(double n) { + return (0.5f * (2.0f * (n + 1) + ((n + 2) - n) * 1 + + (2.0f * n - 5.0f * (n + 1) + 4.0f * (n + 2) - (n + 3)) * 1 + + (3.0f * (n + 1) - n - 3.0f * (n + 2) + (n + 3)) * 1)); + } + + /** + * Returns an easing function running forward in time + */ + public static Double2DoubleFunction easeIn(Double2DoubleFunction function) { + return function; + } + + // ---> Easing Transition Type Functions <--- // + + /** + * Returns an easing function running backwards in time + */ + public static Double2DoubleFunction easeOut(Double2DoubleFunction function) { + return time -> 1 - function.apply(1 - time); + } + + /** + * Returns an easing function that runs equally both forwards and backwards in time based on the halfway point, + * generating a symmetrical curve.
    + */ + public static Double2DoubleFunction easeInOut(Double2DoubleFunction function) { + return time -> { + if (time < 0.5d) + return function.apply(time * 2d) / 2d; + + return 1 - function.apply((1 - time) * 2d) / 2d; + }; + } + + /** + * Returns a stepping function that returns 1 for any input value greater than 0, or otherwise returning 0 + */ + public static Double2DoubleFunction stepPositive(Double2DoubleFunction function) { + return n -> n > 0 ? 1 : 0; + } + + /** + * Returns a stepping function that returns 1 for any input value greater than or equal to 0, or otherwise returning + * 0 + */ + public static Double2DoubleFunction stepNonNegative(Double2DoubleFunction function) { + return n -> n >= 0 ? 1 : 0; + } + + /** + * A linear function, equivalent to a null-operation.
    + * {@code f(n) = n} + */ + public static double linear(double n) { + return n; + } + + // ---> Stepping Functions <--- // + + /** + * A quadratic function, equivalent to the square (n^2) of elapsed time.
    + * {@code f(n) = n^2}
    + * Easings.net#easeInQuad + */ + public static double quadratic(double n) { + return n * n; + } + + /** + * A cubic function, equivalent to cube (n^3) of elapsed time.
    + * {@code f(n) = n^3}
    + * Easings.net#easeInCubic + */ + public static double cubic(double n) { + return n * n * n; + } + + // ---> Mathematical Functions <--- // + + /** + * A sinusoidal function, equivalent to a sine curve output.
    + * {@code f(n) = 1 - cos(n * π / 2)}
    + * Easings.net#easeInSine + */ + public static double sine(double n) { + return 1 - Math.cos(n * Math.PI / 2f); + } + + /** + * A circular function, equivalent to a normally symmetrical curve.
    + * {@code f(n) = 1 - sqrt(1 - n^2)}
    + * Easings.net#easeInCirc + */ + public static double circle(double n) { + return 1 - Math.sqrt(1 - n * n); + } + + /** + * An exponential function, equivalent to an exponential curve.
    + * {@code f(n) = 2^(10 * (n - 1))}
    + * Easings.net#easeInExpo + */ + public static double exp(double n) { + return Math.pow(2, 10 * (n - 1)); + } + + /** + * An elastic function, equivalent to an oscillating curve.
    + * n defines the elasticity of the output.
    + * {@code f(t) = 1 - (cos(t * π) / 2))^3 * cos(t * n * π)}
    + * Easings.net#easeInElastic + */ + public static Double2DoubleFunction elastic(Double n) { + double n2 = n == null ? 1 : n; + + return t -> 1 - Math.pow(Math.cos(t * Math.PI / 2f), 3) * Math.cos(t * n2 * Math.PI); + } + + /** + * A bouncing function, equivalent to a bouncing ball curve.
    + * n defines the bounciness of the output.
    + * Thanks to Waterded#6455 for making the bounce adjustable, and GiantLuigi4#6616 for additional + * cleanup.
    + * Easings.net#easeInBounce + */ + public static Double2DoubleFunction bounce(Double n) { + final double n2 = n == null ? 0.5d : n; + + Double2DoubleFunction one = x -> 121f / 16f * x * x; + Double2DoubleFunction two = x -> 121f / 4f * n2 * Math.pow(x - 6f / 11f, 2) + 1 - n2; + Double2DoubleFunction three = x -> 121 * n2 * n2 * Math.pow(x - 9f / 11f, 2) + 1 - n2 * n2; + Double2DoubleFunction four = x -> 484 * n2 * n2 * n2 * Math.pow(x - 10.5f / 11f, 2) + 1 - n2 * n2 * n2; + + return t -> Math.min(Math.min(one.apply(t), two.apply(t)), Math.min(three.apply(t), four.apply(t))); + } + + /** + * A negative elastic function, equivalent to inverting briefly before increasing.
    + * f(t) = t^2 * ((n * 1.70158 + 1) * t - n * 1.70158)
    + * Easings.net#easeInBack + */ + public static Double2DoubleFunction back(Double n) { + final double n2 = n == null ? 1.70158d : n * 1.70158d; + + return t -> t * t * ((n2 + 1) * t - n2); + } + + // ---> Easing Curve Functions <--- // + + /** + * An exponential function, equivalent to an exponential curve to the {@code n} root.
    + * f(t) = t^n + * + * @param n The exponent + */ + public static Double2DoubleFunction pow(double n) { + return t -> Math.pow(t, n); + } + + /** + * The MIT License (MIT)
    + *
    + * Copyright (c) 2015 Boris Chumichev
    + *
    + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and + * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
    + *
    + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software.
    + *
    + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE.
    + *
    + * Returns a stepped value based on the nearest step to the input value.
    + * The size (grade) of the steps depends on the provided value of {@code n} + **/ + public static Double2DoubleFunction step(Double n) { + double n2 = n == null ? 2 : n; + + if (n2 < 2) + throw new IllegalArgumentException("Steps must be >= 2, got: " + n2); + + final int steps = (int) n2; + + return t -> { + double result = 0; + + if (t < 0) + return result; + + double stepLength = (1 / (double) steps); + + if (t > (result = (steps - 1) * stepLength)) + return result; + + int testIndex; + int leftBorderIndex = 0; + int rightBorderIndex = steps - 1; + + while (rightBorderIndex - leftBorderIndex != 1) { + testIndex = leftBorderIndex + (rightBorderIndex - leftBorderIndex) / 2; + + if (t >= testIndex * stepLength) { + leftBorderIndex = testIndex; + } else { + rightBorderIndex = testIndex; + } + } + + return leftBorderIndex * stepLength; + }; + } + + public static double lerpWithOverride(AzAnimationPoint animationPoint, AzEasingType override) { + var easingType = override; + + if (override == null) { + easingType = animationPoint.keyframe() == null + ? AzEasingTypes.LINEAR + : animationPoint.keyframe().easingType(); + } + + return easingType.apply(animationPoint); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java new file mode 100644 index 000000000..b57b63ca6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzCustomInstructionKeyframeEvent.java @@ -0,0 +1,29 @@ +package mod.azure.azurelib.core2.animation.event; + +import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyframeCallbacks; + +/** + * The {@link AzKeyframeEvent} specific to the {@link AzKeyframeCallbacks#customKeyframeHandler()}.
    + * Called when a custom instruction keyframe is encountered + */ +public class AzCustomInstructionKeyframeEvent extends AzKeyframeEvent { + + public AzCustomInstructionKeyframeEvent( + T entity, + double animationTick, + AzAnimationController controller, + CustomInstructionKeyframeData customInstructionKeyframeData + ) { + super(entity, animationTick, controller, customInstructionKeyframeData); + } + + /** + * Get the {@link CustomInstructionKeyframeData} relevant to this event call + */ + @Override + public CustomInstructionKeyframeData getKeyframeData() { + return super.getKeyframeData(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzKeyframeEvent.java new file mode 100644 index 000000000..9b3b403cf --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzKeyframeEvent.java @@ -0,0 +1,65 @@ +package mod.azure.azurelib.core2.animation.event; + +import mod.azure.azurelib.core.keyframe.Keyframe; +import mod.azure.azurelib.core.keyframe.event.data.KeyFrameData; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; + +/** + * The base class for {@link Keyframe} events.
    + * These will be passed to one of the controllers in {@link AzAnimationController} when encountered during animation. + * + * @see AzCustomInstructionKeyframeEvent + * @see AzParticleKeyframeEvent + * @see AzSoundKeyframeEvent + */ +public abstract class AzKeyframeEvent { + + private final T animatable; + + private final double animationTick; + + private final AzAnimationController controller; + + private final E eventKeyframe; + + protected AzKeyframeEvent( + T animatable, + double animationTick, + AzAnimationController controller, + E eventKeyframe + ) { + this.animatable = animatable; + this.animationTick = animationTick; + this.controller = controller; + this.eventKeyframe = eventKeyframe; + } + + /** + * Gets the amount of ticks that have passed in either the current transition or animation, depending on the + * controller's AnimationState. + */ + public double getAnimationTick() { + return animationTick; + } + + /** + * Gets the {@link T animatable} object being rendered + */ + public T getAnimatable() { + return animatable; + } + + /** + * Gets the {@link AzAnimationController} responsible for the currently playing animation + */ + public AzAnimationController getController() { + return controller; + } + + /** + * Returns the {@link KeyFrameData} relevant to the encountered {@link Keyframe} + */ + public E getKeyframeData() { + return this.eventKeyframe; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java new file mode 100644 index 000000000..8a56fa239 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzParticleKeyframeEvent.java @@ -0,0 +1,34 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation.event; + +import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyframeCallbacks; + +/** + * The {@link AzKeyframeEvent} specific to the {@link AzKeyframeCallbacks#particleKeyframeHandler()}.
    + * Called when a particle instruction keyframe is encountered + */ +public class AzParticleKeyframeEvent extends AzKeyframeEvent { + + public AzParticleKeyframeEvent( + T animatable, + double animationTick, + AzAnimationController controller, + ParticleKeyframeData particleKeyframeData + ) { + super(animatable, animationTick, controller, particleKeyframeData); + } + + /** + * Get the {@link ParticleKeyframeData} relevant to this event call + */ + @Override + public ParticleKeyframeData getKeyframeData() { + return super.getKeyframeData(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java new file mode 100644 index 000000000..4927dc134 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/event/AzSoundKeyframeEvent.java @@ -0,0 +1,34 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation.event; + +import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyframeCallbacks; + +/** + * The {@link AzKeyframeEvent} specific to the {@link AzKeyframeCallbacks#soundKeyframeHandler()}.
    + * Called when a sound instruction keyframe is encountered + */ +public class AzSoundKeyframeEvent extends AzKeyframeEvent { + + /** + * This stores all the fields that are needed in the AnimationTestEvent + * + * @param entity the entity + * @param animationTick The amount of ticks that have passed in either the current transition or animation, + * depending on the controller's AnimationState. + * @param controller the controller + */ + public AzSoundKeyframeEvent( + T entity, + double animationTick, + AzAnimationController controller, + SoundKeyframeData keyframeData + ) { + super(entity, animationTick, controller, keyframeData); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzBlockAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzBlockAnimator.java new file mode 100644 index 000000000..367050433 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzBlockAnimator.java @@ -0,0 +1,20 @@ +package mod.azure.azurelib.core2.animation.impl; + +import net.minecraft.world.level.block.entity.BlockEntity; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; + +/** + * The {@code AzBlockAnimator} class extends the functionality of the {@link AzAnimator} to provide animation support + * specifically for {@link BlockEntity} instances. This abstract class serves as a base for creating block entity + * animators with reusable configuration and animation controller registration mechanisms. + * + * @param The type of {@link BlockEntity} that this animator will manage animations for. + */ +public abstract class AzBlockAnimator extends AzAnimator { + + protected AzBlockAnimator(AzAnimatorConfig config) { + super(config); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java new file mode 100644 index 000000000..556c492bd --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzEntityAnimator.java @@ -0,0 +1,70 @@ +package mod.azure.azurelib.core2.animation.impl; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.MolangQueries; +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; + +/** + * The {@code AzEntityAnimator} class extends {@link AzAnimator} to provide specialized animation management for + * entities. This abstract class is designed to handle various animation-related requirements for entities in a game + * framework, including the application of MoLang queries specific to entity-related properties such as position, + * health, and motion state. + * + * @param The type of entity this animator is designed to manage. + */ +public abstract class AzEntityAnimator extends AzAnimator { + + protected AzEntityAnimator() { + super(); + } + + protected AzEntityAnimator(AzAnimatorConfig config) { + super(config); + } + + /** + * Applies MoLang queries specific to an entity in the animation system. These queries provide contextual + * information about the entity's state and environment, such as its position, health, movement, and interaction + * with the world. The method extends the baseline queries defined in the superclass with additional entity-specific + * properties, particularly for living entities. + * + * @param entity The entity for which the MoLang queries are being applied. + * @param animTime The current animation time, in seconds, used for time-dependent queries. + */ + @Override + protected void applyMolangQueries(T entity, double animTime) { + super.applyMolangQueries(entity, animTime); + + var parser = MolangParser.INSTANCE; + var minecraft = Minecraft.getInstance(); + + parser.setMemoizedValue( + MolangQueries.DISTANCE_FROM_CAMERA, + () -> minecraft.gameRenderer.getMainCamera().getPosition().distanceTo(entity.position()) + ); + parser.setMemoizedValue(MolangQueries.IS_ON_GROUND, () -> RenderUtils.booleanToFloat(entity.onGround())); + parser.setMemoizedValue(MolangQueries.IS_IN_WATER, () -> RenderUtils.booleanToFloat(entity.isInWater())); + parser.setMemoizedValue( + MolangQueries.IS_IN_WATER_OR_RAIN, + () -> RenderUtils.booleanToFloat(entity.isInWaterOrRain()) + ); + parser.setMemoizedValue(MolangQueries.IS_ON_FIRE, () -> RenderUtils.booleanToFloat(entity.isOnFire())); + + if (entity instanceof LivingEntity livingEntity) { + parser.setMemoizedValue(MolangQueries.HEALTH, livingEntity::getHealth); + parser.setMemoizedValue(MolangQueries.MAX_HEALTH, livingEntity::getMaxHealth); + parser.setMemoizedValue(MolangQueries.GROUND_SPEED, () -> { + var velocity = livingEntity.getDeltaMovement(); + return Mth.sqrt((float) ((velocity.x * velocity.x) + (velocity.z * velocity.z))); + }); + parser.setMemoizedValue(MolangQueries.YAW_SPEED, () -> livingEntity.getYRot() - livingEntity.yRotO); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java new file mode 100644 index 000000000..1deac4073 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/impl/AzItemAnimator.java @@ -0,0 +1,26 @@ +package mod.azure.azurelib.core2.animation.impl; + +import net.minecraft.world.item.ItemStack; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; + +/** + * The {@code AzItemAnimator} class is an abstract extension of the {@code AzAnimator} class, specifically designed to + * handle animations for {@link ItemStack} objects. It provides common functionality and structure for animating items + * within the framework.
    + *
    + * This class serves as a base for developing custom item animator implementations. Subclasses are required to implement + * methods for animation controller registration and for specifying the animation location for the corresponding + * {@code ItemStack}. + */ +public abstract class AzItemAnimator extends AzAnimator { + + protected AzItemAnimator() { + super(); + } + + protected AzItemAnimator(AzAnimatorConfig config) { + super(config); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java new file mode 100644 index 000000000..b9609f69c --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzBakedAnimationsAdapter.java @@ -0,0 +1,365 @@ +package mod.azure.azurelib.core2.animation.parse; + +import com.google.gson.*; +import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import org.apache.commons.lang3.math.NumberUtils; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.util.JsonUtil; +import mod.azure.azurelib.core.keyframe.BoneAnimation; +import mod.azure.azurelib.core.keyframe.KeyframeStack; +import mod.azure.azurelib.core.math.Constant; +import mod.azure.azurelib.core.math.IValue; +import mod.azure.azurelib.core.molang.MolangException; +import mod.azure.azurelib.core.molang.MolangParser; +import mod.azure.azurelib.core.molang.expressions.MolangValue; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimation; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyframe; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyframeStack; +import mod.azure.azurelib.core2.animation.easing.AzEasingType; +import mod.azure.azurelib.core2.animation.easing.AzEasingTypeLoader; +import mod.azure.azurelib.core2.animation.easing.AzEasingTypes; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimation; +import mod.azure.azurelib.core2.animation.primitive.AzBakedAnimations; +import mod.azure.azurelib.core2.animation.primitive.AzKeyframes; +import mod.azure.azurelib.core2.animation.primitive.AzLoopType; + +/** + * {@link com.google.gson.Gson} {@link JsonDeserializer} for {@link AzBakedAnimations}.
    + * Acts as the deserialization interface for {@code BakedAnimations} + */ +public class AzBakedAnimationsAdapter implements JsonDeserializer { + + /** + * Processes a given JSON element and transforms it into a list of pairs, where each pair consists of a string key + * and a corresponding JSON element. Depending on the type of the input element, it handles primitive values, + * arrays, and objects differently, ensuring a uniform output structure. For JSON primitives, a synthetic triplet + * array is generated. For JSON arrays, the array is paired with the key "0". For JSON objects, individual entries + * are processed recursively, with special handling for nested objects without a "vector" key. + * + * @param element The JSON element to be processed. It can be a {@link JsonPrimitive}, {@link JsonObject}, or + * {@link JsonArray}. If null, an empty list is returned. + * @return A list of {@link Pair} objects where each pair contains a string key and a corresponding + * {@link JsonElement}. This list represents the processed structure of the input JSON element. + * @throws JsonParseException If the provided JSON element is of an unsupported type or is invalid. + */ + private static List> getTripletObj(JsonElement element) { + if (element == null) + return List.of(); + + if (element instanceof JsonPrimitive primitive) { + JsonArray array = new JsonArray(3); + + array.add(primitive); + array.add(primitive); + array.add(primitive); + + element = array; + } + + if (element instanceof JsonArray array) + return ObjectArrayList.of(Pair.of("0", array)); + + if (element instanceof JsonObject obj) { + List> list = new ObjectArrayList<>(); + + for (Map.Entry entry : obj.entrySet()) { + if (entry.getValue() instanceof JsonObject entryObj && !entryObj.has("vector")) { + list.add(getTripletObjBedrock(entry.getKey(), entryObj)); + + continue; + } + + list.add(Pair.of(entry.getKey(), entry.getValue())); + } + + return list; + } + + throw new JsonParseException("Invalid object type provided to getTripletObj, got: " + element); + } + + /** + * Extracts and processes keyframe data from a given JSON object, returning a pair consisting of a timestamp and + * associated JSON element data. The method focuses on retrieving either the "pre" or "post" keyframe data from the + * input JSON object, applying specific handling for array or object-based representations. + * + * @param timestamp The string representation of the timestamp for the keyframe data. If the input value is not + * valid as a numeric string, it defaults to "0". + * @param keyframe A {@link JsonObject} containing the keyframe data. Expected keys include "pre" or "post" with + * their associated values either as JSON arrays or nested objects containing a "vector" element. + * @return A {@link Pair} where the first element is the processed timestamp as a string, and the second element is + * a {@link JsonArray} representing the keyframe values. + * @throws JsonParseException If the provided keyframe data is invalid or does not meet the expected structure, such + * as missing or incorrectly formatted "pre" or "post" keys. + */ + private static Pair getTripletObjBedrock(String timestamp, JsonObject keyframe) { + JsonArray keyframeValues = null; + + if (keyframe.has("pre")) { + JsonElement pre = keyframe.get("pre"); + keyframeValues = pre.isJsonArray() + ? pre.getAsJsonArray() + : GsonHelper.getAsJsonArray(pre.getAsJsonObject(), "vector"); + } else if (keyframe.has("post")) { + JsonElement post = keyframe.get("post"); + keyframeValues = post.isJsonArray() + ? post.getAsJsonArray() + : GsonHelper.getAsJsonArray(post.getAsJsonObject(), "vector"); + } + + if (keyframeValues != null) + return Pair.of(NumberUtils.isCreatable(timestamp) ? timestamp : "0", keyframeValues); + + throw new JsonParseException("Invalid keyframe data - expected array, found " + keyframe); + } + + /** + * Calculates the overall length of the animation timeline across all provided bone animations. The calculation + * considers the maximum keyframe time for rotation, position, and scale transformations for each bone and + * determines the longest timeline among them. + * + * @param boneAnimations An array of {@link BoneAnimation} instances representing the animations for individual + * bones. Each bone animation includes keyframe stacks for rotation, position, and scale + * transformations. + * @return The maximum length of the animation timeline. If no keyframes are present, it defaults to + * {@link Double#MAX_VALUE}. + */ + private static double calculateAnimationLength(AzBoneAnimation[] boneAnimations) { + double length = 0; + + for (var animation : boneAnimations) { + length = Math.max(length, animation.rotationKeyframes().getLastKeyframeTime()); + length = Math.max(length, animation.positionKeyframes().getLastKeyframeTime()); + length = Math.max(length, animation.scaleKeyframes().getLastKeyframeTime()); + } + + return length == 0 ? Double.MAX_VALUE : length; + } + + /** + * Deserializes JSON data into an instance of {@link AzBakedAnimations}. + * + * @param json The JSON element to deserialize, expected to contain a valid structure for animations and optional + * includes. + * @param type The type of object to deserialize to; this is typically {@link AzBakedAnimations}. + * @param context A context for handling nested deserialization, such as for custom types embedded within the JSON + * structure. + * @return A newly created {@link AzBakedAnimations} instance containing parsed animations and includes as specified + * in the provided JSON data. + * @throws JsonParseException If the JSON structure is invalid or an error occurs during deserialization. + */ + @Override + public AzBakedAnimations deserialize( + JsonElement json, + Type type, + JsonDeserializationContext context + ) throws JsonParseException { + JsonObject jsonObj = json.getAsJsonObject(); + + JsonObject animationJsonList = jsonObj.getAsJsonObject("animations"); + JsonArray includeListJSONObj = jsonObj.getAsJsonArray("includes"); + Map includes = null; + if (includeListJSONObj != null) { + includes = new Object2ObjectOpenHashMap<>(includeListJSONObj.size()); + for (JsonElement entry : includeListJSONObj.asList()) { + JsonObject obj = entry.getAsJsonObject(); + ResourceLocation fileId = ResourceLocation.parse(obj.get("file_id").getAsString()); + for (JsonElement animName : obj.getAsJsonArray("animations")) { + String ani = animName.getAsString(); + if (includes.containsKey(ani)) { + AzureLib.LOGGER.warn( + "Animation {} is already included! File already including: {} File trying to include from again: {}", + ani, + includes.get(ani), + fileId + ); + } else { + includes.put(ani, fileId); + } + } + } + } + + Map animations = new Object2ObjectOpenHashMap<>(animationJsonList.size()); + + for (Map.Entry entry : animationJsonList.entrySet()) { + try { + animations.put( + entry.getKey(), + bakeAnimation(entry.getKey(), entry.getValue().getAsJsonObject(), context) + ); + } catch (MolangException ex) { + AzureLib.LOGGER.error("Unable to parse animation: {}", entry.getKey()); + ex.printStackTrace(); + } + } + + return new AzBakedAnimations(animations, includes); + } + + /** + * Processes the provided JSON data to create an instance of {@link AzBakedAnimation}. This method interprets the + * animation JSON object, constructs the necessary data structures such as bone animations and keyframes, and + * applies logic to calculate the animation length if not explicitly defined. + * + * @param name The name of the animation being created. + * @param animationObj The JSON object containing the animation definition. This object may include details such as + * animation length, loop type, bones, and keyframe data. + * @param context The deserialization context used for nested data structures such as {@link AzKeyframes}. + * @return A constructed {@link AzBakedAnimation} instance containing the parsed animation details. + * @throws MolangException If an error occurs while processing expressions or any other aspect of the Molang + * language during animation creation. + */ + private AzBakedAnimation bakeAnimation( + String name, + JsonObject animationObj, + JsonDeserializationContext context + ) throws MolangException { + double length = animationObj.has("animation_length") + ? GsonHelper.getAsDouble(animationObj, "animation_length") * 20d + : -1; + AzLoopType loopType = AzLoopType.fromJson(animationObj.get("loop")); + AzBoneAnimation[] boneAnimations = bakeBoneAnimations( + GsonHelper.getAsJsonObject(animationObj, "bones", new JsonObject()) + ); + AzKeyframes keyframes = context.deserialize(animationObj, AzKeyframes.class); + + if (length == -1) + length = calculateAnimationLength(boneAnimations); + + return new AzBakedAnimation(name, length, loopType, boneAnimations, keyframes); + } + + /** + * Processes a JSON object representing bone animations and constructs an array of {@link BoneAnimation} instances. + * Each bone's animation includes keyframe stacks for position, rotation, and scale transformations. + * + * @param bonesObj The JSON object containing bone animation data, where each key is the bone name and the value is + * an object with keyframe data for scale, position, and rotation. + * @return An array of {@link BoneAnimation} instances representing the deserialized animations for each bone. + * @throws MolangException If an error occurs during the processing of keyframes or Molang expressions. + */ + private AzBoneAnimation[] bakeBoneAnimations(JsonObject bonesObj) throws MolangException { + AzBoneAnimation[] animations = new AzBoneAnimation[bonesObj.size()]; + int index = 0; + + for (Map.Entry entry : bonesObj.entrySet()) { + JsonObject entryObj = entry.getValue().getAsJsonObject(); + AzKeyframeStack> scaleFrames = buildKeyframeStack( + getTripletObj(entryObj.get("scale")), + false + ); + AzKeyframeStack> positionFrames = buildKeyframeStack( + getTripletObj(entryObj.get("position")), + false + ); + AzKeyframeStack> rotationFrames = buildKeyframeStack( + getTripletObj(entryObj.get("rotation")), + true + ); + + animations[index] = new AzBoneAnimation(entry.getKey(), rotationFrames, positionFrames, scaleFrames); + index++; + } + + return animations; + } + + /** + * Builds a {@link KeyframeStack} containing keyframes for X, Y, and Z-axis transformations based on the provided + * animation data. The method processes a list of paired time-stamped keyframe data, interprets the JSON structures, + * applies appropriate transformations for rotations (if specified), and generates keyframes with defined easing + * behaviors. + * + * @param entries A list of {@link Pair} objects containing the timestamp as a {@link String} and associated + * {@link JsonElement} data describing the keyframe. Each entry represents a point in time + * within the animation timeline. + * @param isForRotation A boolean indicating whether the keyframe transformations should account for rotation. If + * true, the keyframe values undergo additional processing to convert angles to radians. + * @return A {@link KeyframeStack} containing three lists of keyframes for X, Y, and Z transformations, + * respectively. + * @throws MolangException If an error occurs during the parsing or interpretation of Molang expressions in the + * keyframe data. + */ + private AzKeyframeStack> buildKeyframeStack( + List> entries, + boolean isForRotation + ) throws MolangException { + if (entries.isEmpty()) + return new AzKeyframeStack<>(); + + List> xFrames = new ObjectArrayList<>(); + List> yFrames = new ObjectArrayList<>(); + List> zFrames = new ObjectArrayList<>(); + + IValue xPrev = null; + IValue yPrev = null; + IValue zPrev = null; + Pair prevEntry = null; + + for (Pair entry : entries) { + String key = entry.getFirst(); + JsonElement element = entry.getSecond(); + + if (key.equals("easing") || key.equals("easingArgs") || key.equals("lerp_mode")) + continue; + + double prevTime = prevEntry != null ? Double.parseDouble(prevEntry.getFirst()) : 0; + double curTime = NumberUtils.isCreatable(key) ? Double.parseDouble(entry.getFirst()) : 0; + double timeDelta = curTime - prevTime; + + JsonArray keyframeVector = element instanceof JsonArray array + ? array + : GsonHelper.getAsJsonArray(element.getAsJsonObject(), "vector"); + MolangValue rawXValue = MolangParser.parseJson(keyframeVector.get(0)); + MolangValue rawYValue = MolangParser.parseJson(keyframeVector.get(1)); + MolangValue rawZValue = MolangParser.parseJson(keyframeVector.get(2)); + IValue xValue = isForRotation && rawXValue.isConstant() + ? new Constant(Math.toRadians(-rawXValue.get())) + : rawXValue; + IValue yValue = isForRotation && rawYValue.isConstant() + ? new Constant(Math.toRadians(-rawYValue.get())) + : rawYValue; + IValue zValue = isForRotation && rawZValue.isConstant() + ? new Constant(Math.toRadians(rawZValue.get())) + : rawZValue; + + JsonObject entryObj = element instanceof JsonObject obj ? obj : null; + AzEasingType easingType = entryObj != null && entryObj.has("easing") + ? AzEasingTypeLoader.fromJson(entryObj.get("easing")) + : AzEasingTypes.LINEAR; + List easingArgs = entryObj != null && entryObj.has("easingArgs") + ? JsonUtil.jsonArrayToList( + GsonHelper.getAsJsonArray(entryObj, "easingArgs"), + ele -> new Constant(ele.getAsDouble()) + ) + : new ObjectArrayList<>(); + + xFrames.add( + new AzKeyframe<>(timeDelta * 20, prevEntry == null ? xValue : xPrev, xValue, easingType, easingArgs) + ); + yFrames.add( + new AzKeyframe<>(timeDelta * 20, prevEntry == null ? yValue : yPrev, yValue, easingType, easingArgs) + ); + zFrames.add( + new AzKeyframe<>(timeDelta * 20, prevEntry == null ? zValue : zPrev, zValue, easingType, easingArgs) + ); + + xPrev = xValue; + yPrev = yValue; + zPrev = zValue; + prevEntry = entry; + } + + return new AzKeyframeStack<>(xFrames, yFrames, zFrames); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzKeyframesAdapter.java b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzKeyframesAdapter.java new file mode 100644 index 000000000..cbb42aaaa --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/parse/AzKeyframesAdapter.java @@ -0,0 +1,149 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.animation.parse; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.util.GsonHelper; + +import java.lang.reflect.Type; +import java.util.Map; + +import mod.azure.azurelib.common.internal.common.util.JsonUtil; +import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; +import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; +import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; +import mod.azure.azurelib.core2.animation.primitive.AzKeyframes; + +/** + * {@link Gson} {@link JsonDeserializer} for {@link AzKeyframes}.
    + * Acts as the deserialization interface for {@code Keyframes} + */ +public class AzKeyframesAdapter implements JsonDeserializer { + + /** + * Builds an array of {@link SoundKeyframeData} objects from a given JSON object. This method parses a JSON object + * containing sound effect data, extracting key-value pairs to create instances of {@link SoundKeyframeData}. The + * keys represent the time in seconds, which are converted into ticks, and the values specify the sound effect. + * + * @param rootObj the root JSON object containing the "sound_effects" data + * @return an array of {@link SoundKeyframeData} objects extracted from the JSON object + */ + private static SoundKeyframeData[] buildSoundFrameData(JsonObject rootObj) { + JsonObject soundsObj = GsonHelper.getAsJsonObject(rootObj, "sound_effects", new JsonObject()); + SoundKeyframeData[] sounds = new SoundKeyframeData[soundsObj.size()]; + int index = 0; + + for (Map.Entry entry : soundsObj.entrySet()) { + sounds[index] = new SoundKeyframeData( + Double.parseDouble(entry.getKey()) * 20d, + GsonHelper.getAsString(entry.getValue().getAsJsonObject(), "effect") + ); + index++; + } + + return sounds; + } + + /** + * Builds an array of {@link ParticleKeyframeData} objects from a given JSON object. This method parses a JSON + * object containing particle effect data, extracting key-value pairs to create instances of + * {@link ParticleKeyframeData}. The keys are interpreted as time in ticks, whereas the values provide effect + * details like effect type, locator, and script. + * + * @param rootObj the root JSON object containing the "particle_effects" data + * @return an array of {@link ParticleKeyframeData} objects extracted from the JSON object + */ + private static ParticleKeyframeData[] buildParticleFrameData(JsonObject rootObj) { + JsonObject particlesObj = GsonHelper.getAsJsonObject(rootObj, "particle_effects", new JsonObject()); + ParticleKeyframeData[] particles = new ParticleKeyframeData[particlesObj.size()]; + int index = 0; + + for (Map.Entry entry : particlesObj.entrySet()) { + JsonObject obj = entry.getValue().getAsJsonObject(); + String effect = GsonHelper.getAsString(obj, "effect", ""); + String locator = GsonHelper.getAsString(obj, "locator", ""); + String script = GsonHelper.getAsString(obj, "pre_effect_script", ""); + + particles[index] = new ParticleKeyframeData( + Double.parseDouble(entry.getKey()) * 20d, + effect, + locator, + script + ); + index++; + } + + return particles; + } + + /** + * Builds an array of {@link CustomInstructionKeyframeData} objects from a given JSON object. + *

    + * This method parses a JSON object containing custom instructions for keyframes, extracting each key-value pair to + * create instances of {@link CustomInstructionKeyframeData}. The keys are interpreted as time in ticks, and the + * values as instructions. + * + * @param rootObj the root JSON object containing the "timeline" data for custom instructions + * @return an array of {@link CustomInstructionKeyframeData} objects extracted from the JSON object + */ + private static CustomInstructionKeyframeData[] buildCustomFrameData(JsonObject rootObj) { + JsonObject customInstructionsObj = GsonHelper.getAsJsonObject(rootObj, "timeline", new JsonObject()); + CustomInstructionKeyframeData[] customInstructions = new CustomInstructionKeyframeData[customInstructionsObj + .size()]; + int index = 0; + + for (Map.Entry entry : customInstructionsObj.entrySet()) { + String instructions = ""; + + if (entry.getValue() instanceof JsonArray array) { + instructions = JsonUtil.GEO_GSON.fromJson(array, ObjectArrayList.class).toString(); + } else if (entry.getValue() instanceof JsonPrimitive primitive) { + instructions = primitive.getAsString(); + } + + customInstructions[index] = new CustomInstructionKeyframeData( + Double.parseDouble(entry.getKey()) * 20d, + instructions + ); + index++; + } + + return customInstructions; + } + + /** + * Deserializes a JSON element into an {@code AzKeyframes} object. This method converts the JSON representation of + * keyframe data into instances of {@code SoundKeyframeData}, {@code ParticleKeyframeData}, and + * {@code CustomInstructionKeyframeData} to construct an {@code AzKeyframes} object. + * + * @param json the JSON element containing the keyframe data + * @param type the type parameter for deserialization (not used in this method) + * @param context the deserialization context provided by Gson + * @return an instance of {@code AzKeyframes} containing deserialized keyframe data + * @throws JsonParseException if the JSON is invalid or cannot be properly parsed + */ + @Override + public AzKeyframes deserialize( + JsonElement json, + Type type, + JsonDeserializationContext context + ) throws JsonParseException { + JsonObject obj = json.getAsJsonObject(); + SoundKeyframeData[] sounds = buildSoundFrameData(obj); + ParticleKeyframeData[] particles = buildParticleFrameData(obj); + CustomInstructionKeyframeData[] customInstructions = buildCustomFrameData(obj); + + return new AzKeyframes(sounds, particles, customInstructions); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/play_behavior/AzPlayBehavior.java b/common/src/main/java/mod/azure/azurelib/core2/animation/play_behavior/AzPlayBehavior.java new file mode 100644 index 000000000..ccb208141 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/play_behavior/AzPlayBehavior.java @@ -0,0 +1,20 @@ +package mod.azure.azurelib.core2.animation.play_behavior; + +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; + +public abstract class AzPlayBehavior { + + private final String name; + + protected AzPlayBehavior(String name) { + this.name = name; + } + + public void onUpdate(AzAnimationControllerStateMachine.Context context) {} + + public void onFinish(AzAnimationControllerStateMachine.Context context) {} + + public String name() { + return name; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/play_behavior/AzPlayBehaviorRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/animation/play_behavior/AzPlayBehaviorRegistry.java new file mode 100644 index 000000000..19a6a895e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/play_behavior/AzPlayBehaviorRegistry.java @@ -0,0 +1,31 @@ +package mod.azure.azurelib.core2.animation.play_behavior; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class AzPlayBehaviorRegistry { + + private static final Map PLAY_BEHAVIORS = new HashMap<>(); + + public static AzPlayBehavior register(AzPlayBehavior playBehavior) { + PLAY_BEHAVIORS.put(playBehavior.name(), playBehavior); + return playBehavior; + } + + public static AzPlayBehavior getOrDefault(String name, @NotNull AzPlayBehavior defaultValue) { + return PLAY_BEHAVIORS.getOrDefault(name, defaultValue); + } + + public static @Nullable AzPlayBehavior getOrNull(String name) { + return PLAY_BEHAVIORS.get(name); + } + + public static Collection getValues() { + return Collections.unmodifiableCollection(PLAY_BEHAVIORS.values()); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/play_behavior/AzPlayBehaviors.java b/common/src/main/java/mod/azure/azurelib/core2/animation/play_behavior/AzPlayBehaviors.java new file mode 100644 index 000000000..0bb7dc59f --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/play_behavior/AzPlayBehaviors.java @@ -0,0 +1,33 @@ +package mod.azure.azurelib.core2.animation.play_behavior; + +import mod.azure.azurelib.core2.animation.controller.state.machine.AzAnimationControllerStateMachine; + +public class AzPlayBehaviors { + + public static final AzPlayBehavior HOLD_ON_LAST_FRAME = AzPlayBehaviorRegistry.register(new AzPlayBehavior("hold_on_last_frame") { + @Override + public void onFinish(AzAnimationControllerStateMachine.Context context) { + context.stateMachine().pause(); + } + }); + + public static final AzPlayBehavior LOOP = AzPlayBehaviorRegistry.register(new AzPlayBehavior("loop") { + @Override + public void onFinish(AzAnimationControllerStateMachine.Context context) { + var controller = context.animationController(); + var controllerTimer = controller.controllerTimer(); + var keyframeManager = controller.keyframeManager(); + var keyframeCallbackHandler = keyframeManager.keyframeCallbackHandler(); + + controllerTimer.reset(); + keyframeCallbackHandler.reset(); + } + }); + + public static final AzPlayBehavior PLAY_ONCE = AzPlayBehaviorRegistry.register(new AzPlayBehavior("play_once") { + @Override + public void onFinish(AzAnimationControllerStateMachine.Context context) { + context.stateMachine().stop(); + } + }); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimation.java new file mode 100644 index 000000000..725dfa741 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimation.java @@ -0,0 +1,19 @@ +package mod.azure.azurelib.core2.animation.primitive; + +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzBoneAnimation; + +/** + * A compiled animation instance for use by the {@link AzAnimationController}
    + * Modifications or extensions of a compiled Animation are not supported, and therefore an instance of + * Animation is considered final and immutable. + */ +public record AzBakedAnimation( + String name, + double length, + AzLoopType loopType, + AzBoneAnimation[] boneAnimations, + AzKeyframes keyframes +) { + +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimations.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimations.java new file mode 100644 index 000000000..a8d6c0239 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzBakedAnimations.java @@ -0,0 +1,30 @@ +package mod.azure.azurelib.core2.animation.primitive; + +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +/** + * Represents a container for baked animations in the AzureLib framework. This record holds mappings for precompiled + * animation instances ({@link AzBakedAnimation}) and resource includes ({@link ResourceLocation}) for use in + * animation-driven content.
    + * The `AzBakedAnimations` structure provides functionality for retrieving animations by name and supporting external + * resource references via the includes mapping, enabling extensibility and reuse of animations across various contexts. + *
    + * Immutable and designed for efficient storage and retrieval of animation data. + */ +public record AzBakedAnimations( + Map animations, + Map includes +) { + + /** + * Gets an {@link AzBakedAnimation} by its name, if present + */ + @Nullable + public AzBakedAnimation getAnimation(String name) { + return animations.get(name); + } + +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzKeyframes.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzKeyframes.java new file mode 100644 index 000000000..2db216051 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzKeyframes.java @@ -0,0 +1,23 @@ +package mod.azure.azurelib.core2.animation.primitive; + +import mod.azure.azurelib.core.keyframe.event.data.CustomInstructionKeyframeData; +import mod.azure.azurelib.core.keyframe.event.data.ParticleKeyframeData; +import mod.azure.azurelib.core.keyframe.event.data.SoundKeyframeData; + +/** + * Represents a collection of keyframe data used for animations.
    + * The AzKeyframes record combines different types of keyframe data into a single structure: + *

      + *
    • {@link SoundKeyframeData} for sound-related keyframes.
    • + *
    • {@link ParticleKeyframeData} for particle effect-related keyframes.
    • + *
    • {@link CustomInstructionKeyframeData} for custom instruction keyframes.
    • + *
    + *
    + * This record organizes and provides access to all three types of keyframe data, enabling cohesive handling of + * animation sequences defined in an animation system. + */ +public record AzKeyframes( + SoundKeyframeData[] sounds, + ParticleKeyframeData[] particles, + CustomInstructionKeyframeData[] customInstructions +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java new file mode 100644 index 000000000..9ed5d2ec3 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzLoopType.java @@ -0,0 +1,152 @@ +package mod.azure.azurelib.core2.animation.primitive; + +import com.google.gson.JsonElement; +import org.apache.commons.lang3.function.TriFunction; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; + +/** + * Loop type functional interface to define post-play handling for a given animation.
    + * Custom loop types are supported by extending this class and providing the extended class instance as the loop type + * for the animation + * + * @deprecated + */ +@Deprecated(forRemoval = true) +public interface AzLoopType { + + String name(); + + /** + * Override in a custom instance to dynamically decide whether an animation should repeat or stop + * + * @param animatable The animating object relevant to this method call + * @param controller The {@link AzAnimationController} playing the current animation + * @param currentAnimation The current animation that just played + * @return Whether the animation should play again, or stop + */ + boolean shouldPlayAgain( + Object animatable, + AzAnimationController controller, + AzBakedAnimation currentAnimation + ); + + Map LOOP_TYPES = new ConcurrentHashMap<>(5); + + AzLoopType FALSE = register("false", (animatable, controller, currentAnimation) -> false); + + AzLoopType TRUE = register("true", (animatable, controller, currentAnimation) -> true); + + /** + * A predefined {@code AzLoopType} that indicates an animation should play only once without repeating. This loop + * type is used to configure animations that are intended to run a single time and stop when completed, instead of + * looping or holding on the last frame. The associated logic for this type always returns {@code false} for the + * repeat condition, preventing the animation from replaying once it has finished. + */ + AzLoopType PLAY_ONCE = register("play_once", FALSE); + + /** + * A pre-defined AzLoopType representing the behavior of holding on the last frame of an animation after it + * completes. + *

    + * When used as the loop type for an animation, the animation will pause on its final frame. The `pause()` method of + * the controller's state machine ensures this behavior. This is useful when the desired outcome is for the + * animation to display its last frame persistently without replaying or resetting. + *

    + * Implementation Details: - Utilizes the `controller.getStateMachine().pause()` method to halt the animation. - + * Returns `true`, indicating the controller should not proceed to the next state or reset/replay the animation. + */ + AzLoopType HOLD_ON_LAST_FRAME = register("hold_on_last_frame", (animatable, controller, currentAnimation) -> { + controller.stateMachine().pause(); + + return true; + }); + + /** + * Represents a preconfigured {@code AzLoopType} that determines the looping behavior of an animation. The + * {@code LOOP} type is designed to always repeat the animation, ensuring that the looping condition remains + * consistently true. This constant is registered with AzureLib's loop handler using the static {@code register} + * method. When used, it applies a behavior where the animation will indefinitely loop, regardless of any dynamic + * runtime evaluations about the animatable object or animation state. + */ + AzLoopType LOOP = register("loop", TRUE); + + /** + * Retrieve a AzLoopType instance based on a {@link JsonElement}. Returns either {@link AzLoopType#PLAY_ONCE} or + * {@link AzLoopType#LOOP} based on a boolean or string element type, or any other registered loop type with a + * matching type string. + * + * @param json The loop {@link JsonElement} to attempt to parse + * @return A usable AzLoopType instance + */ + static AzLoopType fromJson(JsonElement json) { + if (json == null || !json.isJsonPrimitive()) { + return PLAY_ONCE; + } + + var primitive = json.getAsJsonPrimitive(); + + if (primitive.isBoolean()) { + return primitive.getAsBoolean() ? LOOP : PLAY_ONCE; + } + + if (primitive.isString()) { + return fromString(primitive.getAsString()); + } + + return PLAY_ONCE; + } + + /** + * Retrieves an AzLoopType instance based on the given name. If the name does not match any registered loop type, + * the default {@link AzLoopType#PLAY_ONCE} is returned. + * + * @param name The name of the loop type to retrieve. + * @return The corresponding AzLoopType instance, or the default AzLoopType if no match is found. + */ + static AzLoopType fromString(String name) { + return LOOP_TYPES.getOrDefault(name, PLAY_ONCE); + } + + static AzLoopType register(String name, AzLoopType loopType) { + return register(name, (a, b, c) -> loopType.shouldPlayAgain(a, b, c)); + } + + /** + * Register a AzLoopType with AzureLib for handling loop functionality of animations..
    + * MUST be called during mod construct
    + * It is recommended you don't call this directly, and instead call it via {@code AzureLibUtil#addCustomLoopType} + * + * @param name The name of the loop type + * @param shouldPlayAgainFunction The loop type to register + * @return The registered {@code AzLoopType} + */ + static AzLoopType register( + String name, + TriFunction, AzBakedAnimation, Boolean> shouldPlayAgainFunction + ) { + var loopType = new AzLoopType() { + + @Override + public String name() { + return name; + } + + @Override + public boolean shouldPlayAgain( + Object animatable, + AzAnimationController controller, + AzBakedAnimation currentAnimation + ) { + return shouldPlayAgainFunction.apply(animatable, controller, currentAnimation); + } + }; + + LOOP_TYPES.put(name, loopType); + + return loopType; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzQueuedAnimation.java b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzQueuedAnimation.java new file mode 100644 index 000000000..dddd17844 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/primitive/AzQueuedAnimation.java @@ -0,0 +1,27 @@ +package mod.azure.azurelib.core2.animation.primitive; + +import mod.azure.azurelib.core2.animation.play_behavior.AzPlayBehavior; + +/** + * Represents an entry in an animation queue, combining an animation and its looping behavior. This record defines a + * queued animation to be played, including its associated {@link AzBakedAnimation} instance and the {@link AzPlayBehavior} + * that determines how the animation behaves once it reaches the end of its sequence.
    + *
    + * Instances of AzQueuedAnimation are immutable by design, ensuring that queued animations, once defined, cannot be + * modified, preserving their behavior within the animation controller.
    + *
    + * Fields: + *

      + *
    • {@code animation}: The {@link AzBakedAnimation} instance that contains the actual animation data to be + * played.
    • + *
    • {@code playBehavior}: The {@link AzPlayBehavior} that dictates the looping behavior or termination handling for the + * animation.
    • + *
    + * + * @deprecated + */ +@Deprecated(forRemoval = true) +public record AzQueuedAnimation( + AzBakedAnimation animation, + AzPlayBehavior playBehavior +) {} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/property/AzAnimationProperties.java b/common/src/main/java/mod/azure/azurelib/core2/animation/property/AzAnimationProperties.java new file mode 100644 index 000000000..8716e7e31 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/property/AzAnimationProperties.java @@ -0,0 +1,92 @@ +package mod.azure.azurelib.core2.animation.property; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +import mod.azure.azurelib.core2.animation.easing.AzEasingType; +import mod.azure.azurelib.core2.animation.easing.AzEasingTypes; +import mod.azure.azurelib.core2.animation.property.codec.AzAnimationPropertiesCodec; + +public class AzAnimationProperties { + + public static final AzAnimationPropertiesCodec CODEC = new AzAnimationPropertiesCodec(); + + public static final AzAnimationProperties DEFAULT = new AzAnimationProperties(1D, AzEasingTypes.NONE, 0F); + + public static final AzAnimationProperties EMPTY = new AzAnimationProperties(null, null, null); + + protected final @Nullable Double animationSpeed; + + protected final @Nullable AzEasingType easingType; + + protected final @Nullable Float transitionLength; + + public AzAnimationProperties( + @Nullable Double animationSpeed, + @Nullable AzEasingType easingType, + @Nullable Float transitionLength + ) { + this.animationSpeed = animationSpeed; + this.easingType = easingType; + this.transitionLength = transitionLength; + } + + public boolean hasAnimationSpeed() { + return animationSpeed != null; + } + + public boolean hasEasingType() { + return easingType != null; + } + + public boolean hasTransitionLength() { + return transitionLength != null; + } + + public AzAnimationProperties withAnimationSpeed(double animationSpeed) { + return new AzAnimationProperties(animationSpeed, easingType, transitionLength); + } + + public AzAnimationProperties withEasingType(@NotNull AzEasingType easingType) { + return new AzAnimationProperties(animationSpeed, easingType, transitionLength); + } + + public AzAnimationProperties withTransitionLength(float transitionLength) { + return new AzAnimationProperties(animationSpeed, easingType, transitionLength); + } + + public double animationSpeed() { + return animationSpeed == null ? DEFAULT.animationSpeed() : animationSpeed; + } + + public AzEasingType easingType() { + return easingType == null ? DEFAULT.easingType() : easingType; + } + + public float transitionLength() { + return transitionLength == null ? DEFAULT.transitionLength() : transitionLength; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + + if (object == null || getClass() != object.getClass()) { + return false; + } + + AzAnimationProperties that = (AzAnimationProperties) object; + + return Objects.equals(animationSpeed, that.animationSpeed) && Objects.equals(easingType, that.easingType) + && Objects.equals(transitionLength, that.transitionLength); + } + + @Override + public int hashCode() { + return Objects.hash(animationSpeed, easingType, transitionLength); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/property/AzAnimationStageProperties.java b/common/src/main/java/mod/azure/azurelib/core2/animation/property/AzAnimationStageProperties.java new file mode 100644 index 000000000..d95725d3f --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/property/AzAnimationStageProperties.java @@ -0,0 +1,89 @@ +package mod.azure.azurelib.core2.animation.property; + +import mod.azure.azurelib.core2.animation.play_behavior.AzPlayBehavior; +import mod.azure.azurelib.core2.animation.play_behavior.AzPlayBehaviors; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +import mod.azure.azurelib.core2.animation.easing.AzEasingType; +import mod.azure.azurelib.core2.animation.easing.AzEasingTypes; +import mod.azure.azurelib.core2.animation.property.codec.AzAnimationStagePropertiesCodec; + +public class AzAnimationStageProperties extends AzAnimationProperties { + + public static final AzAnimationStagePropertiesCodec CODEC = new AzAnimationStagePropertiesCodec(); + + public static final AzAnimationStageProperties DEFAULT = new AzAnimationStageProperties( + 1D, + AzEasingTypes.NONE, + AzPlayBehaviors.PLAY_ONCE, + 0F + ); + + public static final AzAnimationStageProperties EMPTY = new AzAnimationStageProperties(null, null, null, null); + + private final AzPlayBehavior playBehavior; + + public AzAnimationStageProperties( + @Nullable Double animationSpeed, + @Nullable AzEasingType easingType, + @Nullable AzPlayBehavior playBehavior, + @Nullable Float transitionLength + ) { + super(animationSpeed, easingType, transitionLength); + this.playBehavior = playBehavior; + } + + public boolean hasPlayBehavior() { + return playBehavior != null; + } + + @Override + public AzAnimationStageProperties withAnimationSpeed(double animationSpeed) { + return new AzAnimationStageProperties(animationSpeed, easingType, playBehavior, transitionLength); + } + + @Override + public AzAnimationStageProperties withEasingType(@NotNull AzEasingType easingType) { + return new AzAnimationStageProperties(animationSpeed, easingType, playBehavior, transitionLength); + } + + public AzAnimationStageProperties withPlayBehavior(@NotNull AzPlayBehavior playBehavior) { + return new AzAnimationStageProperties(animationSpeed, easingType, playBehavior, transitionLength); + } + + @Override + public AzAnimationStageProperties withTransitionLength(float transitionLength) { + return new AzAnimationStageProperties(animationSpeed, easingType, playBehavior, transitionLength); + } + + public AzPlayBehavior playBehavior() { + return playBehavior == null ? DEFAULT.playBehavior() : playBehavior; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + + if (object == null || getClass() != object.getClass()) { + return false; + } + + if (!super.equals(object)) { + return false; + } + + AzAnimationStageProperties that = (AzAnimationStageProperties) object; + + return Objects.equals(playBehavior, that.playBehavior) && super.equals(object); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), playBehavior); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/property/codec/AzAnimationPropertiesCodec.java b/common/src/main/java/mod/azure/azurelib/core2/animation/property/codec/AzAnimationPropertiesCodec.java new file mode 100644 index 000000000..6da554519 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/property/codec/AzAnimationPropertiesCodec.java @@ -0,0 +1,58 @@ +package mod.azure.azurelib.core2.animation.property.codec; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.core2.animation.easing.AzEasingTypeRegistry; +import mod.azure.azurelib.core2.animation.easing.AzEasingTypes; +import mod.azure.azurelib.core2.animation.property.AzAnimationProperties; + +public class AzAnimationPropertiesCodec implements StreamCodec { + + @Override + public @NotNull AzAnimationProperties decode(FriendlyByteBuf buf) { + var propertyLength = buf.readByte(); + var properties = AzAnimationProperties.EMPTY; + + for (int i = 0; i < propertyLength; i++) { + var code = buf.readByte(); + + switch (code) { + case 0 -> properties = properties.withAnimationSpeed(buf.readDouble()); + case 1 -> properties = properties.withTransitionLength(buf.readFloat()); + case 2 -> { + var easingType = AzEasingTypeRegistry.getOrDefault(buf.readUtf(), AzEasingTypes.NONE); + properties = properties.withEasingType(easingType); + } + } + } + + return properties; + } + + @Override + public void encode(FriendlyByteBuf buf, AzAnimationProperties properties) { + var propertyLength = 0; + propertyLength += properties.hasAnimationSpeed() ? 1 : 0; + propertyLength += properties.hasTransitionLength() ? 1 : 0; + propertyLength += properties.hasEasingType() ? 1 : 0; + + buf.writeByte(propertyLength); + + if (properties.hasAnimationSpeed()) { + buf.writeByte(0); + buf.writeDouble(properties.animationSpeed()); + } + + if (properties.hasTransitionLength()) { + buf.writeByte(1); + buf.writeFloat(properties.transitionLength()); + } + + if (properties.hasEasingType()) { + buf.writeByte(2); + buf.writeUtf(properties.easingType().name()); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/animation/property/codec/AzAnimationStagePropertiesCodec.java b/common/src/main/java/mod/azure/azurelib/core2/animation/property/codec/AzAnimationStagePropertiesCodec.java new file mode 100644 index 000000000..c78f67baa --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/animation/property/codec/AzAnimationStagePropertiesCodec.java @@ -0,0 +1,70 @@ +package mod.azure.azurelib.core2.animation.property.codec; + +import mod.azure.azurelib.core2.animation.play_behavior.AzPlayBehaviorRegistry; +import mod.azure.azurelib.core2.animation.play_behavior.AzPlayBehaviors; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.core2.animation.easing.AzEasingTypeRegistry; +import mod.azure.azurelib.core2.animation.easing.AzEasingTypes; +import mod.azure.azurelib.core2.animation.property.AzAnimationStageProperties; + +public class AzAnimationStagePropertiesCodec implements StreamCodec { + + @Override + public @NotNull AzAnimationStageProperties decode(FriendlyByteBuf buf) { + var propertyLength = buf.readByte(); + var properties = AzAnimationStageProperties.EMPTY; + + for (int i = 0; i < propertyLength; i++) { + var code = buf.readByte(); + + switch (code) { + case 0 -> properties = properties.withAnimationSpeed(buf.readDouble()); + case 1 -> properties = properties.withTransitionLength(buf.readFloat()); + case 2 -> { + var easingType = AzEasingTypeRegistry.getOrDefault(buf.readUtf(), AzEasingTypes.NONE); + properties = properties.withEasingType(easingType); + } + case 3 -> { + var playBehavior = AzPlayBehaviorRegistry.getOrDefault(buf.readUtf(), AzPlayBehaviors.PLAY_ONCE); + properties = properties.withPlayBehavior(playBehavior); + } + } + } + + return properties; + } + + @Override + public void encode(FriendlyByteBuf buf, AzAnimationStageProperties properties) { + var propertyLength = 0; + propertyLength += properties.hasAnimationSpeed() ? 1 : 0; + propertyLength += properties.hasTransitionLength() ? 1 : 0; + propertyLength += properties.hasEasingType() ? 1 : 0; + propertyLength += properties.hasPlayBehavior() ? 1 : 0; + + buf.writeByte(propertyLength); + + if (properties.hasAnimationSpeed()) { + buf.writeByte(0); + buf.writeDouble(properties.animationSpeed()); + } + + if (properties.hasTransitionLength()) { + buf.writeByte(1); + buf.writeFloat(properties.transitionLength()); + } + + if (properties.hasEasingType()) { + buf.writeByte(2); + buf.writeUtf(properties.easingType().name()); + } + + if (properties.hasPlayBehavior()) { + buf.writeByte(3); + buf.writeUtf(properties.playBehavior().name()); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java new file mode 100644 index 000000000..c393c52a4 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBakedModel.java @@ -0,0 +1,58 @@ +package mod.azure.azurelib.core2.model; + +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * Represents a baked 3D model consisting of hierarchical bone structures. This class is immutable and provides + * read-only access to bones by name or as a list of top-level bones. Bones are uniquely identified by their names. + */ +public class AzBakedModel { + + public static final AzBakedModel EMPTY = new AzBakedModel(List.of()); + + private final Map bonesByName; + + private final List topLevelBones; + + public AzBakedModel(List topLevelBones) { + this.topLevelBones = Collections.unmodifiableList(topLevelBones); + this.bonesByName = Collections.unmodifiableMap(mapBonesByName(topLevelBones)); + } + + private Map mapBonesByName(List bones) { + var bonesByName = new HashMap(); + var nodesToMap = new ArrayDeque<>(bones); + + while (!nodesToMap.isEmpty()) { + var currentBone = nodesToMap.poll(); + nodesToMap.addAll(currentBone.getChildBones()); + currentBone.saveInitialSnapshot(); + bonesByName.put(currentBone.getName(), currentBone); + } + + return bonesByName; + } + + public @Nullable AzBone getBoneOrNull(String name) { + return bonesByName.get(name); + } + + public Optional getBone(String name) { + return Optional.ofNullable(getBoneOrNull(name)); + } + + public Map getBonesByName() { + return bonesByName; + } + + public List getTopLevelBones() { + return topLevelBones; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java new file mode 100644 index 000000000..962bd2b31 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBone.java @@ -0,0 +1,464 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ +package mod.azure.azurelib.core2.model; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.joml.Matrix3f; +import org.joml.Matrix4f; +import org.joml.Vector3d; +import org.joml.Vector3f; +import org.joml.Vector4f; + +import java.util.List; +import java.util.Objects; + +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.core.animatable.model.CoreGeoBone; +import mod.azure.azurelib.core.state.BoneSnapshot; + +/** + * Mutable bone object representing a set of cubes, as well as child bones.
    + * This is the object that is directly modified by animations to handle movement + */ +public class AzBone implements CoreGeoBone { + + private final AzBoneMetadata metadata; + + private final List children = new ObjectArrayList<>(); + + private final List cubes = new ObjectArrayList<>(); + + private final Matrix4f modelSpaceMatrix = new Matrix4f(); + + private final Matrix4f localSpaceMatrix = new Matrix4f(); + + private final Matrix4f worldSpaceMatrix = new Matrix4f(); + + private AzBoneSnapshot initialSnapshot; + + private boolean hidden; + + private boolean childrenHidden = false; + + private final Vector3f pivot; + + private final Vector3f position; + + private final Vector3f rotation; + + private final Vector3f scale; + + private boolean positionChanged = false; + + private boolean rotationChanged = false; + + private boolean scaleChanged = false; + + private Matrix3f worldSpaceNormal = new Matrix3f(); + + private boolean trackingMatrices; + + public AzBone(AzBoneMetadata metadata) { + this.metadata = metadata; + this.trackingMatrices = false; + this.hidden = metadata.dontRender() == Boolean.TRUE; + + this.position = new Vector3f(); + this.pivot = new Vector3f(); + this.rotation = new Vector3f(); + this.scale = new Vector3f(1, 1, 1); + + this.worldSpaceNormal.identity(); + this.worldSpaceMatrix.identity(); + this.localSpaceMatrix.identity(); + this.modelSpaceMatrix.identity(); + } + + @Override + public String getName() { + return metadata.name(); + } + + @Override + public AzBone getParent() { + return metadata.parent(); + } + + @Override + public float getRotX() { + return this.rotation.x; + } + + @Override + public void setRotX(float value) { + this.rotation.x = value; + + markRotationAsChanged(); + } + + @Override + public float getRotY() { + return this.rotation.y; + } + + @Override + public void setRotY(float value) { + this.rotation.y = value; + + markRotationAsChanged(); + } + + @Override + public float getRotZ() { + return this.rotation.z; + } + + @Override + public void setRotZ(float value) { + this.rotation.z = value; + + markRotationAsChanged(); + } + + @Override + public float getPosX() { + return this.position.x; + } + + @Override + public void setPosX(float value) { + this.position.x = value; + + markPositionAsChanged(); + } + + @Override + public float getPosY() { + return this.position.y; + } + + @Override + public void setPosY(float value) { + this.position.y = value; + + markPositionAsChanged(); + } + + @Override + public float getPosZ() { + return this.position.z; + } + + @Override + public void setPosZ(float value) { + this.position.z = value; + + markPositionAsChanged(); + } + + @Override + public float getScaleX() { + return this.scale.x; + } + + @Override + public void setScaleX(float value) { + this.scale.x = value; + + markScaleAsChanged(); + } + + @Override + public float getScaleY() { + return this.scale.y; + } + + @Override + public void setScaleY(float value) { + this.scale.y = value; + + markScaleAsChanged(); + } + + @Override + public float getScaleZ() { + return this.scale.z; + } + + @Override + public void setScaleZ(float value) { + this.scale.z = value; + + markScaleAsChanged(); + } + + @Override + public boolean isHidden() { + return this.hidden; + } + + @Override + public void setHidden(boolean hidden) { + this.hidden = hidden; + + setChildrenHidden(hidden); + } + + @Override + public void setChildrenHidden(boolean hideChildren) { + this.childrenHidden = hideChildren; + } + + @Override + public float getPivotX() { + return this.pivot.x; + } + + @Override + public void setPivotX(float value) { + this.pivot.x = value; + } + + @Override + public float getPivotY() { + return this.pivot.y; + } + + @Override + public void setPivotY(float value) { + this.pivot.y = value; + } + + @Override + public float getPivotZ() { + return this.pivot.z; + } + + @Override + public void setPivotZ(float value) { + this.pivot.z = value; + } + + @Override + public boolean isHidingChildren() { + return this.childrenHidden; + } + + @Override + public void markScaleAsChanged() { + this.scaleChanged = true; + } + + @Override + public void markRotationAsChanged() { + this.rotationChanged = true; + } + + @Override + public void markPositionAsChanged() { + this.positionChanged = true; + } + + @Override + public boolean hasScaleChanged() { + return this.scaleChanged; + } + + @Override + public boolean hasRotationChanged() { + return this.rotationChanged; + } + + @Override + public boolean hasPositionChanged() { + return this.positionChanged; + } + + @Override + public void resetStateChanges() { + this.scaleChanged = false; + this.rotationChanged = false; + this.positionChanged = false; + } + + /** + * @deprecated DO NOT USE OR I WILL FIND YOU. + */ + @Override + @Deprecated(forRemoval = true) + public BoneSnapshot getInitialSnapshot() { + throw new UnsupportedOperationException(); + } + + public AzBoneSnapshot getInitialAzSnapshot() { + return this.initialSnapshot; + } + + @Override + public List getChildBones() { + return this.children; + } + + @Override + public void saveInitialSnapshot() { + if (this.initialSnapshot == null) { + this.initialSnapshot = new AzBoneSnapshot(this); + } + } + + public Boolean getMirror() { + return metadata.mirror(); + } + + public Double getInflate() { + return metadata.inflate(); + } + + public Boolean shouldNeverRender() { + return metadata.dontRender(); + } + + public Boolean getReset() { + return metadata.reset(); + } + + public List getCubes() { + return this.cubes; + } + + public boolean isTrackingMatrices() { + return trackingMatrices; + } + + public void setTrackingMatrices(boolean trackingMatrices) { + this.trackingMatrices = trackingMatrices; + } + + public Matrix4f getModelSpaceMatrix() { + setTrackingMatrices(true); + + return this.modelSpaceMatrix; + } + + public void setModelSpaceMatrix(Matrix4f matrix) { + this.modelSpaceMatrix.set(matrix); + } + + public Matrix4f getLocalSpaceMatrix() { + setTrackingMatrices(true); + + return this.localSpaceMatrix; + } + + public void setLocalSpaceMatrix(Matrix4f matrix) { + this.localSpaceMatrix.set(matrix); + } + + public Matrix4f getWorldSpaceMatrix() { + setTrackingMatrices(true); + + return this.worldSpaceMatrix; + } + + public void setWorldSpaceMatrix(Matrix4f matrix) { + this.worldSpaceMatrix.set(matrix); + } + + public Matrix3f getWorldSpaceNormal() { + return worldSpaceNormal; + } + + public void setWorldSpaceNormal(Matrix3f matrix) { + this.worldSpaceNormal = matrix; + } + + /** + * Get the position of the bone relative to its owner + */ + public Vector3d getLocalPosition() { + Vector4f vec = getLocalSpaceMatrix().transform(new Vector4f(0, 0, 0, 1)); + + return new Vector3d(vec.x(), vec.y(), vec.z()); + } + + /** + * Get the position of the bone relative to the model it belongs to + */ + public Vector3d getModelPosition() { + Vector4f vec = getModelSpaceMatrix().transform(new Vector4f(0, 0, 0, 1)); + + return new Vector3d(-vec.x() * 16f, vec.y() * 16f, vec.z() * 16f); + } + + public void setModelPosition(Vector3d pos) { + // Doesn't work on bones with parent transforms + AzBone parent = metadata.parent(); + Matrix4f matrix = (parent == null ? new Matrix4f().identity() : new Matrix4f(parent.getModelSpaceMatrix())) + .invert(); + Vector4f vec = matrix.transform( + new Vector4f(-(float) pos.x / 16f, (float) pos.y / 16f, (float) pos.z / 16f, 1) + ); + + updatePosition(-vec.x() * 16f, vec.y() * 16f, vec.z() * 16f); + } + + /** + * Get the position of the bone relative to the world + */ + public Vector3d getWorldPosition() { + Vector4f vec = getWorldSpaceMatrix().transform(new Vector4f(0, 0, 0, 1)); + + return new Vector3d(vec.x(), vec.y(), vec.z()); + } + + public Matrix4f getModelRotationMatrix() { + Matrix4f matrix = new Matrix4f(getModelSpaceMatrix()); + matrix.m03(0); + matrix.m13(0); + matrix.m23(0); + + return matrix; + } + + public Vector3d getPositionVector() { + return new Vector3d(getPosX(), getPosY(), getPosZ()); + } + + public Vector3d getRotationVector() { + return new Vector3d(getRotX(), getRotY(), getRotZ()); + } + + public Vector3d getScaleVector() { + return new Vector3d(getScaleX(), getScaleY(), getScaleZ()); + } + + public void addRotationOffsetFromBone(AzBone source) { + setRotX(getRotX() + source.getRotX() - source.getInitialAzSnapshot().getRotX()); + setRotY(getRotY() + source.getRotY() - source.getInitialAzSnapshot().getRotY()); + setRotZ(getRotZ() + source.getRotZ() - source.getInitialAzSnapshot().getRotZ()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + + if (obj == null || getClass() != obj.getClass()) + return false; + + return hashCode() == obj.hashCode(); + } + + @Override + public int hashCode() { + return Objects.hash( + getName(), + (getParent() != null ? getParent().getName() : 0), + getCubes().size(), + getChildBones().size() + ); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneMetadata.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneMetadata.java new file mode 100644 index 000000000..7b80ca1ec --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneMetadata.java @@ -0,0 +1,24 @@ +package mod.azure.azurelib.core2.model; + +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.common.internal.common.loading.json.raw.Bone; + +/** + * AzBoneMetadata is a record class representing metadata about a 3D model bone. This metadata provides information such + * as rendering preferences, inflation values, mirroring, hierarchy, and reset options for a bone in a 3D model's + * structure. + */ +public record AzBoneMetadata( + @Nullable Boolean dontRender, + @Nullable Double inflate, + Boolean mirror, + String name, + @Nullable AzBone parent, + @Nullable Boolean reset +) { + + public AzBoneMetadata(Bone bone, AzBone parent) { + this(bone.neverRender(), bone.inflate(), bone.mirror(), bone.name(), parent, bone.reset()); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneSnapshot.java b/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneSnapshot.java new file mode 100644 index 000000000..a4804d17c --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/AzBoneSnapshot.java @@ -0,0 +1,180 @@ +/** + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. + * https://github.com/bernie-g/geckolib/blob/main/LICENSE + */ + +package mod.azure.azurelib.core2.model; + +import org.joml.Vector3f; + +/** + * A state monitoring class for a given {@link AzBone}.
    + */ +public class AzBoneSnapshot { + + private final AzBone bone; + + private final Vector3f offsetPosition; + + private final Vector3f rotation; + + private final Vector3f scale; + + private double lastResetRotationTick = 0; + + private double lastResetPositionTick = 0; + + private double lastResetScaleTick = 0; + + private boolean rotAnimInProgress = true; + + private boolean posAnimInProgress = true; + + private boolean scaleAnimInProgress = true; + + public AzBoneSnapshot(AzBone bone) { + this.bone = bone; + this.offsetPosition = new Vector3f(bone.getPosX(), bone.getPosY(), bone.getPosZ()); + this.rotation = new Vector3f(bone.getRotX(), bone.getRotY(), bone.getRotZ()); + this.scale = new Vector3f(bone.getScaleX(), bone.getScaleY(), bone.getScaleZ()); + } + + public static AzBoneSnapshot copy(AzBoneSnapshot snapshot) { + AzBoneSnapshot newSnapshot = new AzBoneSnapshot(snapshot.bone); + + newSnapshot.offsetPosition.set(snapshot.offsetPosition); + newSnapshot.rotation.set(snapshot.rotation); + newSnapshot.scale.set(snapshot.scale); + + return newSnapshot; + } + + public AzBone getBone() { + return this.bone; + } + + public float getScaleX() { + return this.scale.x; + } + + public float getScaleY() { + return this.scale.y; + } + + public float getScaleZ() { + return this.scale.z; + } + + public float getOffsetX() { + return this.offsetPosition.x; + } + + public float getOffsetY() { + return this.offsetPosition.y; + } + + public float getOffsetZ() { + return this.offsetPosition.z; + } + + public float getRotX() { + return this.rotation.x; + } + + public float getRotY() { + return this.rotation.y; + } + + public float getRotZ() { + return this.rotation.z; + } + + public double getLastResetRotationTick() { + return this.lastResetRotationTick; + } + + public double getLastResetPositionTick() { + return this.lastResetPositionTick; + } + + public double getLastResetScaleTick() { + return this.lastResetScaleTick; + } + + public boolean isRotAnimInProgress() { + return this.rotAnimInProgress; + } + + public boolean isPosAnimInProgress() { + return this.posAnimInProgress; + } + + public boolean isScaleAnimInProgress() { + return this.scaleAnimInProgress; + } + + /** + * Update the scale state of this snapshot + */ + public void updateScale(float scaleX, float scaleY, float scaleZ) { + scale.set(scaleX, scaleY, scaleZ); + } + + /** + * Update the offset state of this snapshot + */ + public void updateOffset(float offsetX, float offsetY, float offsetZ) { + offsetPosition.set(offsetX, offsetY, offsetZ); + } + + /** + * Update the rotation state of this snapshot + */ + public void updateRotation(float rotX, float rotY, float rotZ) { + rotation.set(rotX, rotY, rotZ); + } + + public void startPosAnim() { + this.posAnimInProgress = true; + } + + public void stopPosAnim(double tick) { + this.posAnimInProgress = false; + this.lastResetPositionTick = tick; + } + + public void startRotAnim() { + this.rotAnimInProgress = true; + } + + public void stopRotAnim(double tick) { + this.rotAnimInProgress = false; + this.lastResetRotationTick = tick; + } + + public void startScaleAnim() { + this.scaleAnimInProgress = true; + } + + public void stopScaleAnim(double tick) { + this.scaleAnimInProgress = false; + this.lastResetScaleTick = tick; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + + if (obj == null || getClass() != obj.getClass()) + return false; + + return hashCode() == obj.hashCode(); + } + + @Override + public int hashCode() { + return this.bone.getName().hashCode(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java b/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java new file mode 100644 index 000000000..2e22e3581 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/cache/AzBakedModelCache.java @@ -0,0 +1,50 @@ +package mod.azure.azurelib.core2.model.cache; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import mod.azure.azurelib.common.internal.common.loading.FileLoader; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Model; +import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; +import mod.azure.azurelib.core2.AzResourceCache; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.factory.registry.AzBakedModelFactoryRegistry; + +/** + * AzBakedModelCache is a singleton class that extends {@link AzResourceCache} and is designed to manage and cache baked + * models of type {@link AzBakedModel}. It provides functionality to asynchronously load and store models associated + * with specific resource locations. + */ +public class AzBakedModelCache extends AzResourceCache { + + private static final AzBakedModelCache INSTANCE = new AzBakedModelCache(); + + public static AzBakedModelCache getInstance() { + return INSTANCE; + } + + private final Map bakedModels; + + private AzBakedModelCache() { + this.bakedModels = new Object2ObjectOpenHashMap<>(); + } + + public CompletableFuture loadModels(Executor backgroundExecutor, ResourceManager resourceManager) { + return loadResources(backgroundExecutor, resourceManager, "geo", resource -> { + Model model = FileLoader.loadModelFile(resource, resourceManager); + + return AzBakedModelFactoryRegistry.getForNamespace(resource.getNamespace()) + .constructGeoModel(GeometryTree.fromModel(model)); + }, bakedModels::put); + } + + public @Nullable AzBakedModel getNullable(ResourceLocation resourceLocation) { + return bakedModels.get(resourceLocation); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java new file mode 100644 index 000000000..3c8216924 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/AzBakedModelFactory.java @@ -0,0 +1,148 @@ +package mod.azure.azurelib.core2.model.factory; + +import net.minecraft.core.Direction; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Cube; +import mod.azure.azurelib.common.internal.common.loading.json.raw.FaceUV; +import mod.azure.azurelib.common.internal.common.loading.json.raw.ModelProperties; +import mod.azure.azurelib.common.internal.common.loading.json.raw.UVUnion; +import mod.azure.azurelib.common.internal.common.loading.object.BoneStructure; +import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.factory.primitive.VertexSet; + +/** + * Abstract factory class for constructing baked models, bones, and cubes from raw input data such as geometry trees or + * properties. This class provides a structure for defining the creation of complex 3D models, including managing + * hierarchical relationships between bones and their associated components. + */ +public abstract class AzBakedModelFactory { + + /** + * Construct the output model from the given {@link GeometryTree}.
    + */ + public abstract AzBakedModel constructGeoModel(GeometryTree geometryTree); + + /** + * Construct a {@link AzBone} from the relevant raw input data + * + * @param boneStructure The {@code BoneStructure} comprising the structure of the bone and its children + * @param properties The loaded properties for the model + * @param parent The parent bone for this bone, or null if a top-level bone + */ + public abstract AzBone constructBone( + BoneStructure boneStructure, + ModelProperties properties, + @Nullable AzBone parent + ); + + /** + * Construct a {@link GeoCube} from the relevant raw input data + * + * @param cube The raw {@code Cube} comprising the structure and properties of the cube + * @param properties The loaded properties for the model + * @param bone The bone this cube belongs to + */ + public abstract GeoCube constructCube(Cube cube, ModelProperties properties, AzBone bone); + + /** + * Builtin method to construct the quad list from the various vertices and related data, to make it easier.
    + * Vertices have already been mirrored here if {@code mirror} is true + */ + public GeoQuad[] buildQuads( + UVUnion uvUnion, + VertexSet vertices, + Cube cube, + float textureWidth, + float textureHeight, + boolean mirror + ) { + GeoQuad[] quads = new GeoQuad[6]; + + quads[0] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.WEST); + quads[1] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.EAST); + quads[2] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.NORTH); + quads[3] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.SOUTH); + quads[4] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.UP); + quads[5] = buildQuad(vertices, cube, uvUnion, textureWidth, textureHeight, mirror, Direction.DOWN); + + return quads; + } + + /** + * Build an individual quad + */ + public GeoQuad buildQuad( + VertexSet vertices, + Cube cube, + UVUnion uvUnion, + float textureWidth, + float textureHeight, + boolean mirror, + Direction direction + ) { + if (!uvUnion.isBoxUV()) { + FaceUV faceUV = uvUnion.faceUV().fromDirection(direction); + + if (faceUV == null) + return null; + + return GeoQuad.build( + vertices.verticesForQuad(direction, false, mirror || cube.mirror() == Boolean.TRUE), + faceUV.uv(), + faceUV.uvSize(), + faceUV.uvRotation(), + textureWidth, + textureHeight, + mirror, + direction + ); + } + + double[] uv = cube.uv().boxUVCoords(); + double[] uvSize = cube.size(); + Vec3 uvSizeVec = new Vec3(Math.floor(uvSize[0]), Math.floor(uvSize[1]), Math.floor(uvSize[2])); + double[][] uvData = switch (direction) { + case WEST -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.z, uvSizeVec.y } + }; + case EAST -> new double[][] { + new double[] { uv[0], uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.z, uvSizeVec.y } + }; + case NORTH -> new double[][] { + new double[] { uv[0] + uvSizeVec.z, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, uvSizeVec.y } + }; + case SOUTH -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x + uvSizeVec.z, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, uvSizeVec.y } + }; + case UP -> new double[][] { + new double[] { uv[0] + uvSizeVec.z, uv[1] }, + new double[] { uvSizeVec.x, uvSizeVec.z } + }; + case DOWN -> new double[][] { + new double[] { uv[0] + uvSizeVec.z + uvSizeVec.x, uv[1] + uvSizeVec.z }, + new double[] { uvSizeVec.x, -uvSizeVec.z } + }; + }; + + return GeoQuad.build( + vertices.verticesForQuad(direction, true, mirror || cube.mirror() == Boolean.TRUE), + uvData[0], + uvData[1], + FaceUV.Rotation.NONE, + textureWidth, + textureHeight, + mirror, + direction + ); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java new file mode 100644 index 000000000..d512aa8a3 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/impl/AzBuiltinBakedModelFactory.java @@ -0,0 +1,89 @@ +package mod.azure.azurelib.core2.model.factory.impl; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.world.phys.Vec3; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.common.internal.common.loading.json.raw.Cube; +import mod.azure.azurelib.common.internal.common.loading.json.raw.ModelProperties; +import mod.azure.azurelib.common.internal.common.loading.object.BoneStructure; +import mod.azure.azurelib.common.internal.common.loading.object.GeometryTree; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.model.AzBoneMetadata; +import mod.azure.azurelib.core2.model.factory.AzBakedModelFactory; +import mod.azure.azurelib.core2.model.factory.primitive.VertexSet; + +/** + * A concrete implementation of the {@link AzBakedModelFactory} that constructs baked models, bones, and cubes from raw + * geometry data. It is tailored to create and configure the model and its associated components in a hierarchical + * manner, based on the provided structure and properties. + */ +public final class AzBuiltinBakedModelFactory extends AzBakedModelFactory { + + @Override + public AzBakedModel constructGeoModel(GeometryTree geometryTree) { + var bones = new ObjectArrayList(); + + for (var boneStructure : geometryTree.topLevelBones().values()) { + bones.add(constructBone(boneStructure, geometryTree.properties(), null)); + } + + return new AzBakedModel(bones); + } + + @Override + public AzBone constructBone(BoneStructure boneStructure, ModelProperties properties, AzBone parent) { + var bone = boneStructure.self(); + var boneMetadata = new AzBoneMetadata(bone, parent); + var newBone = new AzBone(boneMetadata); + var rotation = RenderUtils.arrayToVec(bone.rotation()); + var pivot = RenderUtils.arrayToVec(bone.pivot()); + + newBone.updateRotation( + (float) Math.toRadians(-rotation.x), + (float) Math.toRadians(-rotation.y), + (float) Math.toRadians(rotation.z) + ); + newBone.updatePivot((float) -pivot.x, (float) pivot.y, (float) pivot.z); + + for (var cube : bone.cubes()) { + newBone.getCubes().add(constructCube(cube, properties, newBone)); + } + + // TODO: Avoid recursive calls here. + for (var child : boneStructure.children().values()) { + newBone.getChildBones().add(constructBone(child, properties, newBone)); + } + + return newBone; + } + + @Override + public GeoCube constructCube(Cube cube, ModelProperties properties, AzBone bone) { + var mirror = cube.mirror() == Boolean.TRUE; + var inflate = cube.inflate() != null + ? cube.inflate() / 16f + : (bone.getInflate() == null ? 0 : bone.getInflate() / 16f); + var size = RenderUtils.arrayToVec(cube.size()); + var origin = RenderUtils.arrayToVec(cube.origin()); + var rotation = RenderUtils.arrayToVec(cube.rotation()); + var pivot = RenderUtils.arrayToVec(cube.pivot()); + origin = new Vec3(-(origin.x + size.x) / 16d, origin.y / 16d, origin.z / 16d); + var vertexSize = size.multiply(1 / 16d, 1 / 16d, 1 / 16d); + + pivot = pivot.multiply(-1, 1, 1); + rotation = new Vec3(Math.toRadians(-rotation.x), Math.toRadians(-rotation.y), Math.toRadians(rotation.z)); + var quads = buildQuads( + cube.uv(), + new VertexSet(origin, vertexSize, inflate), + cube, + (float) properties.textureWidth(), + (float) properties.textureHeight(), + mirror + ); + + return new GeoCube(quads, pivot, rotation, size, inflate, mirror); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/primitive/VertexSet.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/primitive/VertexSet.java new file mode 100644 index 000000000..20c86e27f --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/primitive/VertexSet.java @@ -0,0 +1,121 @@ +package mod.azure.azurelib.core2.model.factory.primitive; + +import net.minecraft.core.Direction; +import net.minecraft.world.phys.Vec3; + +import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; + +/** + * Holder class to make it easier to store and refer to vertices for a given cube + */ +public record VertexSet( + GeoVertex bottomLeftBack, + GeoVertex bottomRightBack, + GeoVertex topLeftBack, + GeoVertex topRightBack, + GeoVertex topLeftFront, + GeoVertex topRightFront, + GeoVertex bottomLeftFront, + GeoVertex bottomRightFront +) { + + public VertexSet(Vec3 origin, Vec3 vertexSize, double inflation) { + this( + new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z - inflation), + new GeoVertex(origin.x - inflation, origin.y - inflation, origin.z + vertexSize.z + inflation), + new GeoVertex(origin.x - inflation, origin.y + vertexSize.y + inflation, origin.z - inflation), + new GeoVertex( + origin.x - inflation, + origin.y + vertexSize.y + inflation, + origin.z + vertexSize.z + inflation + ), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y + vertexSize.y + inflation, + origin.z - inflation + ), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y + vertexSize.y + inflation, + origin.z + vertexSize.z + inflation + ), + new GeoVertex(origin.x + vertexSize.x + inflation, origin.y - inflation, origin.z - inflation), + new GeoVertex( + origin.x + vertexSize.x + inflation, + origin.y - inflation, + origin.z + vertexSize.z + inflation + ) + ); + } + + /** + * Returns the normal vertex array for a west-facing quad + */ + public GeoVertex[] quadWest() { + return new GeoVertex[] { this.topRightBack, this.topLeftBack, this.bottomLeftBack, this.bottomRightBack }; + } + + /** + * Returns the normal vertex array for an east-facing quad + */ + public GeoVertex[] quadEast() { + return new GeoVertex[] { + this.topLeftFront, + this.topRightFront, + this.bottomRightFront, + this.bottomLeftFront + }; + } + + /** + * Returns the normal vertex array for a north-facing quad + */ + public GeoVertex[] quadNorth() { + return new GeoVertex[] { this.topLeftBack, this.topLeftFront, this.bottomLeftFront, this.bottomLeftBack }; + } + + /** + * Returns the normal vertex array for a south-facing quad + */ + public GeoVertex[] quadSouth() { + return new GeoVertex[] { + this.topRightFront, + this.topRightBack, + this.bottomRightBack, + this.bottomRightFront + }; + } + + /** + * Returns the normal vertex array for a top-facing quad + */ + public GeoVertex[] quadUp() { + return new GeoVertex[] { this.topRightBack, this.topRightFront, this.topLeftFront, this.topLeftBack }; + } + + /** + * Returns the normal vertex array for a bottom-facing quad + */ + public GeoVertex[] quadDown() { + return new GeoVertex[] { + this.bottomLeftBack, + this.bottomLeftFront, + this.bottomRightFront, + this.bottomRightBack + }; + } + + /** + * Return the vertex array relevant to the quad being built, taking into account mirroring and quad type + */ + public GeoVertex[] verticesForQuad(Direction direction, boolean boxUv, boolean mirror) { + return switch (direction) { + case WEST -> mirror ? quadEast() : quadWest(); + case EAST -> mirror ? quadWest() : quadEast(); + case NORTH -> quadNorth(); + case SOUTH -> quadSouth(); + case UP -> mirror && !boxUv ? quadDown() : quadUp(); + case DOWN -> mirror && !boxUv ? quadUp() : quadDown(); + }; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/model/factory/registry/AzBakedModelFactoryRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/model/factory/registry/AzBakedModelFactoryRegistry.java new file mode 100644 index 000000000..7a7106781 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/model/factory/registry/AzBakedModelFactoryRegistry.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.core2.model.factory.registry; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +import java.util.Map; + +import mod.azure.azurelib.common.internal.common.util.AzureLibUtil; +import mod.azure.azurelib.core2.model.factory.AzBakedModelFactory; +import mod.azure.azurelib.core2.model.factory.impl.AzBuiltinBakedModelFactory; + +/** + * A registry for managing instances of {@link AzBakedModelFactory} that are used to handle the creation of baked models + * for specific namespaces. This allows custom behavior for different mods or namespaces when constructing models.
    + * This class provides functionality to register, retrieve, and manage baked model factories. It ensures that a default + * factory is available for any namespace that does not explicitly register a custom factory. + */ +public class AzBakedModelFactoryRegistry { + + private static final Map FACTORIES = new Object2ObjectOpenHashMap<>(1); + + private static final AzBakedModelFactory DEFAULT_FACTORY = new AzBuiltinBakedModelFactory(); + + public static AzBakedModelFactory getForNamespace(String namespace) { + return FACTORIES.getOrDefault(namespace, DEFAULT_FACTORY); + } + + /** + * Register a custom {@link AzBakedModelFactory} to handle loading models in a custom way.
    + * MUST be called during mod construct
    + * It is recommended you don't call this directly, and instead call it via + * {@link AzureLibUtil#addCustomBakedModelFactory} + * + * @param namespace The namespace (modid) to register the factory for + * @param factory The factory responsible for model loading under the given namespace + */ + public static void register(String namespace, AzBakedModelFactory factory) { + FACTORIES.put(namespace, factory); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzLayerRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzLayerRenderer.java new file mode 100644 index 000000000..46bc4b75e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzLayerRenderer.java @@ -0,0 +1,52 @@ +package mod.azure.azurelib.core2.render; + +import java.util.Collection; +import java.util.function.Supplier; + +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +/** + * Provides a mechanism to manage and apply multiple render layers for a given animatable context. This class acts as a + * wrapper for handling collections of render layers and delegates the rendering responsibilities to the individual + * layers. + * + * @param The type of animatable entity or object the render layers apply to. + */ +public class AzLayerRenderer { + + private final Supplier>> renderLayerSupplier; + + public AzLayerRenderer(Supplier>> renderLayerSupplier) { + this.renderLayerSupplier = renderLayerSupplier; + } + + /** + * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their + * {@link AzRenderLayer#preRender pre-render} actions. + */ + protected void preApplyRenderLayers(AzRendererPipelineContext context) { + for (var renderLayer : renderLayerSupplier.get()) { + renderLayer.preRender(context); + } + } + + /** + * Calls back to the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer for their + * {@link AzRenderLayer#renderForBone per-bone} render actions. + */ + public void applyRenderLayersForBone(AzRendererPipelineContext context, AzBone bone) { + for (var renderLayer : renderLayerSupplier.get()) { + renderLayer.renderForBone(context, bone); + } + } + + /** + * Render the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer + */ + protected void applyRenderLayers(AzRendererPipelineContext context) { + for (var renderLayer : renderLayerSupplier.get()) { + renderLayer.render(context); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzModelRenderer.java new file mode 100644 index 000000000..4c2344d09 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzModelRenderer.java @@ -0,0 +1,165 @@ +package mod.azure.azurelib.core2.render; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.joml.Vector4f; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.object.GeoCube; +import mod.azure.azurelib.common.internal.common.cache.object.GeoQuad; +import mod.azure.azurelib.common.internal.common.cache.object.GeoVertex; +import mod.azure.azurelib.core2.model.AzBone; + +/** + * AzModelRenderer provides a generic and extensible base class for rendering models by processing hierarchical bone + * structures recursively. It leverages a rendering pipeline and a layer renderer to facilitate advanced rendering + * tasks, including layer application and animated texture processing. + * + * @param the type of animatable object this renderer supports + */ +public class AzModelRenderer { + + private final Matrix4f poseStateCache = new Matrix4f(); + + private final Vector3f normalCache = new Vector3f(); + + private final AzRendererPipeline rendererPipeline; + + protected final AzLayerRenderer layerRenderer; + + public AzModelRenderer(AzRendererPipeline rendererPipeline, AzLayerRenderer layerRenderer) { + this.layerRenderer = layerRenderer; + this.rendererPipeline = rendererPipeline; + } + + /** + * The actual render method that sub-type renderers should override to handle their specific rendering tasks.
    + */ + protected void render(AzRendererPipelineContext context, boolean isReRender) { + var animatable = context.animatable(); + var model = context.bakedModel(); + + rendererPipeline.updateAnimatedTextureFrame(animatable); + + for (var bone : model.getTopLevelBones()) { + renderRecursively(context, bone, isReRender); + } + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + protected void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + var poseStack = context.poseStack(); + + poseStack.pushPose(); + RenderUtils.prepMatrixForBone(poseStack, bone); + renderCubesOfBone(context, bone); + + if (!isReRender) { + layerRenderer.applyRenderLayersForBone(context, bone); + } + + renderChildBones(context, bone, isReRender); + poseStack.popPose(); + } + + /** + * Renders the {@link GeoCube GeoCubes} associated with a given {@link AzBone} + */ + protected void renderCubesOfBone(AzRendererPipelineContext context, AzBone bone) { + if (bone.isHidden()) { + return; + } + + var poseStack = context.poseStack(); + + for (var cube : bone.getCubes()) { + poseStack.pushPose(); + + renderCube(context, cube); + + poseStack.popPose(); + } + } + + /** + * Render the child bones of a given {@link AzBone}.
    + * Note that this does not render the bone itself. That should be done through + * {@link AzModelRenderer#renderCubesOfBone} separately + */ + protected void renderChildBones(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + if (bone.isHidingChildren()) + return; + + for (var childBone : bone.getChildBones()) { + renderRecursively(context, childBone, isReRender); + } + } + + /** + * Renders an individual {@link GeoCube}.
    + * This tends to be called recursively from something like {@link AzModelRenderer#renderCubesOfBone} + */ + protected void renderCube(AzRendererPipelineContext context, GeoCube cube) { + var poseStack = context.poseStack(); + + RenderUtils.translateToPivotPoint(poseStack, cube); + RenderUtils.rotateMatrixAroundCube(poseStack, cube); + RenderUtils.translateAwayFromPivotPoint(poseStack, cube); + + var normalisedPoseState = poseStack.last().normal(); + var poseState = poseStateCache.set(poseStack.last().pose()); + + for (var quad : cube.quads()) { + if (quad == null) { + continue; + } + + normalCache.set(quad.normal()); + var normal = normalisedPoseState.transform(normalCache); + + RenderUtils.fixInvertedFlatCube(cube, normal); + createVerticesOfQuad(context, quad, poseState, normal); + } + } + + private final Vector4f poseStateTransformCache = new Vector4f(); + + /** + * Applies the {@link GeoQuad Quad's} {@link GeoVertex vertices} to the given {@link VertexConsumer buffer} for + * rendering + */ + protected void createVerticesOfQuad( + AzRendererPipelineContext context, + GeoQuad quad, + Matrix4f poseState, + Vector3f normal + ) { + var buffer = context.vertexConsumer(); + var color = context.renderColor(); + var packedOverlay = context.packedOverlay(); + var packedLight = context.packedLight(); + + for (var vertex : quad.vertices()) { + var position = vertex.position(); + poseStateTransformCache.set(position.x(), position.y(), position.z(), 1.0f); + var vector4f = poseState.transform(poseStateTransformCache); + + buffer.addVertex( + vector4f.x(), + vector4f.y(), + vector4f.z(), + color, + vertex.texU(), + vertex.texV(), + packedOverlay, + packedLight, + normal.x(), + normal.y(), + normal.z() + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzPhasedRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzPhasedRenderer.java new file mode 100644 index 000000000..ca7b797c8 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzPhasedRenderer.java @@ -0,0 +1,29 @@ +package mod.azure.azurelib.core2.render; + +import com.mojang.blaze3d.vertex.PoseStack; + +/** + * Represents a phased renderer interface used as part of a rendering pipeline. Allows customization at specific stages + * of the rendering process for animatable models.
    + * The interface provides two key methods, enabling actions to be taken before and after the core rendering operations + * within the pipeline, specifically focusing on transforming and modifying render contexts.
    + * This is part of a flexible rendering system that enables complex rendering logic while maintaining separation of + * concerns and modularity. + * + * @param The type of animatable object being rendered. + */ +public interface AzPhasedRenderer { + + /** + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
    + * {@link PoseStack} translations made here are kept until the end of the render process + */ + void preRender(AzRendererPipelineContext context, boolean isReRender); + + /** + * Called after rendering the model to buffer. Post-render modifications should be performed here.
    + * {@link PoseStack} transformations will be unused and lost once this method ends + */ + void postRender(AzRendererPipelineContext context, boolean isReRender); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzProvider.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzProvider.java new file mode 100644 index 000000000..ec9fb9789 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzProvider.java @@ -0,0 +1,79 @@ +package mod.azure.azurelib.core2.render; + +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; +import java.util.function.Supplier; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.animation.AzAnimatorAccessor; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.cache.AzBakedModelCache; + +/** + * The {@code AzProvider} class serves as a utility for providing animation-related resources, such as baked models and + * animators for animatable objects of type {@code T}. This class facilitates the dynamic retrieval and caching of + * resources to enhance performance during runtime and minimize redundant resource generation. + * + * @param The type of the animatable object this provider works with (e.g., an entity, block, or item). + */ +public class AzProvider { + + private final Supplier> animatorSupplier; + + private final Function modelLocationProvider; + + public AzProvider( + Supplier> animatorSupplier, + Function modelLocationProvider + ) { + this.animatorSupplier = animatorSupplier; + this.modelLocationProvider = modelLocationProvider; + } + + /** + * Provides a baked model associated with the specified animatable object. This method retrieves the model resource + * location for the animatable object using the configured model location provider, then fetches the corresponding + * baked model from the {@link AzBakedModelCache}. + * + * @param animatable the animatable object for which the baked model should be retrieved, must not be null + * @return the baked model associated with the animatable object, or null if no model is found + */ + public @Nullable AzBakedModel provideBakedModel(@NotNull T animatable) { + var modelResourceLocation = modelLocationProvider.apply(animatable); + return AzBakedModelCache.getInstance().getNullable(modelResourceLocation); + } + + /** + * Provides an {@link AzAnimator} instance associated with the given animatable object. If the animator is not + * already cached, this method will create a new animator, register its controllers, and cache it for future use. + * + * @param animatable the animatable object for which the animator should be provided + * @return an {@link AzAnimator} instance associated with the animatable object, or null if the animator could not + * be created or retrieved + */ + public @Nullable AzAnimator provideAnimator(T animatable) { + // TODO: Instead of caching the entire animator itself, we're going to want to cache the relevant data for the + // entity. + var accessor = AzAnimatorAccessor.cast(animatable); + var cachedAnimator = accessor.getAnimatorOrNull(); + + if (cachedAnimator == null) { + // If the cached animator is null, create a new one. We use a separate reference here just for some + cachedAnimator = animatorSupplier.get(); + + if (cachedAnimator != null) { + // If the new animator we created is not null, then register its controllers. + cachedAnimator.registerControllers( + cachedAnimator.getAnimationControllerContainer() + ); + // Also cache the animator so that the next time we fetch the animator, it's ready for us. + accessor.setAnimator(cachedAnimator); + } + } + + return cachedAnimator; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java new file mode 100644 index 000000000..5cac75239 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererConfig.java @@ -0,0 +1,164 @@ +package mod.azure.azurelib.core2.render; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +/** + * The {@code AzRendererConfig} class is a configuration class used for defining rendering configurations for generic + * animatable objects. It allows customization of model and texture locations, animators, render layers, and scale + * factors. + * + * @param The type of animatable object this configuration applies to. + */ +public class AzRendererConfig { + + private final Supplier<@Nullable AzAnimator> animatorProvider; + + private final Function modelLocationProvider; + + private final List> renderLayers; + + private final Function textureLocationProvider; + + private final float scaleHeight; + + private final float scaleWidth; + + public AzRendererConfig( + Supplier> animatorProvider, + Function modelLocationProvider, + List> renderLayers, + Function textureLocationProvider, + float scaleHeight, + float scaleWidth + ) { + this.animatorProvider = animatorProvider; + this.modelLocationProvider = modelLocationProvider; + this.renderLayers = Collections.unmodifiableList(renderLayers); + this.textureLocationProvider = textureLocationProvider; + this.scaleHeight = scaleHeight; + this.scaleWidth = scaleWidth; + } + + public @Nullable AzAnimator createAnimator() { + return animatorProvider.get(); + } + + public ResourceLocation modelLocation(T animatable) { + return modelLocationProvider.apply(animatable); + } + + public ResourceLocation textureLocation(T animatable) { + return textureLocationProvider.apply(animatable); + } + + public List> renderLayers() { + return renderLayers; + } + + public float scaleHeight() { + return scaleHeight; + } + + public float scaleWidth() { + return scaleWidth; + } + + public static class Builder { + + private final Function modelLocationProvider; + + private final List> renderLayers; + + private final Function textureLocationProvider; + + private Supplier<@Nullable AzAnimator> animatorProvider; + + private float scaleHeight; + + private float scaleWidth; + + protected Builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + this.animatorProvider = () -> null; + this.modelLocationProvider = modelLocationProvider; + this.renderLayers = new ObjectArrayList<>(); + this.textureLocationProvider = textureLocationProvider; + this.scaleHeight = 1; + this.scaleWidth = 1; + } + + /** + * Sets the animator provider for the builder. The animator provider is responsible for supplying an instance of + * {@link AzAnimator} that defines the animation logic for the target object. + * + * @param animatorProvider a {@link Supplier} that provides a {@link AzAnimator} instance or null if no custom + * animation logic is required + * @return the updated {@code Builder} instance for chaining configuration methods + */ + public Builder setAnimatorProvider(Supplier<@Nullable AzAnimator> animatorProvider) { + this.animatorProvider = animatorProvider; + return this; + } + + /** + * Adds a {@link AzRenderLayer} to this config, to be called after the main model is rendered each frame + */ + public Builder addRenderLayer(AzRenderLayer renderLayer) { + this.renderLayers.add(renderLayer); + return this; + } + + /** + * Sets the scaling factor uniformly for both width and height dimensions. + * + * @param scale the uniform scaling factor to be applied to both width and height + * @return the {@code Builder} instance for method chaining + */ + public Builder setScale(float scale) { + return setScale(scale, scale); + } + + /** + * Sets the scaling factors for both width and height. + * + * @param scaleWidth the scaling factor for the width + * @param scaleHeight the scaling factor for the height + * @return the updated builder instance for chaining operations + */ + public Builder setScale(float scaleWidth, float scaleHeight) { + this.scaleHeight = scaleHeight; + this.scaleWidth = scaleWidth; + return this; + } + + /** + * Builds and returns a finalized {@link AzRendererConfig} instance with the current configuration settings + * provided through the builder. + * + * @return a new instance of {@link AzRendererConfig} configured with the specified animator provider, model + * location provider, texture location provider, render layers, and scale factors. + */ + public AzRendererConfig build() { + return new AzRendererConfig<>( + animatorProvider, + modelLocationProvider, + renderLayers, + textureLocationProvider, + scaleHeight, + scaleWidth + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipeline.java new file mode 100644 index 000000000..489ec1727 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipeline.java @@ -0,0 +1,185 @@ +package mod.azure.azurelib.core2.render; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +/** + * Abstract base class for defining a rendering pipeline. The {@code AzRendererPipeline} provides a structured framework + * to handle complex rendering tasks by separating responsibilities into different components, such as layer rendering + * and model rendering. + * + * @param The type of the object to be rendered. + */ +public abstract class AzRendererPipeline implements AzPhasedRenderer { + + protected final AzRendererConfig config; + + private final AzRendererPipelineContext context; + + private final AzLayerRenderer layerRenderer; + + private final AzModelRenderer modelRenderer; + + protected AzRendererPipeline(AzRendererConfig config) { + this.config = config; + this.context = createContext(this); + this.layerRenderer = createLayerRenderer(config); + this.modelRenderer = createModelRenderer(layerRenderer); + } + + /** + * Creates a rendering pipeline context for the specified renderer pipeline. This method is intended to be + * implemented by subclasses to provide a specific implementation of the {@link AzRendererPipelineContext} for + * rendering. + * + * @param rendererPipeline the renderer pipeline for which the context is to be created + * @return a new instance of {@link AzRendererPipelineContext} specific to the given renderer pipeline + */ + protected abstract AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline); + + /** + * Creates an instance of {@link AzModelRenderer} using the provided {@link AzLayerRenderer}. This method is part of + * the rendering pipeline and is responsible for generating a model renderer which can handle hierarchical + * structures and advanced rendering tasks. + * + * @param layerRenderer the {@link AzLayerRenderer} instance used to decorate and handle additional render layers + * within the model rendering process + * @return a new instance of {@link AzModelRenderer} configured with the provided layer renderer + */ + protected abstract AzModelRenderer createModelRenderer(AzLayerRenderer layerRenderer); + + /** + * Creates an instance of {@link AzLayerRenderer} using the provided {@link AzRendererConfig}. This method is + * responsible for generating a layer renderer configured with the provided rendering configuration, allowing for + * the management and application of multiple render layers. + * + * @param config The configuration object of type {@link AzRendererConfig} that provides the necessary settings and + * parameters for the layer renderer. + * @return A newly created {@link AzLayerRenderer} instance configured based on the specified + * {@link AzRendererConfig}. + */ + protected abstract AzLayerRenderer createLayerRenderer(AzRendererConfig config); + + /** + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
    + * This should only be called immediately prior to rendering, and only + * + * @see AnimatableTexture#setAndUpdate + */ + protected abstract void updateAnimatedTextureFrame(T animatable); + + /** + * Initial access point for rendering. It all begins here.
    + * All AzureLib renderers should immediately defer their respective default {@code render} calls to this, for + * consistent handling + */ + public void render( + PoseStack poseStack, + AzBakedModel model, + T animatable, + MultiBufferSource bufferSource, + @Nullable RenderType renderType, + @Nullable VertexConsumer buffer, + float yaw, + float partialTick, + int packedLight + ) { + context.populate(animatable, model, bufferSource, packedLight, partialTick, poseStack, renderType, buffer); + + poseStack.pushPose(); + + preRender(context, false); + + // TODO: + // if (firePreRenderEvent(poseStack, model, bufferSource, partialTick, packedLight)) { + layerRenderer.preApplyRenderLayers(context); + modelRenderer.render(context, false); + layerRenderer.applyRenderLayers(context); + postRender(context, false); + // TODO: + // firePostRenderEvent(poseStack, model, bufferSource, partialTick, packedLight); + // } + + poseStack.popPose(); + + renderFinal(context); + doPostRenderCleanup(); + } + + /** + * Re-renders the provided {@link AzBakedModel}.
    + * Usually you'd use this for rendering alternate {@link RenderType} layers or for sub-model rendering whilst inside + * a {@link AzRenderLayer} or similar + */ + public void reRender(AzRendererPipelineContext context) { + var poseStack = context.poseStack(); + + poseStack.pushPose(); + + preRender(context, true); + modelRenderer.render(context, true); + postRender(context, true); + + poseStack.popPose(); + } + + /** + * Call after all other rendering work has taken place, including reverting the {@link PoseStack}'s state. This + * method is not called in {@link AzRendererPipeline#reRender re-render} + */ + protected void renderFinal(AzRendererPipelineContext context) {} + + /** + * Called after all render operations are completed and the render pass is considered functionally complete. + *

    + * Use this method to clean up any leftover persistent objects stored during rendering or any other post-render + * maintenance tasks as required + */ + protected void doPostRenderCleanup() {} + + /** + * Scales the {@link PoseStack} in preparation for rendering the model, excluding when re-rendering the model as + * part of a {@link AzRenderLayer} or external render call.
    + * Override and call super with modified scale values as needed to further modify the scale of the model (E.G. child + * entities) + */ + protected void scaleModelForRender( + AzRendererPipelineContext context, + float widthScale, + float heightScale, + boolean isReRender + ) { + if (!isReRender && (widthScale != 1 || heightScale != 1)) { + var poseStack = context.poseStack(); + poseStack.scale(widthScale, heightScale, widthScale); + } + } + + /** + * Provides access to the rendering configuration associated with this rendering pipeline. + * + * @return An instance of {@link AzRendererConfig} that contains the configuration details for this rendering + * pipeline, including animator, model location, texture location, render layers, and scaling parameters. + */ + public AzRendererConfig config() { + return config; + } + + /** + * Provides access to the rendering pipeline context associated with this rendering pipeline. + * + * @return An instance of {@link AzRendererPipelineContext} representing the context for the current rendering + * pipeline, containing relevant rendering data and configurations for processing animations and models. + */ + public AzRendererPipelineContext context() { + return context; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipelineContext.java new file mode 100644 index 000000000..fe4d8a3d8 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/AzRendererPipelineContext.java @@ -0,0 +1,192 @@ +package mod.azure.azurelib.core2.render; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +import mod.azure.azurelib.core.object.Color; +import mod.azure.azurelib.core2.model.AzBakedModel; + +/** + * An abstract base class representing the rendering context for a custom rendering pipeline. This class provides + * generic rendering properties and behavior that can be extended to customize rendering for different types of + * animatable objects. + * + * @param the type of the animatable object being rendered + */ +public abstract class AzRendererPipelineContext { + + private final AzRendererPipeline rendererPipeline; + + private T animatable; + + private AzBakedModel bakedModel; + + private MultiBufferSource multiBufferSource; + + private int packedLight; + + private int packedOverlay; + + private float partialTick; + + private PoseStack poseStack; + + private int renderColor; + + private @Nullable RenderType renderType; + + private VertexConsumer vertexConsumer; + + protected AzRendererPipelineContext(AzRendererPipeline rendererPipeline) { + this.rendererPipeline = rendererPipeline; + } + + /** + * Populates the rendering context with all necessary parameters required to render a specific animatable object. + * This method initializes the rendering pipeline with data such as the model, buffer source, lighting, and other + * associated properties for rendering the specified animatable object. + * + * @param animatable The animatable object that is being rendered. + * @param bakedModel The pre-baked 3D model associated with the animatable object. + * @param multiBufferSource The multibuffer source used for rendering vertex data. + * @param packedLight The packed light value for controlling light effects during rendering. + * @param partialTick The partial tick value for interpolating animations or movements. + * @param poseStack The pose stack used to manage rendering transformations. + * @param renderType The render type that determines how the object will be rendered, e.g., opaque, + * translucent, etc. + * @param vertexConsumer The vertex consumer used for buffering vertex attributes during rendering. + */ + public void populate( + T animatable, + AzBakedModel bakedModel, + MultiBufferSource multiBufferSource, + int packedLight, + float partialTick, + PoseStack poseStack, + RenderType renderType, + VertexConsumer vertexConsumer + ) { + this.animatable = animatable; + this.bakedModel = bakedModel; + this.multiBufferSource = multiBufferSource; + this.packedLight = packedLight; + this.packedOverlay = getPackedOverlay(animatable, 0, partialTick); + this.partialTick = partialTick; + this.poseStack = poseStack; + this.renderType = renderType; + this.vertexConsumer = vertexConsumer; + this.renderColor = getRenderColor(animatable, partialTick, packedLight).argbInt(); + + if (renderType == null) { + var textureLocation = rendererPipeline.config().textureLocation(animatable); + this.renderType = getDefaultRenderType(animatable, textureLocation, multiBufferSource, partialTick); + } + + Objects.requireNonNull(this.renderType); + + if (vertexConsumer == null) { + this.vertexConsumer = multiBufferSource.getBuffer(this.renderType); + } + } + + /** + * Gets the {@link RenderType} to render the given animatable with.
    + * Uses the {@link RenderType#entityCutoutNoCull} {@code RenderType} by default.
    + * Override this to change the way a model will render (such as translucent models, etc) + */ + public abstract @NotNull RenderType getDefaultRenderType( + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ); + + /** + * Gets a tint-applying color to render the given animatable with.
    + * Returns {@link Color#WHITE} by default + */ + protected Color getRenderColor(T animatable, float partialTick, int packedLight) { + return Color.WHITE; + } + + /** + * Gets a packed overlay coordinate pair for rendering.
    + * Mostly just used for the red tint when an entity is hurt, but can be used for other things like the + * {@link net.minecraft.world.entity.monster.Creeper} white tint when exploding. + */ + protected int getPackedOverlay(T animatable, float u, float partialTick) { + return OverlayTexture.NO_OVERLAY; + } + + public AzRendererPipeline rendererPipeline() { + return rendererPipeline; + } + + public T animatable() { + return animatable; + } + + public AzBakedModel bakedModel() { + return bakedModel; + } + + public MultiBufferSource multiBufferSource() { + return multiBufferSource; + } + + public int packedLight() { + return packedLight; + } + + public void setPackedLight(int packedLight) { + this.packedLight = packedLight; + } + + public int packedOverlay() { + return packedOverlay; + } + + public void setPackedOverlay(int packedOverlay) { + this.packedOverlay = packedOverlay; + } + + public float partialTick() { + return partialTick; + } + + public PoseStack poseStack() { + return poseStack; + } + + public int renderColor() { + return renderColor; + } + + public void setRenderColor(int renderColor) { + this.renderColor = renderColor; + } + + public @Nullable RenderType renderType() { + return renderType; + } + + public void setRenderType(@Nullable RenderType renderType) { + this.renderType = renderType; + } + + public VertexConsumer vertexConsumer() { + return vertexConsumer; + } + + public void setVertexConsumer(VertexConsumer vertexConsumer) { + this.vertexConsumer = vertexConsumer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModel.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModel.java new file mode 100644 index 000000000..7aa7b60f6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModel.java @@ -0,0 +1,74 @@ +package mod.azure.azurelib.core2.render.armor; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.geom.ModelLayers; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.world.entity.LivingEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class AzArmorModel extends HumanoidModel { + + private final AzArmorRendererPipeline rendererPipeline; + + public AzArmorModel(AzArmorRendererPipeline rendererPipeline) { + super(Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR)); + this.rendererPipeline = rendererPipeline; + } + + @Override + public void renderToBuffer( + @NotNull PoseStack poseStack, + @Nullable VertexConsumer buffer, + int packedLight, + int packedOverlay, + int var5 + ) { + var mc = Minecraft.getInstance(); + var context = rendererPipeline.context(); + var currentEntity = context.currentEntity(); + var currentStack = context.currentStack(); + MultiBufferSource bufferSource = Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); + + var shouldOutline = Minecraft.getInstance().levelRenderer.shouldShowEntityOutlines() && mc + .shouldEntityAppearGlowing( + currentEntity + ); + + if (shouldOutline) { + bufferSource = Minecraft.getInstance().levelRenderer.renderBuffers.outlineBufferSource(); + } + + var config = rendererPipeline.config(); + var animatable = context.animatable(); + var partialTick = mc.getTimer().getGameTimeDeltaTicks(); + var textureLocation = config.textureLocation(animatable); + var renderType = context.getDefaultRenderType(animatable, textureLocation, bufferSource, partialTick); + buffer = ItemRenderer.getArmorFoilBuffer(bufferSource, renderType, currentStack.hasFoil()); + + var model = rendererPipeline.renderer().provider().provideBakedModel(animatable); + rendererPipeline.render(poseStack, model, animatable, bufferSource, null, buffer, 0, partialTick, packedLight); + } + + /** + * Applies settings and transformations pre-render based on the default model + */ + public void applyBaseModel(HumanoidModel baseModel) { + this.young = baseModel.young; + this.crouching = baseModel.crouching; + this.riding = baseModel.riding; + this.rightArmPose = baseModel.rightArmPose; + this.leftArmPose = baseModel.leftArmPose; + } + + @Override + public void setAllVisible(boolean pVisible) { + super.setAllVisible(pVisible); + var boneContext = rendererPipeline.context().boneContext(); + boneContext.setAllVisible(pVisible); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModelRenderer.java new file mode 100644 index 000000000..0fa5a481d --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorModelRenderer.java @@ -0,0 +1,80 @@ +package mod.azure.azurelib.core2.render.armor; + +import net.minecraft.world.item.ItemStack; +import org.joml.Matrix4f; +import org.joml.Vector3f; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzPhasedRenderer; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +public class AzArmorModelRenderer extends AzModelRenderer { + + private final AzArmorRendererPipeline armorRendererPipeline; + + public AzArmorModelRenderer( + AzArmorRendererPipeline armorRendererPipeline, + AzLayerRenderer layerRenderer + ) { + super(armorRendererPipeline, layerRenderer); + this.armorRendererPipeline = armorRendererPipeline; + } + + /** + * The actual render method that subtype renderers should override to handle their specific rendering tasks.
    + * {@link AzPhasedRenderer#preRender} has already been called by this stage, and {@link AzPhasedRenderer#postRender} + * will be called directly after + */ + @Override + public void render(AzRendererPipelineContext context, boolean isReRender) { + var poseStack = context.poseStack(); + poseStack.pushPose(); + poseStack.translate(0, 24 / 16f, 0); + poseStack.scale(-1, -1, 1); + + if (!isReRender) { + var animatable = context.animatable(); + var animator = armorRendererPipeline.renderer().animator(); + + if (animator != null) { + animator.animate(animatable, context.partialTick()); + } + } + + armorRendererPipeline.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); + + super.render(context, isReRender); + poseStack.popPose(); + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + @Override + public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + var poseStack = context.poseStack(); + // TODO: This is dangerous. + var ctx = armorRendererPipeline.context(); + + if (bone.isTrackingMatrices()) { + Matrix4f poseState = new Matrix4f(poseStack.last().pose()); + Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices( + poseState, + armorRendererPipeline.entityRenderTranslations + ); + + bone.setModelSpaceMatrix( + RenderUtils.invertAndMultiplyMatrices(poseState, armorRendererPipeline.modelRenderTranslations) + ); + bone.setLocalSpaceMatrix(RenderUtils.translateMatrix(localMatrix, new Vector3f())); + bone.setWorldSpaceMatrix( + RenderUtils.translateMatrix(new Matrix4f(localMatrix), ctx.currentEntity().position().toVector3f()) + ); + } + + super.renderRecursively(context, bone, isReRender); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRenderer.java new file mode 100644 index 000000000..cc84fc304 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRenderer.java @@ -0,0 +1,83 @@ +package mod.azure.azurelib.core2.render.armor; + +import mod.azure.azurelib.core2.render.entity.AzEntityRendererConfig; +import mod.azure.azurelib.core2.render.entity.AzEntityRendererPipeline; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.render.AzProvider; +import mod.azure.azurelib.core2.render.AzRendererConfig; + +public class AzArmorRenderer { + + private final AzProvider provider; + + private final AzArmorRendererPipeline rendererPipeline; + + @Nullable + private AzItemAnimator reusedAzItemAnimator; + + public AzArmorRenderer(AzRendererConfig config) { + this.provider = new AzProvider<>(config::createAnimator, config::modelLocation); + this.rendererPipeline = createPipeline(config); + } + + protected AzArmorRendererPipeline createPipeline(AzRendererConfig config) { + return new AzArmorRendererPipeline(config, this); + } + + /** + * Prepare the renderer for the current render cycle.
    + * Must be called prior to render as the default HumanoidModel doesn't give render context.
    + * Params have been left nullable so that the renderer can be called for model/texture purposes safely. If you do + * grab the renderer using null parameters, you should not use it for actual rendering. + * + * @param entity The entity being rendered with the armor on + * @param stack The ItemStack being rendered + * @param slot The slot being rendered + * @param baseModel The default (vanilla) model that would have been rendered if this model hadn't replaced it + */ + public void prepForRender( + @Nullable Entity entity, + ItemStack stack, + @Nullable EquipmentSlot slot, + @Nullable HumanoidModel baseModel + ) { + if (entity == null || slot == null || baseModel == null) { + return; + } + + rendererPipeline.context().prepare(entity, stack, slot, baseModel); + + var model = provider.provideBakedModel(stack); + prepareAnimator(stack, model); + } + + private void prepareAnimator(ItemStack stack, AzBakedModel model) { + var cachedEntityAnimator = (AzItemAnimator) provider.provideAnimator(stack); + + if (cachedEntityAnimator != null && model != null) { + cachedEntityAnimator.setActiveModel(model); + } + + // Point the renderer's current animator reference to the cached entity animator before rendering. + reusedAzItemAnimator = cachedEntityAnimator; + } + + public @Nullable AzItemAnimator animator() { + return reusedAzItemAnimator; + } + + public AzProvider provider() { + return provider; + } + + public AzArmorRendererPipeline rendererPipeline() { + return rendererPipeline; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererConfig.java new file mode 100644 index 000000000..19f3d91d9 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererConfig.java @@ -0,0 +1,93 @@ +package mod.azure.azurelib.core2.render.armor; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.armor.bone.AzArmorBoneProvider; +import mod.azure.azurelib.core2.render.armor.bone.AzDefaultArmorBoneProvider; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +public class AzArmorRendererConfig extends AzRendererConfig { + + private final AzArmorBoneProvider boneProvider; + + private AzArmorRendererConfig( + Supplier> animatorProvider, + AzArmorBoneProvider boneProvider, + Function modelLocationProvider, + List> renderLayers, + Function textureLocationProvider, + float scaleHeight, + float scaleWidth + ) { + super(animatorProvider, modelLocationProvider, renderLayers, textureLocationProvider, scaleHeight, scaleWidth); + this.boneProvider = boneProvider; + } + + public AzArmorBoneProvider boneProvider() { + return boneProvider; + } + + public static Builder builder( + ResourceLocation modelLocation, + ResourceLocation textureLocation + ) { + return new Builder($ -> modelLocation, $ -> textureLocation); + } + + public static Builder builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + return new Builder(modelLocationProvider, textureLocationProvider); + } + + public static class Builder extends AzRendererConfig.Builder { + + private AzArmorBoneProvider boneProvider; + + protected Builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + super(modelLocationProvider, textureLocationProvider); + this.boneProvider = new AzDefaultArmorBoneProvider(); + } + + @Override + public Builder addRenderLayer(AzRenderLayer renderLayer) { + return (Builder) super.addRenderLayer(renderLayer); + } + + @Override + public Builder setAnimatorProvider(Supplier<@Nullable AzAnimator> animatorProvider) { + return (Builder) super.setAnimatorProvider(animatorProvider); + } + + public Builder setBoneProvider(AzArmorBoneProvider boneProvider) { + this.boneProvider = boneProvider; + return this; + } + + public AzArmorRendererConfig build() { + var baseConfig = super.build(); + + return new AzArmorRendererConfig( + baseConfig::createAnimator, + boneProvider, + baseConfig::modelLocation, + baseConfig.renderLayers(), + baseConfig::textureLocation, + baseConfig.scaleHeight(), + baseConfig.scaleWidth() + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipeline.java new file mode 100644 index 000000000..6d7148e5e --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipeline.java @@ -0,0 +1,131 @@ +package mod.azure.azurelib.core2.render.armor; + +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; +import org.joml.Matrix4f; + +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +public class AzArmorRendererPipeline extends AzRendererPipeline { + + private final AzArmorModel armorModel; + + private final AzArmorRenderer armorRenderer; + + protected Matrix4f entityRenderTranslations = new Matrix4f(); + + protected Matrix4f modelRenderTranslations = new Matrix4f(); + + public AzArmorRendererPipeline(AzRendererConfig config, AzArmorRenderer armorRenderer) { + super(config); + this.armorModel = new AzArmorModel<>(this); + this.armorRenderer = armorRenderer; + } + + @Override + protected AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { + return new AzArmorRendererPipelineContext(rendererPipeline); + } + + @Override + protected AzModelRenderer createModelRenderer(AzLayerRenderer layerRenderer) { + return new AzArmorModelRenderer(this, layerRenderer); + } + + @Override + protected AzLayerRenderer createLayerRenderer(AzRendererConfig config) { + return new AzLayerRenderer<>(config::renderLayers); + } + + @Override + protected void updateAnimatedTextureFrame(ItemStack animatable) { + var currentEntity = context().currentEntity(); + + if (currentEntity != null) { + var textureLocation = config().textureLocation(animatable); + var frameTick = currentEntity.getId() + currentEntity.tickCount; + + AnimatableTexture.setAndUpdate(textureLocation, frameTick); + } + } + + @Override + public void preRender(AzRendererPipelineContext context, boolean isReRender) { + var armorContext = (AzArmorRendererPipelineContext) context; + var baseModel = armorContext.baseModel(); + var boneContext = armorContext.boneContext(); + var config = config(); + var currentSlot = armorContext.currentSlot(); + var scaleWidth = config.scaleWidth(); + var scaleHeight = config.scaleHeight(); + + var animatable = armorContext.animatable(); + var model = armorRenderer.provider().provideBakedModel(animatable); + var poseStack = armorContext.poseStack(); + + this.entityRenderTranslations = new Matrix4f(poseStack.last().pose()); + + armorModel.applyBaseModel(baseModel); + boneContext.grabRelevantBones(model, config.boneProvider()); + boneContext.applyBaseTransformations(baseModel); + scaleModelForBaby(armorContext, isReRender); + scaleModelForRender(context, scaleWidth, scaleHeight, isReRender); + + boneContext.applyBoneVisibilityBySlot(currentSlot); + } + + @Override + public void postRender(AzRendererPipelineContext context, boolean isReRender) {} + + /** + * Apply custom scaling to account for {@link net.minecraft.client.model.AgeableListModel AgeableListModel} baby + * models + */ + public void scaleModelForBaby(AzArmorRendererPipelineContext context, boolean isReRender) { + if (!armorModel.young || isReRender) { + return; + } + + var baseModel = context.baseModel(); + var currentSlot = context.currentSlot(); + var poseStack = context.poseStack(); + + if (currentSlot == EquipmentSlot.HEAD) { + if (baseModel.scaleHead) { + float headScale = 1.5f / baseModel.babyHeadScale; + + poseStack.scale(headScale, headScale, headScale); + } + + poseStack.translate(0, baseModel.babyYHeadOffset / 16f, baseModel.babyZHeadOffset / 16f); + } else { + float bodyScale = 1 / baseModel.babyBodyScale; + + poseStack.scale(bodyScale, bodyScale, bodyScale); + poseStack.translate(0, baseModel.bodyYOffset / 16f, 0); + } + } + + public AzArmorModel armorModel() { + return armorModel; + } + + @Override + public AzArmorRendererConfig config() { + return (AzArmorRendererConfig) super.config(); + } + + @Override + public AzArmorRendererPipelineContext context() { + return (AzArmorRendererPipelineContext) super.context(); + } + + public AzArmorRenderer renderer() { + return armorRenderer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipelineContext.java new file mode 100644 index 000000000..1fd24e752 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererPipelineContext.java @@ -0,0 +1,96 @@ +package mod.azure.azurelib.core2.render.armor; + +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.DyedItemColor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core.object.Color; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.armor.bone.AzArmorBoneContext; + +public class AzArmorRendererPipelineContext extends AzRendererPipelineContext { + + private final AzArmorBoneContext boneContext; + + private HumanoidModel baseModel; + + private Entity currentEntity; + + private EquipmentSlot currentSlot; + + private ItemStack currentStack; + + public AzArmorRendererPipelineContext(AzRendererPipeline rendererPipeline) { + super(rendererPipeline); + this.baseModel = null; + this.boneContext = new AzArmorBoneContext(); + this.currentEntity = null; + this.currentSlot = null; + this.currentStack = null; + } + + @Override + public @NotNull RenderType getDefaultRenderType( + ItemStack animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ) { + return RenderType.armorCutoutNoCull(texture); + } + + public void prepare( + @Nullable Entity entity, + ItemStack stack, + @Nullable EquipmentSlot slot, + @Nullable HumanoidModel baseModel + ) { + this.baseModel = baseModel; + this.currentEntity = entity; + this.currentStack = stack; + this.currentSlot = slot; + } + + /** + * Gets a tint-applying color to render the given animatable with + *

    + * Returns {@link Color#WHITE} by default + */ + @Override + public Color getRenderColor(ItemStack animatable, float partialTick, int packedLight) { + return this.currentStack.is(ItemTags.DYEABLE) + ? Color.ofOpaque( + DyedItemColor.getOrDefault(this.currentStack, -6265536) + ) + : Color.WHITE; + } + + public HumanoidModel baseModel() { + return baseModel; + } + + public AzArmorBoneContext boneContext() { + return boneContext; + } + + public Entity currentEntity() { + return currentEntity; + } + + public EquipmentSlot currentSlot() { + return currentSlot; + } + + public ItemStack currentStack() { + return currentStack; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererRegistry.java new file mode 100644 index 000000000..cf23ea097 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/AzArmorRendererRegistry.java @@ -0,0 +1,34 @@ +package mod.azure.azurelib.core2.render.armor; + +import net.minecraft.world.item.Item; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +public class AzArmorRendererRegistry { + + private static final Map ITEM_TO_RENDERER = new HashMap<>(); + + private static final Map> ITEM_TO_RENDERER_SUPPLIER = new HashMap<>(); + + public static void register(Item item, Supplier armorRendererSupplier) { + ITEM_TO_RENDERER_SUPPLIER.put(item, armorRendererSupplier); + } + + public static void register(Supplier armorRendererSupplier, Item item, Item... items) { + register(item, armorRendererSupplier); + + for (var otherItem : items) { + register(otherItem, armorRendererSupplier); + } + } + + public static @Nullable AzArmorRenderer getOrNull(Item item) { + return ITEM_TO_RENDERER.computeIfAbsent(item, ($) -> { + var rendererSupplier = ITEM_TO_RENDERER_SUPPLIER.get(item); + return rendererSupplier == null ? null : rendererSupplier.get(); + }); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneContext.java new file mode 100644 index 000000000..9dd0790e8 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneContext.java @@ -0,0 +1,198 @@ +package mod.azure.azurelib.core2.render.armor.bone; + +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.world.entity.EquipmentSlot; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; + +public class AzArmorBoneContext { + + private AzBakedModel lastModel; + + private AzBone head; + + private AzBone body; + + private AzBone rightArm; + + private AzBone leftArm; + + private AzBone rightLeg; + + private AzBone leftLeg; + + private AzBone rightBoot; + + private AzBone leftBoot; + + public AzArmorBoneContext() { + this.head = null; + this.body = null; + this.rightArm = null; + this.leftArm = null; + this.rightLeg = null; + this.leftLeg = null; + this.rightBoot = null; + this.leftBoot = null; + } + + public void setAllVisible(boolean pVisible) { + setBoneVisible(this.head, pVisible); + setBoneVisible(this.body, pVisible); + setBoneVisible(this.rightArm, pVisible); + setBoneVisible(this.leftArm, pVisible); + setBoneVisible(this.rightLeg, pVisible); + setBoneVisible(this.leftLeg, pVisible); + setBoneVisible(this.rightBoot, pVisible); + setBoneVisible(this.leftBoot, pVisible); + } + + /** + * Gets and caches the relevant armor model bones for this baked model if it hasn't been done already + */ + public void grabRelevantBones(AzBakedModel model, AzArmorBoneProvider boneProvider) { + if (this.lastModel == model) { + return; + } + + this.lastModel = model; + this.head = boneProvider.getHeadBone(model); + this.body = boneProvider.getBodyBone(model); + this.rightArm = boneProvider.getRightArmBone(model); + this.leftArm = boneProvider.getLeftArmBone(model); + this.rightLeg = boneProvider.getRightLegBone(model); + this.leftLeg = boneProvider.getLeftLegBone(model); + this.rightBoot = boneProvider.getRightBootBone(model); + this.leftBoot = boneProvider.getLeftBootBone(model); + } + + /** + * Transform the currently rendering {@link AzBakedModel} to match the positions and rotations of the base model + */ + public void applyBaseTransformations(HumanoidModel baseModel) { + if (this.head != null) { + ModelPart headPart = baseModel.head; + + RenderUtils.matchModelPartRot(headPart, this.head); + this.head.updatePosition(headPart.x, -headPart.y, headPart.z); + } + + if (this.body != null) { + ModelPart bodyPart = baseModel.body; + + RenderUtils.matchModelPartRot(bodyPart, this.body); + this.body.updatePosition(bodyPart.x, -bodyPart.y, bodyPart.z); + } + + if (this.rightArm != null) { + ModelPart rightArmPart = baseModel.rightArm; + + RenderUtils.matchModelPartRot(rightArmPart, this.rightArm); + this.rightArm.updatePosition(rightArmPart.x + 5, 2 - rightArmPart.y, rightArmPart.z); + } + + if (this.leftArm != null) { + ModelPart leftArmPart = baseModel.leftArm; + + RenderUtils.matchModelPartRot(leftArmPart, this.leftArm); + this.leftArm.updatePosition(leftArmPart.x - 5f, 2f - leftArmPart.y, leftArmPart.z); + } + + if (this.rightLeg != null) { + ModelPart rightLegPart = baseModel.rightLeg; + + RenderUtils.matchModelPartRot(rightLegPart, this.rightLeg); + this.rightLeg.updatePosition(rightLegPart.x + 2, 12 - rightLegPart.y, rightLegPart.z); + + if (this.rightBoot != null) { + RenderUtils.matchModelPartRot(rightLegPart, this.rightBoot); + this.rightBoot.updatePosition(rightLegPart.x + 2, 12 - rightLegPart.y, rightLegPart.z); + } + } + + if (this.leftLeg != null) { + ModelPart leftLegPart = baseModel.leftLeg; + + RenderUtils.matchModelPartRot(leftLegPart, this.leftLeg); + this.leftLeg.updatePosition(leftLegPart.x - 2, 12 - leftLegPart.y, leftLegPart.z); + + if (this.leftBoot != null) { + RenderUtils.matchModelPartRot(leftLegPart, this.leftBoot); + this.leftBoot.updatePosition(leftLegPart.x - 2, 12 - leftLegPart.y, leftLegPart.z); + } + } + } + + /** + * Resets the bone visibility for the model based on the current {@link ModelPart} and {@link EquipmentSlot}, and + * then sets the bones relevant to the current part as visible for rendering.
    + *
    + * If you are rendering a geo entity with armor, you should probably be calling this prior to rendering + */ + public void applyBoneVisibilityByPart(EquipmentSlot currentSlot, ModelPart currentPart, HumanoidModel model) { + setAllVisible(false); + + currentPart.visible = true; + AzBone bone = null; + + if (currentPart == model.hat || currentPart == model.head) { + bone = this.head; + } else if (currentPart == model.body) { + bone = this.body; + } else if (currentPart == model.leftArm) { + bone = this.leftArm; + } else if (currentPart == model.rightArm) { + bone = this.rightArm; + } else if (currentPart == model.leftLeg) { + bone = currentSlot == EquipmentSlot.FEET ? this.leftBoot : this.leftLeg; + } else if (currentPart == model.rightLeg) { + bone = currentSlot == EquipmentSlot.FEET ? this.rightBoot : this.rightLeg; + } + + if (bone != null) { + bone.setHidden(false); + } + } + + /** + * Resets the bone visibility for the model based on the currently rendering slot, and then sets bones relevant to + * the current slot as visible for rendering.
    + *
    + * This is only called by default for non-geo entities (I.E. players or vanilla mobs) + */ + public void applyBoneVisibilityBySlot(EquipmentSlot currentSlot) { + setAllVisible(false); + + switch (currentSlot) { + case HEAD -> setBoneVisible(this.head, true); + case CHEST -> { + setBoneVisible(this.body, true); + setBoneVisible(this.rightArm, true); + setBoneVisible(this.leftArm, true); + } + case LEGS -> { + setBoneVisible(this.rightLeg, true); + setBoneVisible(this.leftLeg, true); + } + case FEET -> { + setBoneVisible(this.rightBoot, true); + setBoneVisible(this.leftBoot, true); + } + case MAINHAND, OFFHAND -> { /* NO-OP */ } + } + } + + /** + * Sets a bone as visible or hidden, with nullability + */ + protected void setBoneVisible(@Nullable AzBone bone, boolean visible) { + if (bone == null) + return; + + bone.setHidden(!visible); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneProvider.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneProvider.java new file mode 100644 index 000000000..4a65ad61a --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzArmorBoneProvider.java @@ -0,0 +1,97 @@ +package mod.azure.azurelib.core2.render.armor.bone; + +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; + +public interface AzArmorBoneProvider { + + String BONE_ARMOR_BODY_NAME = "armorBody"; + + String BONE_ARMOR_HEAD_NAME = "armorHead"; + + String BONE_ARMOR_LEFT_ARM_NAME = "armorLeftArm"; + + String BONE_ARMOR_RIGHT_ARM_NAME = "armorRightArm"; + + String BONE_ARMOR_LEFT_BOOT_NAME = "armorLeftBoot"; + + String BONE_ARMOR_RIGHT_BOOT_NAME = "armorRightBoot"; + + String BONE_ARMOR_LEFT_LEG_NAME = "armorLeftLeg"; + + String BONE_ARMOR_RIGHT_LEG_NAME = "armorRightLeg"; + + /** + * Returns the 'head' GeoBone from this model.
    + * Override if your geo model has different bone names for these bones + * + * @return The bone for the head model piece, or null if not using it + */ + @Nullable + AzBone getHeadBone(AzBakedModel model); + + /** + * Returns the 'body' GeoBone from this model.
    + * Override if your geo model has different bone names for these bones + * + * @return The bone for the body model piece, or null if not using it + */ + @Nullable + AzBone getBodyBone(AzBakedModel model); + + /** + * Returns the 'right arm' GeoBone from this model.
    + * Override if your geo model has different bone names for these bones + * + * @return The bone for the right arm model piece, or null if not using it + */ + @Nullable + AzBone getRightArmBone(AzBakedModel model); + + /** + * Returns the 'left arm' GeoBone from this model.
    + * Override if your geo model has different bone names for these bones + * + * @return The bone for the left arm model piece, or null if not using it + */ + @Nullable + AzBone getLeftArmBone(AzBakedModel model); + + /** + * Returns the 'right leg' GeoBone from this model.
    + * Override if your geo model has different bone names for these bones + * + * @return The bone for the right leg model piece, or null if not using it + */ + @Nullable + AzBone getRightLegBone(AzBakedModel model); + + /** + * Returns the 'left leg' GeoBone from this model.
    + * Override if your geo model has different bone names for these bones + * + * @return The bone for the left leg model piece, or null if not using it + */ + @Nullable + AzBone getLeftLegBone(AzBakedModel model); + + /** + * Returns the 'right boot' GeoBone from this model.
    + * Override if your geo model has different bone names for these bones + * + * @return The bone for the right boot model piece, or null if not using it + */ + @Nullable + AzBone getRightBootBone(AzBakedModel model); + + /** + * Returns the 'left boot' GeoBone from this model.
    + * Override if your geo model has different bone names for these bones + * + * @return The bone for the left boot model piece, or null if not using it + */ + @Nullable + AzBone getLeftBootBone(AzBakedModel model); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzDefaultArmorBoneProvider.java b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzDefaultArmorBoneProvider.java new file mode 100644 index 000000000..43b416c19 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/armor/bone/AzDefaultArmorBoneProvider.java @@ -0,0 +1,49 @@ +package mod.azure.azurelib.core2.render.armor.bone; + +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; + +public class AzDefaultArmorBoneProvider implements AzArmorBoneProvider { + + @Nullable + public AzBone getHeadBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_HEAD_NAME); + } + + @Nullable + public AzBone getBodyBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_BODY_NAME); + } + + @Nullable + public AzBone getRightArmBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_RIGHT_ARM_NAME); + } + + @Nullable + public AzBone getLeftArmBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_LEFT_ARM_NAME); + } + + @Nullable + public AzBone getRightLegBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_RIGHT_LEG_NAME); + } + + @Nullable + public AzBone getLeftLegBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_LEFT_LEG_NAME); + } + + @Nullable + public AzBone getRightBootBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_RIGHT_BOOT_NAME); + } + + @Nullable + public AzBone getLeftBootBone(AzBakedModel model) { + return model.getBoneOrNull(BONE_ARMOR_LEFT_BOOT_NAME); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityModelRenderer.java new file mode 100644 index 000000000..4303e5071 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityModelRenderer.java @@ -0,0 +1,156 @@ +package mod.azure.azurelib.core2.render.block; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.DirectionalBlock; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; +import org.joml.Vector3f; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * The AzBlockEntityModelRenderer is a specialized model renderer class for rendering block entities in a 3D space. It + * extends the AzModelRenderer class and provides functionality specific to handling and rendering block entities based + * on their corresponding properties and transformations. + * + * @param The type of BlockEntity that this renderer is responsible for + */ +public class AzBlockEntityModelRenderer extends AzModelRenderer { + + private final AzBlockEntityRendererPipeline blockEntityRendererPipeline; + + public AzBlockEntityModelRenderer( + AzBlockEntityRendererPipeline blockEntityRendererPipeline, + AzLayerRenderer layerRenderer + ) { + super(blockEntityRendererPipeline, layerRenderer); + this.blockEntityRendererPipeline = blockEntityRendererPipeline; + } + + /** + * The actual render method that subtype renderers should override to handle their specific rendering tasks.
    + * {@link AzBlockEntityRendererPipeline#preRender} has already been called by this stage, and + * {@link AzBlockEntityRendererPipeline#postRender} will be called directly after + */ + @Override + public void render(AzRendererPipelineContext context, boolean isReRender) { + var entity = context.animatable(); + var poseStack = context.poseStack(); + + if (!isReRender) { + rotateBlock(getFacing(entity), poseStack); + + poseStack.translate(0.5, 0, 0.5); + var animator = blockEntityRendererPipeline.getRenderer().getAnimator(); + + if (animator != null) { + animator.animate(entity, context.partialTick()); + } + } + + blockEntityRendererPipeline.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); + + var textureLocation = blockEntityRendererPipeline.config().textureLocation(entity); + RenderSystem.setShaderTexture(0, textureLocation); + super.render(context, isReRender); + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + @Override + public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + var buffer = context.vertexConsumer(); + var bufferSource = context.multiBufferSource(); + var entity = context.animatable(); + var poseStack = context.poseStack(); + var renderType = context.renderType(); + + poseStack.pushPose(); + RenderUtils.translateMatrixToBone(poseStack, bone); + RenderUtils.translateToPivotPoint(poseStack, bone); + RenderUtils.rotateMatrixAroundBone(poseStack, bone); + RenderUtils.scaleMatrixForBone(poseStack, bone); + + if (bone.isTrackingMatrices()) { + Matrix4f poseState = new Matrix4f(poseStack.last().pose()); + Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices( + poseState, + blockEntityRendererPipeline.entityRenderTranslations + ); + + bone.setModelSpaceMatrix( + RenderUtils.invertAndMultiplyMatrices(poseState, blockEntityRendererPipeline.modelRenderTranslations) + ); + bone.setLocalSpaceMatrix( + RenderUtils.translateMatrix(localMatrix, Vec3.ZERO.toVector3f()) + ); + bone.setWorldSpaceMatrix( + RenderUtils.translateMatrix( + new Matrix4f(localMatrix), + new Vector3f( + entity.getBlockPos().getX(), + entity.getBlockPos().getY(), + entity.getBlockPos().getZ() + ) + ) + ); + } + + RenderUtils.translateAwayFromPivotPoint(poseStack, bone); + + if (!isReRender && buffer instanceof BufferBuilder builder && !builder.building) { + context.setVertexConsumer(bufferSource.getBuffer(renderType)); + } + + renderCubesOfBone(context, bone); + + if (!isReRender) { + layerRenderer.applyRenderLayersForBone(context, bone); + } + + renderChildBones(context, bone, isReRender); + + poseStack.popPose(); + } + + /** + * Attempt to extract a direction from the block so that the model can be oriented correctly + */ + protected Direction getFacing(T block) { + BlockState blockState = block.getBlockState(); + + if (blockState.hasProperty(HorizontalDirectionalBlock.FACING)) + return blockState.getValue(HorizontalDirectionalBlock.FACING); + + if (blockState.hasProperty(DirectionalBlock.FACING)) + return blockState.getValue(DirectionalBlock.FACING); + + return Direction.NORTH; + } + + /** + * Rotate the {@link PoseStack} based on the determined {@link Direction} the block is facing + */ + protected void rotateBlock(Direction facing, PoseStack poseStack) { + switch (facing) { + case SOUTH -> poseStack.mulPose(Axis.YP.rotationDegrees(180)); + case WEST -> poseStack.mulPose(Axis.YP.rotationDegrees(90)); + case NORTH -> poseStack.mulPose(Axis.YP.rotationDegrees(0)); + case EAST -> poseStack.mulPose(Axis.YP.rotationDegrees(270)); + case UP -> poseStack.mulPose(Axis.XP.rotationDegrees(90)); + case DOWN -> poseStack.mulPose(Axis.XN.rotationDegrees(90)); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java new file mode 100644 index 000000000..53fcd8ea6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRenderer.java @@ -0,0 +1,64 @@ +package mod.azure.azurelib.core2.render.block; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.animation.impl.AzBlockAnimator; +import mod.azure.azurelib.core2.render.AzProvider; + +/** + * The {@code AzBlockEntityRenderer} class is an abstract base class for rendering custom block entities. It leverages + * an animation and rendering pipeline mechanism to provide extended functionalities, such as dynamic animations and + * model customization. + * + * @param The specific type of {@link BlockEntity} that this renderer processes. + */ +public abstract class AzBlockEntityRenderer implements BlockEntityRenderer { + + private final AzProvider provider; + + private final AzBlockEntityRendererPipeline rendererPipeline; + + @Nullable + private AzBlockAnimator reusedAzBlockAnimator; + + protected AzBlockEntityRenderer(AzBlockEntityRendererConfig config) { + this.provider = new AzProvider<>(config::createAnimator, config::modelLocation); + this.rendererPipeline = createPipeline(config); + } + + protected AzBlockEntityRendererPipeline createPipeline(AzBlockEntityRendererConfig config) { + return new AzBlockEntityRendererPipeline<>(config, this); + } + + @Override + public void render( + @NotNull T entity, + float partialTick, + @NotNull PoseStack poseStack, + @NotNull MultiBufferSource source, + int packedLight, + int packedOverlay + ) { + var cachedEntityAnimator = (AzBlockAnimator) provider.provideAnimator(entity); + var model = provider.provideBakedModel(entity); + + if (cachedEntityAnimator != null && model != null) { + cachedEntityAnimator.setActiveModel(model); + } + + // Point the renderer's current animator reference to the cached entity animator before rendering. + reusedAzBlockAnimator = cachedEntityAnimator; + + // Execute the render pipeline. + rendererPipeline.render(poseStack, model, entity, source, null, null, 0, partialTick, packedLight); + } + + public AzBlockAnimator getAnimator() { + return reusedAzBlockAnimator; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererConfig.java new file mode 100644 index 000000000..befa9d554 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererConfig.java @@ -0,0 +1,81 @@ +package mod.azure.azurelib.core2.render.block; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +/** + * The {@code AzBlockEntityRendererConfig} class is a specialized configuration for rendering block entities. It extends + * the generic {@link AzRendererConfig} and provides additional methods to streamline the creation of configurations + * specifically for block entity renderers. + * + * @param The type of block entity this configuration is tailored for. + */ +public class AzBlockEntityRendererConfig extends AzRendererConfig { + + private AzBlockEntityRendererConfig( + Supplier> animatorProvider, + Function modelLocationProvider, + List> renderLayers, + Function textureLocationProvider, + float scaleHeight, + float scaleWidth + ) { + super(animatorProvider, modelLocationProvider, renderLayers, textureLocationProvider, scaleHeight, scaleWidth); + } + + public static Builder builder( + ResourceLocation modelLocation, + ResourceLocation textureLocation + ) { + return new Builder<>($ -> modelLocation, $ -> textureLocation); + } + + public static Builder builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + return new Builder<>(modelLocationProvider, textureLocationProvider); + } + + public static class Builder extends AzRendererConfig.Builder { + + protected Builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + super(modelLocationProvider, textureLocationProvider); + } + + @Override + public Builder addRenderLayer(AzRenderLayer renderLayer) { + return (Builder) super.addRenderLayer(renderLayer); + } + + @Override + public Builder setAnimatorProvider(Supplier<@Nullable AzAnimator> animatorProvider) { + return (Builder) super.setAnimatorProvider(animatorProvider); + } + + public AzBlockEntityRendererConfig build() { + var baseConfig = super.build(); + + return new AzBlockEntityRendererConfig<>( + baseConfig::createAnimator, + baseConfig::modelLocation, + baseConfig.renderLayers(), + baseConfig::textureLocation, + baseConfig.scaleHeight(), + baseConfig.scaleWidth() + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java new file mode 100644 index 000000000..7b816c4f5 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipeline.java @@ -0,0 +1,91 @@ +package mod.azure.azurelib.core2.render.block; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.joml.Matrix4f; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * AzBlockEntityRendererPipeline is a specific implementation of the {@link AzRendererPipeline} tailored for rendering + * block entities. It manages the rendering pipeline with customized configurations and rendering behavior for block + * entities, while integrating with the parent pipeline logic. + * + * @param The type of {@link BlockEntity} that this renderer pipeline is designed to render. + */ +public class AzBlockEntityRendererPipeline extends AzRendererPipeline { + + private final AzBlockEntityRenderer blockEntityRenderer; + + protected Matrix4f entityRenderTranslations = new Matrix4f(); + + protected Matrix4f modelRenderTranslations = new Matrix4f(); + + public AzBlockEntityRendererPipeline( + AzBlockEntityRendererConfig config, + AzBlockEntityRenderer blockEntityRenderer + ) { + super(config); + this.blockEntityRenderer = blockEntityRenderer; + } + + @Override + protected AzBlockEntityRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { + return new AzBlockEntityRendererPipelineContext<>(this); + } + + @Override + protected AzModelRenderer createModelRenderer(AzLayerRenderer layerRenderer) { + return new AzBlockEntityModelRenderer<>(this, layerRenderer); + } + + @Override + protected AzLayerRenderer createLayerRenderer(AzRendererConfig config) { + return new AzLayerRenderer<>(config::renderLayers); + } + + /** + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
    + * This should only be called immediately prior to rendering, and only + * + * @see AnimatableTexture#setAndUpdate(ResourceLocation, int) + */ + @Override + public void updateAnimatedTextureFrame(T entity) { + AnimatableTexture.setAndUpdate( + config.textureLocation(entity), + entity.getBlockPos().getX() + entity.getBlockPos().getY() + entity.getBlockPos().getZ() + + (int) RenderUtils.getCurrentTick() + ); + } + + /** + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
    + * {@link PoseStack} translations made here are kept until the end of the render process + */ + @Override + public void preRender(AzRendererPipelineContext context, boolean isReRender) { + var poseStack = context.poseStack(); + this.entityRenderTranslations.set(poseStack.last().pose()); + + var scaleWidth = config.scaleWidth(); + var scaleHeight = config.scaleHeight(); + scaleModelForRender(context, scaleWidth, scaleHeight, isReRender); + } + + @Override + public void postRender(AzRendererPipelineContext context, boolean isReRender) {} + + public AzBlockEntityRenderer getRenderer() { + return blockEntityRenderer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipelineContext.java new file mode 100644 index 000000000..b9f8b9aff --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/block/AzBlockEntityRendererPipelineContext.java @@ -0,0 +1,35 @@ +package mod.azure.azurelib.core2.render.block; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * Represents a specialized rendering context for handling {@link BlockEntity} rendering in a pipeline-based rendering + * framework. This class extends {@link AzRendererPipelineContext} to provide specific functionality tailored to block + * entities within the AzureLib rendering system. + * + * @param The type of {@link BlockEntity} to be rendered. + */ +public class AzBlockEntityRendererPipelineContext extends AzRendererPipelineContext { + + public AzBlockEntityRendererPipelineContext(AzRendererPipeline rendererPipeline) { + super(rendererPipeline); + } + + @Override + public @NotNull RenderType getDefaultRenderType( + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ) { + return RenderType.entityCutoutNoCull(texture); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLayerRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLayerRenderer.java new file mode 100644 index 000000000..ce00f95f2 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLayerRenderer.java @@ -0,0 +1,35 @@ +package mod.azure.azurelib.core2.render.entity; + +import net.minecraft.world.entity.Entity; + +import java.util.Collection; +import java.util.function.Supplier; + +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +/** + * A renderer class responsible for rendering additional entity layers for a particular animatable entity type. It + * extends functionality from {@link AzLayerRenderer} and enables conditional rendering based on entity states. + * + * @param The type of animatable entity this renderer is applied to. + */ +public class AzEntityLayerRenderer extends AzLayerRenderer { + + public AzEntityLayerRenderer(Supplier>> renderLayerSupplier) { + super(renderLayerSupplier); + } + + /** + * Render the various {@link AzRenderLayer RenderLayers} that have been registered to this renderer + */ + @Override + public void applyRenderLayers(AzRendererPipelineContext context) { + var animatable = context.animatable(); + + if (!animatable.isSpectator()) { + super.applyRenderLayers(context); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLeashRenderUtil.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLeashRenderUtil.java new file mode 100644 index 000000000..bd3fac328 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityLeashRenderUtil.java @@ -0,0 +1,161 @@ +package mod.azure.azurelib.core2.render.entity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; + +/** + * Utility class for rendering entity leash visuals within the Minecraft rendering engine. This class provides static + * methods to handle leash rendering logic, enabling flexible re-use and separation from the default rendering behavior. + *
    + * This utility replicates the leash rendering logic from {@link net.minecraft.client.renderer.entity.MobRenderer} to + * provide enhanced customization for entity rendering purposes. + */ +public class AzEntityLeashRenderUtil { + + /** + * Static rendering code for rendering a leash segment.
    + * It's a like-for-like from {@link net.minecraft.client.renderer.entity.MobRenderer#renderLeash} that had to be + * duplicated here for flexible usage + */ + public static void renderLeash( + AzEntityRenderer azEntityRenderer, + M mob, + float partialTick, + PoseStack poseStack, + MultiBufferSource bufferSource, + E leashHolder + ) { + double lerpBodyAngle = (Mth.lerp(partialTick, mob.yBodyRotO, mob.yBodyRot) * Mth.DEG_TO_RAD) + Mth.HALF_PI; + Vec3 leashOffset = mob.getLeashOffset(); + double xAngleOffset = Math.cos(lerpBodyAngle) * leashOffset.z + Math.sin(lerpBodyAngle) * leashOffset.x; + double zAngleOffset = Math.sin(lerpBodyAngle) * leashOffset.z - Math.cos(lerpBodyAngle) * leashOffset.x; + double lerpOriginX = Mth.lerp(partialTick, mob.xo, mob.getX()) + xAngleOffset; + double lerpOriginY = Mth.lerp(partialTick, mob.yo, mob.getY()) + leashOffset.y; + double lerpOriginZ = Mth.lerp(partialTick, mob.zo, mob.getZ()) + zAngleOffset; + Vec3 ropeGripPosition = leashHolder.getRopeHoldPosition(partialTick); + float xDif = (float) (ropeGripPosition.x - lerpOriginX); + float yDif = (float) (ropeGripPosition.y - lerpOriginY); + float zDif = (float) (ropeGripPosition.z - lerpOriginZ); + float offsetMod = Mth.invSqrt(xDif * xDif + zDif * zDif) * 0.025f / 2f; + float xOffset = zDif * offsetMod; + float zOffset = xDif * offsetMod; + VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.leash()); + BlockPos entityEyePos = BlockPos.containing(mob.getEyePosition(partialTick)); + BlockPos holderEyePos = BlockPos.containing(leashHolder.getEyePosition(partialTick)); + int entityBlockLight = azEntityRenderer.getBlockLightLevel((T) mob, entityEyePos); + int holderBlockLight = leashHolder.isOnFire() + ? 15 + : leashHolder.level() + .getBrightness( + LightLayer.BLOCK, + holderEyePos + ); + int entitySkyLight = mob.level().getBrightness(LightLayer.SKY, entityEyePos); + int holderSkyLight = mob.level().getBrightness(LightLayer.SKY, holderEyePos); + + poseStack.pushPose(); + poseStack.translate(xAngleOffset, leashOffset.y, zAngleOffset); + + Matrix4f posMatrix = new Matrix4f(poseStack.last().pose()); + + for (int segment = 0; segment <= 24; ++segment) { + renderLeashPiece( + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.025f, + xOffset, + zOffset, + segment, + false + ); + } + + for (int segment = 24; segment >= 0; --segment) { + renderLeashPiece( + vertexConsumer, + posMatrix, + xDif, + yDif, + zDif, + entityBlockLight, + holderBlockLight, + entitySkyLight, + holderSkyLight, + 0.025f, + 0.0f, + xOffset, + zOffset, + segment, + true + ); + } + + poseStack.popPose(); + } + + /** + * Static rendering code for rendering a leash segment.
    + * It's a like-for-like from {@link net.minecraft.client.renderer.entity.MobRenderer#addVertexPair} that had to be + * duplicated here for flexible usage + */ + private static void renderLeashPiece( + VertexConsumer buffer, + Matrix4f positionMatrix, + float xDif, + float yDif, + float zDif, + int entityBlockLight, + int holderBlockLight, + int entitySkyLight, + int holderSkyLight, + float width, + float yOffset, + float xOffset, + float zOffset, + int segment, + boolean isLeashKnot + ) { + var piecePosPercent = segment / 24f; + var lerpBlockLight = (int) Mth.lerp(piecePosPercent, entityBlockLight, holderBlockLight); + var lerpSkyLight = (int) Mth.lerp(piecePosPercent, entitySkyLight, holderSkyLight); + var packedLight = LightTexture.pack(lerpBlockLight, lerpSkyLight); + var knotColourMod = segment % 2 == (isLeashKnot ? 1 : 0) ? 0.7f : 1f; + var red = 0.5f * knotColourMod; + var green = 0.4f * knotColourMod; + var blue = 0.3f * knotColourMod; + var x = xDif * piecePosPercent; + var y = yDif > 0.0f + ? yDif * piecePosPercent * piecePosPercent + : yDif - yDif * (1.0f - piecePosPercent) * (1.0f - piecePosPercent); + var z = zDif * piecePosPercent; + + buffer.addVertex(positionMatrix, x - xOffset, y + yOffset, z + zOffset) + .setColor(red, green, blue, 1) + .setLight(packedLight); + buffer.addVertex(positionMatrix, x + xOffset, y + width - yOffset, z - zOffset) + .setColor(red, green, blue, 1) + .setLight(packedLight); + } + + private AzEntityLeashRenderUtil() { + throw new UnsupportedOperationException(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityModelRenderer.java new file mode 100644 index 000000000..dfd9ded30 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityModelRenderer.java @@ -0,0 +1,276 @@ +package mod.azure.azurelib.core2.render.entity; + +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.entity.LivingEntityRenderer; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Pose; +import org.joml.Matrix4f; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * AzEntityModelRenderer is a class responsible for rendering animated 3D entity models in a pipeline-based rendering + * setup. Extends the {@link AzModelRenderer} class and utilizes the {@link AzEntityRendererPipeline} to handle various + * rendering tasks, such as applying model transformations and managing animated states in the rendering lifecycle.
    + * + * @param The type of entity that this renderer applies to, extends the {@link Entity} class. + */ +public class AzEntityModelRenderer extends AzModelRenderer { + + private final AzEntityRendererPipeline entityRendererPipeline; + + public AzEntityModelRenderer(AzEntityRendererPipeline entityRendererPipeline, AzLayerRenderer layerRenderer) { + super(entityRendererPipeline, layerRenderer); + this.entityRendererPipeline = entityRendererPipeline; + } + + /** + * The actual render method that subtype renderers should override to handle their specific rendering tasks.
    + * {@link AzEntityRendererPipeline#preRender} has already been called by this stage, and + * {@link AzEntityRendererPipeline#postRender} will be called directly after + */ + @Override + public void render(AzRendererPipelineContext context, boolean isReRender) { + var animatable = context.animatable(); + var partialTick = context.partialTick(); + var poseStack = context.poseStack(); + + poseStack.pushPose(); + + LivingEntity livingEntity = animatable instanceof LivingEntity entity ? entity : null; + + boolean shouldSit = animatable.isPassenger() && (animatable.getVehicle() != null); + float lerpBodyRot = livingEntity == null + ? 0 + : Mth.rotLerp( + partialTick, + livingEntity.yBodyRotO, + livingEntity.yBodyRot + ); + float lerpHeadRot = livingEntity == null + ? 0 + : Mth.rotLerp( + partialTick, + livingEntity.yHeadRotO, + livingEntity.yHeadRot + ); + float netHeadYaw = lerpHeadRot - lerpBodyRot; + + if (shouldSit && animatable.getVehicle() instanceof LivingEntity livingentity) { + lerpBodyRot = Mth.rotLerp(partialTick, livingentity.yBodyRotO, livingentity.yBodyRot); + netHeadYaw = lerpHeadRot - lerpBodyRot; + float clampedHeadYaw = Mth.clamp(Mth.wrapDegrees(netHeadYaw), -85, 85); + lerpBodyRot = lerpHeadRot - clampedHeadYaw; + + if (clampedHeadYaw * clampedHeadYaw > 2500f) + lerpBodyRot += clampedHeadYaw * 0.2f; + + netHeadYaw = lerpHeadRot - lerpBodyRot; + } + + if (animatable.getPose() == Pose.SLEEPING && livingEntity != null) { + Direction bedDirection = livingEntity.getBedOrientation(); + + if (bedDirection != null) { + float eyePosOffset = livingEntity.getEyeHeight(Pose.STANDING) - 0.1F; + + poseStack.translate( + -bedDirection.getStepX() * eyePosOffset, + 0, + -bedDirection.getStepZ() * eyePosOffset + ); + } + } + + float nativeScale = livingEntity != null ? livingEntity.getScale() : 1; + float ageInTicks = animatable.tickCount + partialTick; + float limbSwingAmount = 0; + float limbSwing = 0; + + poseStack.scale(nativeScale, nativeScale, nativeScale); + applyRotations(animatable, poseStack, ageInTicks, lerpBodyRot, partialTick, nativeScale); + + if (!shouldSit && animatable.isAlive() && livingEntity != null) { + limbSwingAmount = Mth.lerp( + partialTick, + livingEntity.walkAnimation.speedOld, + livingEntity.walkAnimation.speed() + ); + limbSwing = livingEntity.walkAnimation.position() - livingEntity.walkAnimation.speed() * (1 - partialTick); + + if (livingEntity.isBaby()) { + limbSwing *= 3f; + } + + if (limbSwingAmount > 1f) { + limbSwingAmount = 1f; + } + } + + if (!isReRender) { + // FIXME: Figure out what to do with this data stuff. + // float headPitch = Mth.lerp(partialTick, animatable.xRotO, animatable.getXRot()); + // var velocity = animatable.getDeltaMovement(); + // float avgVelocity = (float) (Math.abs(velocity.x) + Math.abs(velocity.z) / 2f); + // + // long instanceId = getInstanceId(animatable); + // + // animationState.setData(DataTickets.TICK, animatable.getTick(animatable)); + // animationState.setData(DataTickets.ENTITY, animatable); + // animationState.setData( + // DataTickets.ENTITY_MODEL_DATA, + // new EntityModelData( + // shouldSit, + // livingEntity != null && livingEntity.isBaby(), + // -netHeadYaw, + // -headPitch + // ) + // ); + // + // this.model.addAdditionalStateData(animatable, instanceId, animationState::setData); + + var animator = entityRendererPipeline.getRenderer().getAnimator(); + + if (animator != null) { + animator.animate(animatable, context.partialTick()); + } + } + + entityRendererPipeline.modelRenderTranslations.set(poseStack.last().pose()); + + if (!animatable.isInvisibleTo(Minecraft.getInstance().player)) { + super.render(context, isReRender); + } + + poseStack.popPose(); + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + @Override + public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + var buffer = context.vertexConsumer(); + var bufferSource = context.multiBufferSource(); + var entity = context.animatable(); + var poseStack = context.poseStack(); + var renderType = context.renderType(); + + poseStack.pushPose(); + RenderUtils.translateMatrixToBone(poseStack, bone); + RenderUtils.translateToPivotPoint(poseStack, bone); + RenderUtils.rotateMatrixAroundBone(poseStack, bone); + RenderUtils.scaleMatrixForBone(poseStack, bone); + + if (bone.isTrackingMatrices()) { + Matrix4f poseState = new Matrix4f(poseStack.last().pose()); + Matrix4f localMatrix = RenderUtils.invertAndMultiplyMatrices( + poseState, + entityRendererPipeline.entityRenderTranslations + ); + + bone.setModelSpaceMatrix( + RenderUtils.invertAndMultiplyMatrices(poseState, entityRendererPipeline.modelRenderTranslations) + ); + bone.setLocalSpaceMatrix( + RenderUtils.translateMatrix( + localMatrix, + entityRendererPipeline.getRenderer().getRenderOffset(entity, 1).toVector3f() + ) + ); + bone.setWorldSpaceMatrix( + RenderUtils.translateMatrix(new Matrix4f(localMatrix), entity.position().toVector3f()) + ); + } + + RenderUtils.translateAwayFromPivotPoint(poseStack, bone); + + if (!isReRender && buffer instanceof BufferBuilder builder && !builder.building) { + context.setVertexConsumer(bufferSource.getBuffer(renderType)); + } + + renderCubesOfBone(context, bone); + + if (!isReRender) { + layerRenderer.applyRenderLayersForBone(context, bone); + } + + renderChildBones(context, bone, isReRender); + + poseStack.popPose(); + } + + /** + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * default scale of 1 + */ + protected void applyRotations( + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick + ) { + applyRotations(animatable, poseStack, ageInTicks, rotationYaw, partialTick, 1); + } + + /** + * Applies rotation transformations to the renderer prior to render time to account for various entity states, + * scalable + */ + protected void applyRotations( + T animatable, + PoseStack poseStack, + float ageInTicks, + float rotationYaw, + float partialTick, + float nativeScale + ) { + if (animatable.isFullyFrozen()) { + rotationYaw += (float) (Math.cos(animatable.tickCount * 3.25d) * Math.PI * 0.4d); + } + + if (!animatable.hasPose(Pose.SLEEPING)) { + poseStack.mulPose(Axis.YP.rotationDegrees(180f - rotationYaw)); + } + + if (animatable instanceof LivingEntity livingEntity) { + var config = entityRendererPipeline.getRenderer().config(); + var deathMaxRotation = config.getDeathMaxRotation(animatable); + + if (livingEntity.deathTime > 0) { + float deathRotation = (livingEntity.deathTime + partialTick - 1f) / 20f * 1.6f; + + poseStack.mulPose( + Axis.ZP.rotationDegrees(Math.min(Mth.sqrt(deathRotation), 1) * deathMaxRotation) + ); + } else if (livingEntity.isAutoSpinAttack()) { + poseStack.mulPose(Axis.XP.rotationDegrees(-90f - livingEntity.getXRot())); + poseStack.mulPose(Axis.YP.rotationDegrees((livingEntity.tickCount + partialTick) * -75f)); + } else if (animatable.hasPose(Pose.SLEEPING)) { + Direction bedOrientation = livingEntity.getBedOrientation(); + + poseStack.mulPose( + Axis.YP.rotationDegrees( + bedOrientation != null ? RenderUtils.getDirectionAngle(bedOrientation) : rotationYaw + ) + ); + poseStack.mulPose(Axis.ZP.rotationDegrees(deathMaxRotation)); + poseStack.mulPose(Axis.YP.rotationDegrees(270f)); + } else if (LivingEntityRenderer.isEntityUpsideDown(livingEntity)) { + poseStack.translate(0, (animatable.getBbHeight() + 0.1f) / nativeScale, 0); + poseStack.mulPose(Axis.ZP.rotationDegrees(180f)); + } + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameRenderUtil.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameRenderUtil.java new file mode 100644 index 000000000..3ab870582 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityNameRenderUtil.java @@ -0,0 +1,60 @@ +package mod.azure.azurelib.core2.render.entity; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.entity.EntityRenderDispatcher; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.Mob; + +import java.util.Objects; + +public class AzEntityNameRenderUtil { + + public static boolean shouldShowName(EntityRenderDispatcher entityRenderDispatcher, T entity) { + var nameRenderDistance = entity.isDiscrete() ? 32d : 64d; + + if (!(entity instanceof LivingEntity)) { + return false; + } + + if (entityRenderDispatcher.distanceToSqr(entity) >= nameRenderDistance * nameRenderDistance) { + return false; + } + + if ( + entity instanceof Mob && (!entity.shouldShowName() && (!entity.hasCustomName() + || entity != entityRenderDispatcher.crosshairPickEntity)) + ) { + return false; + } + + final var minecraft = Minecraft.getInstance(); + // TODO: See if we can do this null check better. + var player = Objects.requireNonNull(minecraft.player); + var visibleToClient = !entity.isInvisibleTo(player); + var entityTeam = entity.getTeam(); + + if (entityTeam == null) { + return Minecraft.renderNames() && entity != minecraft.getCameraEntity() && visibleToClient + && !entity.isVehicle(); + } + + var playerTeam = minecraft.player.getTeam(); + + return switch (entityTeam.getNameTagVisibility()) { + case ALWAYS -> visibleToClient; + case NEVER -> false; + case HIDE_FOR_OTHER_TEAMS -> playerTeam == null + ? visibleToClient + : entityTeam.isAlliedTo( + playerTeam + ) && (entityTeam.canSeeFriendlyInvisibles() || visibleToClient); + case HIDE_FOR_OWN_TEAM -> + playerTeam == null ? visibleToClient : !entityTeam.isAlliedTo(playerTeam) && visibleToClient; + }; + } + + private AzEntityNameRenderUtil() { + throw new UnsupportedOperationException(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java new file mode 100644 index 000000000..3cffabb8b --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRenderer.java @@ -0,0 +1,119 @@ +package mod.azure.azurelib.core2.render.entity; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import mod.azure.azurelib.core2.render.AzProvider; + +/** + * AzEntityRenderer is an abstract class responsible for rendering entities in the game. It extends the base + * functionality of {@link EntityRenderer} to provide additional rendering capabilities specific to animated and custom + * entities. This class is parameterized with a generic type {@code T}, which must extend {@link Entity}. It integrates + * several abstractions such as animation management, model caching, and advanced rendering pipelines for handling + * complex rendering behavior. Users are expected to configure this renderer using an {@link AzEntityRendererConfig}. + * Key components: - {@link AzEntityRendererConfig}: Defines configuration options such as textures, models, and + * animator providers. - {@link AzProvider}: Supplies baked models and animators for entities. - + * {@link AzEntityRendererPipeline}: Manages rendering logic through a custom pipeline. + */ +public abstract class AzEntityRenderer extends EntityRenderer { + + private final AzEntityRendererConfig config; + + private final AzProvider provider; + + private final AzEntityRendererPipeline rendererPipeline; + + @Nullable + private AzEntityAnimator reusedAzEntityAnimator; + + protected AzEntityRenderer(AzEntityRendererConfig config, EntityRendererProvider.Context context) { + super(context); + this.config = config; + this.provider = new AzProvider<>(config::createAnimator, config::modelLocation); + this.rendererPipeline = createPipeline(config); + } + + protected AzEntityRendererPipeline createPipeline(AzEntityRendererConfig config) { + return new AzEntityRendererPipeline<>(config, this); + } + + @Override + public final @NotNull ResourceLocation getTextureLocation(@NotNull T animatable) { + return config.textureLocation(animatable); + } + + public void superRender( + @NotNull T entity, + float entityYaw, + float partialTick, + @NotNull PoseStack poseStack, + @NotNull MultiBufferSource bufferSource, + int packedLight + ) { + super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight); + } + + @Override + public void render( + @NotNull T entity, + float entityYaw, + float partialTick, + @NotNull PoseStack poseStack, + @NotNull MultiBufferSource bufferSource, + int packedLight + ) { + var cachedEntityAnimator = (AzEntityAnimator) provider.provideAnimator(entity); + var azBakedModel = provider.provideBakedModel(entity); + + if (cachedEntityAnimator != null && azBakedModel != null) { + cachedEntityAnimator.setActiveModel(azBakedModel); + } + + // Point the renderer's current animator reference to the cached entity animator before rendering. + reusedAzEntityAnimator = cachedEntityAnimator; + + // Execute the render pipeline. + rendererPipeline.render( + poseStack, + azBakedModel, + entity, + bufferSource, + null, + null, + entityYaw, + partialTick, + packedLight + ); + } + + /** + * Whether the entity's nametag should be rendered or not.
    + * Pretty much exclusively used in {@link EntityRenderer#renderNameTag} + */ + @Override + public boolean shouldShowName(@NotNull T entity) { + return AzEntityNameRenderUtil.shouldShowName(entityRenderDispatcher, entity); + } + + // Proxy method override for super.getBlockLightLevel external access. + @Override + public int getBlockLightLevel(@NotNull T entity, @NotNull BlockPos pos) { + return super.getBlockLightLevel(entity, pos); + } + + public AzEntityAnimator getAnimator() { + return reusedAzEntityAnimator; + } + + public AzEntityRendererConfig config() { + return config; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererConfig.java new file mode 100644 index 000000000..af8884ea1 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererConfig.java @@ -0,0 +1,108 @@ +package mod.azure.azurelib.core2.render.entity; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +/** + * Configures the rendering behavior for custom entities in the game. This extends {@link AzRendererConfig}, adding + * extra functionality specifically for handling entity death rotations. + * + * @param the entity type this configuration applies to, extending {@link Entity} + */ +public class AzEntityRendererConfig extends AzRendererConfig { + + private final Function deathMaxRotationProvider; + + private AzEntityRendererConfig( + Supplier> animatorProvider, + Function deathMaxRotationProvider, + Function modelLocationProvider, + List> renderLayers, + Function textureLocationProvider, + float scaleHeight, + float scaleWidth + ) { + super(animatorProvider, modelLocationProvider, renderLayers, textureLocationProvider, scaleHeight, scaleWidth); + this.deathMaxRotationProvider = deathMaxRotationProvider; + } + + public float getDeathMaxRotation(T entity) { + return deathMaxRotationProvider.apply(entity); + } + + public static Builder builder( + ResourceLocation modelLocation, + ResourceLocation textureLocation + ) { + return new Builder<>($ -> modelLocation, $ -> textureLocation); + } + + public static Builder builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + return new Builder<>(modelLocationProvider, textureLocationProvider); + } + + public static class Builder extends AzRendererConfig.Builder { + + private Function deathMaxRotationProvider; + + protected Builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + super(modelLocationProvider, textureLocationProvider); + this.deathMaxRotationProvider = $ -> 90F; + } + + @Override + public Builder addRenderLayer(AzRenderLayer renderLayer) { + return (Builder) super.addRenderLayer(renderLayer); + } + + @Override + public Builder setAnimatorProvider(Supplier<@Nullable AzAnimator> animatorProvider) { + return (Builder) super.setAnimatorProvider(animatorProvider); + } + + public Builder setDeathMaxRotation(float angle) { + this.deathMaxRotationProvider = $ -> angle; + return this; + } + + /** + * Sets a provider for the max rotation value for dying entities.
    + * You might want to modify this for different aesthetics, such as a + * {@link net.minecraft.world.entity.monster.Spider} flipping upside down on death.
    + * Functionally equivalent to {@link net.minecraft.client.renderer.entity.LivingEntityRenderer#getFlipDegrees} + */ + public Builder setDeathMaxRotation(Function deathMaxRotationProvider) { + this.deathMaxRotationProvider = deathMaxRotationProvider; + return this; + } + + public AzEntityRendererConfig build() { + var baseConfig = super.build(); + + return new AzEntityRendererConfig<>( + baseConfig::createAnimator, + deathMaxRotationProvider, + baseConfig::modelLocation, + baseConfig.renderLayers(), + baseConfig::textureLocation, + baseConfig.scaleHeight(), + baseConfig.scaleWidth() + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipeline.java new file mode 100644 index 000000000..d5c57a440 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipeline.java @@ -0,0 +1,118 @@ +package mod.azure.azurelib.core2.render.entity; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Mob; +import org.joml.Matrix4f; + +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * Represents a renderer pipeline specifically designed for rendering entities. This pipeline facilitates stages of + * rendering where contextual work like pre-translations, texture animations, and leash rendering are managed within a + * customizable structure. + * + * @param The type of entity this renderer pipeline handles. Extends from the base {@link Entity}. + */ +public class AzEntityRendererPipeline extends AzRendererPipeline { + + private final AzEntityRenderer entityRenderer; + + protected Matrix4f entityRenderTranslations = new Matrix4f(); + + protected Matrix4f modelRenderTranslations = new Matrix4f(); + + public AzEntityRendererPipeline(AzEntityRendererConfig config, AzEntityRenderer entityRenderer) { + super(config); + this.entityRenderer = entityRenderer; + } + + @Override + protected AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { + return new AzEntityRendererPipelineContext<>(this); + } + + @Override + protected AzModelRenderer createModelRenderer(AzLayerRenderer layerRenderer) { + return new AzEntityModelRenderer<>(this, layerRenderer); + } + + @Override + protected AzLayerRenderer createLayerRenderer(AzRendererConfig config) { + return new AzEntityLayerRenderer<>(config::renderLayers); + } + + /** + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
    + * This should only be called immediately prior to rendering, and only + * + * @see AnimatableTexture#setAndUpdate(ResourceLocation, int) + */ + @Override + public void updateAnimatedTextureFrame(T entity) { + AnimatableTexture.setAndUpdate( + config.textureLocation(entity), + entity.getId() + entity.tickCount + ); + } + + /** + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
    + * {@link PoseStack} translations made here are kept until the end of the render process + */ + @Override + public void preRender(AzRendererPipelineContext context, boolean isReRender) { + var poseStack = context.poseStack(); + this.entityRenderTranslations.set(poseStack.last().pose()); + + var config = entityRenderer.config(); + var scaleWidth = config.scaleWidth(); + var scaleHeight = config.scaleHeight(); + + scaleModelForRender(context, scaleWidth, scaleHeight, isReRender); + } + + @Override + public void postRender(AzRendererPipelineContext context, boolean isReRender) {} + + /** + * Renders the final frame of the entity, including handling special cases such as entities with leashes. + * + * @param context the rendering context that contains all required data for rendering, such as the entity, pose + * stack, light information, and buffer source + */ + @Override + public void renderFinal(AzRendererPipelineContext context) { + var bufferSource = context.multiBufferSource(); + var entity = context.animatable(); + var packedLight = context.packedLight(); + var partialTick = context.partialTick(); + var poseStack = context.poseStack(); + + entityRenderer.superRender(entity, 0, partialTick, poseStack, bufferSource, packedLight); + + if (!(entity instanceof Mob mob)) { + return; + } + + var leashHolder = mob.getLeashHolder(); + + if (leashHolder == null) { + return; + } + + AzEntityLeashRenderUtil.renderLeash(entityRenderer, mob, partialTick, poseStack, bufferSource, leashHolder); + } + + public AzEntityRenderer getRenderer() { + return entityRenderer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipelineContext.java new file mode 100644 index 000000000..c808ac1b2 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/entity/AzEntityRendererPipelineContext.java @@ -0,0 +1,54 @@ +package mod.azure.azurelib.core2.render.entity; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * A context class specifically for rendering entities using a custom rendering pipeline. This class extends + * {@code AzRendererPipelineContext} and provides implementations for methods to customize entity rendering, such as + * determining default render types and packed overlay settings. + * + * @param the type of entity being rendered, extending {@code Entity} + */ +public class AzEntityRendererPipelineContext extends AzRendererPipelineContext { + + public AzEntityRendererPipelineContext(AzRendererPipeline rendererPipeline) { + super(rendererPipeline); + } + + @Override + public @NotNull RenderType getDefaultRenderType( + T animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ) { + return RenderType.entityCutoutNoCull(texture); + } + + /** + * Gets a packed overlay coordinate pair for rendering.
    + * Mostly just used for the red tint when an entity is hurt, but can be used for other things like the + * {@link net.minecraft.world.entity.monster.Creeper} white tint when exploding. + */ + @Override + public int getPackedOverlay(T entity, float u, float partialTick) { + if (!(entity instanceof LivingEntity livingEntity)) { + return OverlayTexture.NO_OVERLAY; + } + + return OverlayTexture.pack( + OverlayTexture.u(u), + OverlayTexture.v(livingEntity.hurtTime > 0 || livingEntity.deathTime > 0) + ); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemGuiRenderUtil.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemGuiRenderUtil.java new file mode 100644 index 000000000..701c910d4 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemGuiRenderUtil.java @@ -0,0 +1,57 @@ +package mod.azure.azurelib.core2.render.item; + +import com.mojang.blaze3d.platform.Lighting; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.world.item.ItemStack; + +import mod.azure.azurelib.core2.model.AzBakedModel; + +public class AzItemGuiRenderUtil { + + /** + * Wrapper method to handle rendering the item in a GUI context (defined by + * {@link net.minecraft.world.item.ItemDisplayContext#GUI} normally).
    + * Just includes some additional required transformations and settings. + */ + public static void renderInGui( + AzItemRendererConfig config, + AzItemRendererPipeline rendererPipeline, + ItemStack stack, + AzBakedModel model, + ItemStack currentItemStack, + PoseStack poseStack, + MultiBufferSource source, + int packedLight + ) { + if (config.useEntityGuiLighting()) { + Lighting.setupForEntityInInventory(); + } else { + Lighting.setupForFlatItems(); + } + + var partialTick = Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(); + var bSource = + source instanceof MultiBufferSource.BufferSource bufferSource + ? bufferSource + : Minecraft.getInstance().levelRenderer.renderBuffers.bufferSource(); + var textureLocation = config.textureLocation(stack); + var renderType = rendererPipeline.context() + .getDefaultRenderType(stack, textureLocation, bSource, partialTick); + var withGlint = currentItemStack != null && currentItemStack.hasFoil(); + var buffer = ItemRenderer.getFoilBufferDirect(source, renderType, true, withGlint); + + poseStack.pushPose(); + + rendererPipeline.render(poseStack, model, stack, bSource, renderType, buffer, 0, partialTick, packedLight); + + bSource.endBatch(); + RenderSystem.enableDepthTest(); + Lighting.setupFor3DItems(); + + poseStack.popPose(); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemModelRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemModelRenderer.java new file mode 100644 index 000000000..9cb40a9b5 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemModelRenderer.java @@ -0,0 +1,78 @@ +package mod.azure.azurelib.core2.render.item; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzModelRenderer; +import mod.azure.azurelib.core2.render.AzPhasedRenderer; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * AzItemModelRenderer is a specialized implementation of {@link AzModelRenderer} for rendering {@link ItemStack} + * objects. It provides customized rendering logic for rendering item models in a layered and recursive manner. + */ +public class AzItemModelRenderer extends AzModelRenderer { + + private final AzItemRendererPipeline itemRendererPipeline; + + public AzItemModelRenderer(AzItemRendererPipeline itemRendererPipeline, AzLayerRenderer layerRenderer) { + super(itemRendererPipeline, layerRenderer); + this.itemRendererPipeline = itemRendererPipeline; + } + + /** + * The actual render method that subtype renderers should override to handle their specific rendering tasks.
    + * {@link AzPhasedRenderer#preRender} has already been called by this stage, and {@link AzPhasedRenderer#postRender} + * will be called directly after + */ + @Override + public void render(AzRendererPipelineContext context, boolean isReRender) { + if (!isReRender) { + var animatable = context.animatable(); + var animator = itemRendererPipeline.getRenderer().getAnimator(); + + if (animator != null) { + animator.animate(animatable, context.partialTick()); + } + } + + var poseStack = context.poseStack(); + + itemRendererPipeline.modelRenderTranslations = new Matrix4f(poseStack.last().pose()); + + super.render(context, isReRender); + } + + /** + * Renders the provided {@link AzBone} and its associated child bones + */ + @Override + public void renderRecursively(AzRendererPipelineContext context, AzBone bone, boolean isReRender) { + if (bone.isTrackingMatrices()) { + var animatable = context.animatable(); + var poseStack = context.poseStack(); + var poseState = new Matrix4f(poseStack.last().pose()); + var localMatrix = RenderUtils.invertAndMultiplyMatrices( + poseState, + itemRendererPipeline.itemRenderTranslations + ); + + bone.setModelSpaceMatrix( + RenderUtils.invertAndMultiplyMatrices(poseState, itemRendererPipeline.modelRenderTranslations) + ); + bone.setLocalSpaceMatrix( + RenderUtils.translateMatrix(localMatrix, getRenderOffset(animatable, 1).toVector3f()) + ); + } + + super.renderRecursively(context, bone, isReRender); + } + + public Vec3 getRenderOffset(ItemStack itemStack, float f) { + return Vec3.ZERO; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java new file mode 100644 index 000000000..dfdb18a31 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRenderer.java @@ -0,0 +1,97 @@ +package mod.azure.azurelib.core2.render.item; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.render.AzProvider; + +/** + * AzItemRenderer is an abstract base class for rendering custom animated items in a game framework. It provides + * utilities for handling item models, textures, and animations via a configurable pipeline and provider system. This + * class supports rendering of items both in GUI contexts and in-world as entities, enabling advanced visual effects + * such as custom animations and lighting.
    + * The rendering process utilizes a pipeline to manage render layers, textures, and baked models, integrating with game + * frame components like PoseStack and MultiBufferSource. + */ +public abstract class AzItemRenderer { + + private final AzItemRendererConfig config; + + private final AzProvider provider; + + private final AzItemRendererPipeline rendererPipeline; + + @Nullable + private AzItemAnimator reusedAzItemAnimator; + + protected AzItemRenderer( + AzItemRendererConfig config + ) { + this.rendererPipeline = createPipeline(config); + this.provider = new AzProvider<>(config::createAnimator, config::modelLocation); + this.config = config; + } + + protected AzItemRendererPipeline createPipeline(AzItemRendererConfig config) { + return new AzItemRendererPipeline(config, this); + } + + public void renderByGui( + ItemStack stack, + @NotNull PoseStack poseStack, + @NotNull MultiBufferSource source, + int packedLight + ) { + var model = provider.provideBakedModel(stack); + + prepareAnimator(stack, model); + + AzItemGuiRenderUtil.renderInGui(config, rendererPipeline, stack, model, stack, poseStack, source, packedLight); + } + + public void renderByItem( + ItemStack stack, + @NotNull PoseStack poseStack, + @NotNull MultiBufferSource source, + int packedLight + ) { + var model = provider.provideBakedModel(stack); + var partialTick = Minecraft.getInstance().getTimer().getGameTimeDeltaTicks(); + var textureLocation = config.textureLocation(stack); + var renderType = rendererPipeline.context() + .getDefaultRenderType(stack, textureLocation, source, partialTick); + // TODO: Why the null check here? + var withGlint = stack != null && stack.hasFoil(); + var buffer = ItemRenderer.getFoilBufferDirect(source, renderType, false, withGlint); + + prepareAnimator(stack, model); + + rendererPipeline.render(poseStack, model, stack, source, renderType, buffer, 0, partialTick, packedLight); + } + + private void prepareAnimator(ItemStack stack, AzBakedModel model) { + var cachedEntityAnimator = (AzItemAnimator) provider.provideAnimator(stack); + + if (cachedEntityAnimator != null && model != null) { + cachedEntityAnimator.setActiveModel(model); + } + + // Point the renderer's current animator reference to the cached entity animator before rendering. + reusedAzItemAnimator = cachedEntityAnimator; + } + + public @Nullable AzItemAnimator getAnimator() { + return reusedAzItemAnimator; + } + + public AzItemRendererConfig config() { + return config; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererConfig.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererConfig.java new file mode 100644 index 000000000..227ca19b0 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererConfig.java @@ -0,0 +1,117 @@ +package mod.azure.azurelib.core2.render.item; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +import mod.azure.azurelib.core2.animation.AzAnimator; +import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.layer.AzRenderLayer; + +/** + * Configuration class for rendering items using customized settings in an animation framework. Extends + * {@link AzRendererConfig} specifically for handling {@link ItemStack}. Provides additional settings specific to item + * rendering, such as GUI lighting and custom offsets. + */ +public class AzItemRendererConfig extends AzRendererConfig { + + private final boolean useEntityGuiLighting; + + private final boolean useNewOffset; + + private AzItemRendererConfig( + Supplier> animatorProvider, + Function modelLocationProvider, + List> renderLayers, + Function textureLocationProvider, + float scaleHeight, + float scaleWidth, + boolean useEntityGuiLighting, + boolean useNewOffset + ) { + super(animatorProvider, modelLocationProvider, renderLayers, textureLocationProvider, scaleHeight, scaleWidth); + this.useEntityGuiLighting = useEntityGuiLighting; + this.useNewOffset = useNewOffset; + } + + public boolean useEntityGuiLighting() { + return useEntityGuiLighting; + } + + public boolean useNewOffset() { + return useNewOffset; + } + + public static Builder builder( + ResourceLocation modelLocation, + ResourceLocation textureLocation + ) { + return new Builder($ -> modelLocation, $ -> textureLocation); + } + + public static Builder builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + return new Builder(modelLocationProvider, textureLocationProvider); + } + + public static class Builder extends AzRendererConfig.Builder { + + private boolean useEntityGuiLighting; + + private boolean useNewOffset; + + protected Builder( + Function modelLocationProvider, + Function textureLocationProvider + ) { + super(modelLocationProvider, textureLocationProvider); + this.useEntityGuiLighting = false; + this.useNewOffset = false; + } + + @Override + public Builder addRenderLayer(AzRenderLayer renderLayer) { + return (Builder) super.addRenderLayer(renderLayer); + } + + @Override + public Builder setAnimatorProvider(Supplier<@Nullable AzAnimator> animatorProvider) { + return (Builder) super.setAnimatorProvider(animatorProvider); + } + + public Builder useEntityGuiLighting() { + this.useEntityGuiLighting = true; + return this; + } + + /** + * @param useNewOffset Determines whether to apply the y offset for a model due to the change in BlockBench + * 4.11. + */ + public AzRendererConfig.Builder useNewOffset(boolean useNewOffset) { + this.useNewOffset = useNewOffset; + return this; + } + + public AzItemRendererConfig build() { + var baseConfig = super.build(); + + return new AzItemRendererConfig( + baseConfig::createAnimator, + baseConfig::modelLocation, + baseConfig.renderLayers(), + baseConfig::textureLocation, + baseConfig.scaleHeight(), + baseConfig.scaleWidth(), + useEntityGuiLighting, + useNewOffset + ); + } + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipeline.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipeline.java new file mode 100644 index 000000000..18d2f5e32 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipeline.java @@ -0,0 +1,91 @@ +package mod.azure.azurelib.core2.render.item; + +import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.joml.Matrix4f; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.common.internal.common.cache.texture.AnimatableTexture; +import mod.azure.azurelib.core2.render.AzLayerRenderer; +import mod.azure.azurelib.core2.render.AzRendererConfig; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * Extends the {@link AzRendererPipeline} to provide a specific implementation for rendering {@link ItemStack} objects. + * This pipeline includes methods and configurations designed for item rendering and leverages additional utilities such + * as translation matrices and scaling functionalities for accurate rendering. + */ +public class AzItemRendererPipeline extends AzRendererPipeline { + + private final AzItemRenderer itemRenderer; + + protected Matrix4f itemRenderTranslations = new Matrix4f(); + + protected Matrix4f modelRenderTranslations = new Matrix4f(); + + public AzItemRendererPipeline(AzItemRendererConfig config, AzItemRenderer itemRenderer) { + super(config); + this.itemRenderer = itemRenderer; + } + + @Override + protected AzRendererPipelineContext createContext(AzRendererPipeline rendererPipeline) { + return new AzItemRendererPipelineContext(rendererPipeline); + } + + @Override + protected AzItemModelRenderer createModelRenderer(AzLayerRenderer layerRenderer) { + return new AzItemModelRenderer(this, layerRenderer); + } + + @Override + protected AzLayerRenderer createLayerRenderer(AzRendererConfig config) { + return new AzLayerRenderer<>(config::renderLayers); + } + + /** + * Called before rendering the model to buffer. Allows for render modifications and preparatory work such as scaling + * and translating.
    + * {@link PoseStack} translations made here are kept until the end of the render process + */ + @Override + public void preRender(AzRendererPipelineContext context, boolean isReRender) { + var poseStack = context.poseStack(); + this.itemRenderTranslations = new Matrix4f(poseStack.last().pose()); + + var config = itemRenderer.config(); + var scaleWidth = config.scaleWidth(); + var scaleHeight = config.scaleHeight(); + scaleModelForRender(context, scaleWidth, scaleHeight, isReRender); + + if (!isReRender) { + var useNewOffset = config.useNewOffset(); + poseStack.translate(0.5f, useNewOffset ? 0.0f : 0.51f, 0.5f); + } + } + + @Override + public void postRender(AzRendererPipelineContext context, boolean isReRender) {} + + /** + * Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this + * GeoRenderer.
    + * This should only be called immediately prior to rendering, and only + * + * @see AnimatableTexture#setAndUpdate(ResourceLocation, int) + */ + @Override + public void updateAnimatedTextureFrame(ItemStack animatable) { + AnimatableTexture.setAndUpdate( + config.textureLocation(animatable), + Item.getId(animatable.getItem()) + (int) RenderUtils.getCurrentTick() + ); + } + + public AzItemRenderer getRenderer() { + return itemRenderer; + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipelineContext.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipelineContext.java new file mode 100644 index 000000000..3171b00c6 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererPipelineContext.java @@ -0,0 +1,36 @@ +package mod.azure.azurelib.core2.render.item; + +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * A specialized subclass of {@link AzRendererPipelineContext} designed for rendering {@link ItemStack} objects. + * Provides the default rendering context and pipeline for rendering item models within a custom rendering framework. + *
    + * This context delegates rendering operations to its associated {@link AzRendererPipeline} while providing additional + * configuration and control over the rendering process of an {@link ItemStack}. + */ +public class AzItemRendererPipelineContext extends AzRendererPipelineContext { + + public AzItemRendererPipelineContext(AzRendererPipeline rendererPipeline) { + super(rendererPipeline); + } + + // TODO: This is what Geckolib does, but it feels wrong to have this render type getter for an ITEM... + @Override + public @NotNull RenderType getDefaultRenderType( + ItemStack animatable, + ResourceLocation texture, + @Nullable MultiBufferSource bufferSource, + float partialTick + ) { + return RenderType.entityCutoutNoCull(texture); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererRegistry.java b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererRegistry.java new file mode 100644 index 000000000..a0d9b7ca4 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/item/AzItemRendererRegistry.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.core2.render.item; + +import net.minecraft.world.item.Item; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +/** + * The AzItemRendererRegistry class manages the association between items and their renderers in the context of the + * AzureLib framework. It provides functionality to register and retrieve item renderers dynamically, ensuring that + * appropriate renderers can be applied to specific item types or instances. + */ +public class AzItemRendererRegistry { + + private static final Map ITEM_TO_RENDERER = new HashMap<>(); + + private static final Map> ITEM_TO_RENDERER_SUPPLIER = new HashMap<>(); + + public static void register(Item item, Supplier itemRendererSupplier) { + ITEM_TO_RENDERER_SUPPLIER.put(item, itemRendererSupplier); + } + + public static void register(Supplier itemRendererSupplier, Item item, Item... items) { + register(item, itemRendererSupplier); + + for (var otherItem : items) { + register(otherItem, itemRendererSupplier); + } + } + + public static @Nullable AzItemRenderer getOrNull(Item item) { + return ITEM_TO_RENDERER.computeIfAbsent(item, ($) -> { + var rendererSupplier = ITEM_TO_RENDERER_SUPPLIER.get(item); + return rendererSupplier == null ? null : rendererSupplier.get(); + }); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java new file mode 100644 index 000000000..31f9989d4 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzArmorLayer.java @@ -0,0 +1,387 @@ +package mod.azure.azurelib.core2.render.layer; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.geom.ModelLayers; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.blockentity.SkullBlockRenderer; +import net.minecraft.core.component.DataComponents; +import net.minecraft.tags.ItemTags; +import net.minecraft.util.FastColor; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.*; +import net.minecraft.world.item.component.DyedItemColor; +import net.minecraft.world.level.block.AbstractSkullBlock; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; +import mod.azure.azurelib.core2.render.armor.AzArmorRenderer; +import mod.azure.azurelib.core2.render.armor.AzArmorRendererRegistry; + +/** + * Builtin class for handling dynamic armor rendering on AzureLib entities.
    + * Supports {@link net.minecraft.world.item.ArmorItem Vanilla} armor models.
    + * Unlike a traditional armor renderer, this renderer renders per-bone, giving much more flexible armor rendering. + */ +public class AzArmorLayer implements AzRenderLayer { + + protected static final HumanoidModel INNER_ARMOR_MODEL = new HumanoidModel<>( + Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR) + ); + + protected static final HumanoidModel OUTER_ARMOR_MODEL = new HumanoidModel<>( + Minecraft.getInstance().getEntityModels().bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR) + ); + + @Nullable + protected ItemStack mainHandStack; + + @Nullable + protected ItemStack offhandStack; + + @Nullable + protected ItemStack helmetStack; + + @Nullable + protected ItemStack chestplateStack; + + @Nullable + protected ItemStack leggingsStack; + + @Nullable + protected ItemStack bootsStack; + + /** + * Prepares the necessary item stacks for rendering by accessing the relevant equipment slots of the animatable + * instance. If the animatable instance is not a LivingEntity, the method returns without action. + * + * @param context The rendering context containing the animatable instance and other necessary data for rendering. + */ + @Override + public void preRender(AzRendererPipelineContext context) { + if (!(context.animatable() instanceof LivingEntity livingEntity)) { + return; + } + + this.mainHandStack = livingEntity.getItemBySlot(EquipmentSlot.MAINHAND); + this.offhandStack = livingEntity.getItemBySlot(EquipmentSlot.OFFHAND); + this.helmetStack = livingEntity.getItemBySlot(EquipmentSlot.HEAD); + this.chestplateStack = livingEntity.getItemBySlot(EquipmentSlot.CHEST); + this.leggingsStack = livingEntity.getItemBySlot(EquipmentSlot.LEGS); + this.bootsStack = livingEntity.getItemBySlot(EquipmentSlot.FEET); + } + + @Override + public void render(AzRendererPipelineContext context) {} + + /** + * Renders the given armor or skull block for the specified bone using the provided rendering context. Depending on + * the type of item, it delegates rendering to appropriate methods. + * + * @param context The rendering context containing necessary parameters for rendering, like pose stack, light level, + * etc. + * @param bone The specific bone of the model where the armor or skull block will be rendered. + */ + @Override + public void renderForBone(AzRendererPipelineContext context, AzBone bone) { + var poseStack = context.poseStack(); + var armorStack = getArmorItemForBone(context, bone); + + if (armorStack == null) { + return; + } + + if ( + armorStack.getItem() instanceof BlockItem blockItem && blockItem + .getBlock() instanceof AbstractSkullBlock skullBlock + ) { + renderSkullAsArmor(context, bone, armorStack, skullBlock); + } else { + renderArmor(context, bone, armorStack, poseStack); + } + } + + /** + * Renders armor items on a given bone within the render cycle of a model. This method determines the appropriate + * equipment slot, renderer, and model for the armor item and handles the rendering process accordingly. + * + * @param context The rendering context containing the animatable instance and other data essential for + * rendering. + * @param bone The specific bone of the model where the armor piece will be rendered. + * @param armorStack The ItemStack representing the armor item to render. + * @param poseStack The matrix stack used to apply transformations during rendering. + */ + private void renderArmor( + AzRendererPipelineContext context, + AzBone bone, + ItemStack armorStack, + PoseStack poseStack + ) { + var slot = getEquipmentSlotForBone(context, bone, armorStack); + var renderer = getRendererForItem(armorStack); + var model = getModelForItem(armorStack, slot); + var modelPart = getModelPartForBone(context, model); + + if (!modelPart.cubes.isEmpty()) { + poseStack.pushPose(); + poseStack.scale(-1, -1, 1); + + if (renderer != null && context.animatable() instanceof Entity entity) { + var boneContext = renderer.rendererPipeline().context().boneContext(); + + prepModelPartForRender(context, bone, modelPart); + renderer.prepForRender(entity, armorStack, slot, model); + boneContext.applyBoneVisibilityByPart(slot, modelPart, model); + model.renderToBuffer( + poseStack, + null, + context.packedLight(), + context.packedOverlay(), + armorStack.is( + ItemTags.DYEABLE + ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(armorStack, -6265536)) : -1 + ); + } else if (armorStack.getItem() instanceof ArmorItem) { + prepModelPartForRender(context, bone, modelPart); + renderVanillaArmorPiece( + context, + bone, + slot, + armorStack, + modelPart + ); + } + + poseStack.popPose(); + } + } + + /** + * Return an EquipmentSlot for a given {@link ItemStack} and animatable instance.
    + * This is what determines the base model to use for rendering a particular stack + */ + protected @NotNull EquipmentSlot getEquipmentSlotForBone( + AzRendererPipelineContext context, + AzBone bone, + ItemStack stack + ) { + var animatable = context.animatable(); + + if (animatable instanceof LivingEntity livingEntity) { + for (var slot : EquipmentSlot.values()) { + var isHumanoidArmorSlotType = slot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR; + + if (isHumanoidArmorSlotType && stack == livingEntity.getItemBySlot(slot)) { + return slot; + } + } + } + + return EquipmentSlot.CHEST; + } + + /** + * Return a ModelPart for a given {@link AzBone}.
    + * This is then transformed into position for the final render + */ + @NotNull + protected ModelPart getModelPartForBone(AzRendererPipelineContext context, HumanoidModel baseModel) { + return baseModel.body; + } + + /** + * Get the {@link ItemStack} relevant to the bone being rendered.
    + * Return null if this bone should be ignored + */ + @Nullable + protected ItemStack getArmorItemForBone(AzRendererPipelineContext context, AzBone bone) { + return null; + } + + /** + * Renders an individual armor piece base on the given {@link AzBone} and {@link ItemStack} + */ + protected void renderVanillaArmorPiece( + AzRendererPipelineContext context, + AzBone bone, + EquipmentSlot slot, + ItemStack armorStack, + ModelPart modelPart + ) { + var material = ((ArmorItem) armorStack.getItem()).getMaterial(); + + for (var layer : material.value().layers()) { + var buffer = getVanillaArmorBuffer( + context, + armorStack, + slot, + bone, + layer, + false + ); + + modelPart.render(context.poseStack(), buffer, context.packedLight(), context.packedOverlay()); + } + + var trim = armorStack.get(DataComponents.TRIM); + + if (trim != null) { + var spriteLocation = slot == EquipmentSlot.LEGS ? trim.innerTexture(material) : trim.outerTexture(material); + var consumer = context.multiBufferSource() + .getBuffer(Sheets.armorTrimsSheet(trim.pattern().value().decal())); + var sprite = Minecraft.getInstance() + .getModelManager() + .getAtlas(Sheets.ARMOR_TRIMS_SHEET) + .getSprite(spriteLocation); + var buffer = sprite.wrap(consumer); + modelPart.render(context.poseStack(), buffer, context.packedLight(), context.packedOverlay()); + } + + if (armorStack.hasFoil()) + modelPart.render( + context.poseStack(), + getVanillaArmorBuffer( + context, + armorStack, + slot, + bone, + null, + true + ), + context.packedLight(), + context.packedOverlay(), + 1 + ); + } + + /** + * Retrieves a {@link VertexConsumer} for rendering vanilla-styled armor. The method determines whether the armor + * should apply a glint effect or not and selects the appropriate render type accordingly. + * + * @param context The rendering context providing necessary data for rendering, including the animatable instance + * and the buffer source. + * @param stack The armor {@link ItemStack} being rendered. + * @param slot The {@link EquipmentSlot} the armor piece occupies. + * @param bone The model bone associated with the armor piece. + * @param layer The optional {@link ArmorMaterial.Layer} providing texture resources for rendering the armor. + * @param forGlint A flag indicating whether the armor piece should render with a glint effect. + * @return The {@link VertexConsumer} used to render the designated armor piece with the appropriate style and + * effect. + */ + protected VertexConsumer getVanillaArmorBuffer( + AzRendererPipelineContext context, + ItemStack stack, + EquipmentSlot slot, + AzBone bone, + @Nullable ArmorMaterial.Layer layer, + boolean forGlint + ) { + if (forGlint) { + return context.multiBufferSource().getBuffer(RenderType.armorEntityGlint()); + } + + return context.multiBufferSource() + .getBuffer(RenderType.armorCutoutNoCull(layer.texture(slot == EquipmentSlot.LEGS))); + } + + /** + * Retrieves the appropriate {@link AzArmorRenderer} for the given {@link ItemStack}. This method uses the + * {@link AzArmorRendererRegistry} to fetch a renderer if one is registered for the specified item's class or + * instance. + * + * @param stack The {@link ItemStack} for which the renderer is to be obtained. + * @return The {@link AzArmorRenderer} associated with the item in the stack, or null if no renderer exists. + */ + protected @Nullable AzArmorRenderer getRendererForItem(ItemStack stack) { + var item = stack.getItem(); + return AzArmorRendererRegistry.getOrNull(item); + } + + /** + * Returns a cached instance of a base HumanoidModel that is used for rendering/modelling the provided + * {@link ItemStack} + */ + protected HumanoidModel getModelForItem(ItemStack stack, EquipmentSlot slot) { + var renderer = getRendererForItem(stack); + + if (renderer == null) { + return slot == EquipmentSlot.LEGS ? INNER_ARMOR_MODEL : OUTER_ARMOR_MODEL; + } + + return renderer.rendererPipeline().armorModel(); + } + + /** + * Render a given {@link AbstractSkullBlock} as a worn armor piece in relation to a given {@link AzBone} + */ + protected void renderSkullAsArmor( + AzRendererPipelineContext context, + AzBone bone, + ItemStack stack, + AbstractSkullBlock skullBlock + ) { + var type = skullBlock.getType(); + var model = SkullBlockRenderer.createSkullRenderers(Minecraft.getInstance().getEntityModels()) + .get(type); + var renderType = SkullBlockRenderer.getRenderType(type, stack.get(DataComponents.PROFILE)); + + context.poseStack().pushPose(); + RenderUtils.translateAndRotateMatrixForBone(context.poseStack(), bone); + context.poseStack().scale(1.1875f, 1.1875f, 1.1875f); + context.poseStack().translate(-0.5f, 0, -0.5f); + SkullBlockRenderer.renderSkull( + null, + 0, + 0, + context.poseStack(), + context.multiBufferSource(), + context.packedLight(), + model, + renderType + ); + context.poseStack().popPose(); + } + + /** + * Prepares the given {@link ModelPart} for render by setting its translation, position, and rotation values based + * on the provided {@link AzBone} + * + * @param context + * @param bone The AzBone to base the translations on + * @param sourcePart The ModelPart to translate + */ + protected void prepModelPartForRender(AzRendererPipelineContext context, AzBone bone, ModelPart sourcePart) { + var firstCube = bone.getCubes().get(0); + var armorCube = sourcePart.cubes.get(0); + var armorBoneSizeX = firstCube.size().x(); + var armorBoneSizeY = firstCube.size().y(); + var armorBoneSizeZ = firstCube.size().z(); + var actualArmorSizeX = Math.abs(armorCube.maxX - armorCube.minX); + var actualArmorSizeY = Math.abs(armorCube.maxY - armorCube.minY); + var actualArmorSizeZ = Math.abs(armorCube.maxZ - armorCube.minZ); + var scaleX = (float) (armorBoneSizeX / actualArmorSizeX); + var scaleY = (float) (armorBoneSizeY / actualArmorSizeY); + var scaleZ = (float) (armorBoneSizeZ / actualArmorSizeZ); + + sourcePart.setPos( + -(bone.getPivotX() - ((bone.getPivotX() * scaleX) - bone.getPivotX()) / scaleX), + -(bone.getPivotY() - ((bone.getPivotY() * scaleY) - bone.getPivotY()) / scaleY), + (bone.getPivotZ() - ((bone.getPivotZ() * scaleZ) - bone.getPivotZ()) / scaleZ) + ); + + sourcePart.xRot = -bone.getRotX(); + sourcePart.yRot = -bone.getRotY(); + sourcePart.zRot = bone.getRotZ(); + + context.poseStack().scale(scaleX, scaleY, scaleZ); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java new file mode 100644 index 000000000..f68410ebc --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzAutoGlowingLayer.java @@ -0,0 +1,56 @@ +package mod.azure.azurelib.core2.render.layer; + +import net.minecraft.client.renderer.RenderType; + +import mod.azure.azurelib.common.internal.common.cache.texture.AutoGlowingTexture; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * A {@link AzRenderLayer} dedicated to rendering the auto-generated glow layer functionality provided by AzureLib. This + * utilizes texture files with the _glowing suffix to create glowing effects for models. + */ +public class AzAutoGlowingLayer implements AzRenderLayer { + + @Override + public void preRender(AzRendererPipelineContext context) {} + + /** + * Handles the main rendering logic for the animatable object in the pipeline context. This includes switching to a + * custom {@link RenderType} for glowing textures and rendering the object using the pipeline's re-render mechanism. + *

    + * The rendering context's state is modified temporarily to apply a custom render type and packed light. After + * rendering, the context is restored to its original state for consistency. + *

    + * + * @param context the rendering pipeline context, containing the animatable object and rendering state + */ + @Override + public void render(AzRendererPipelineContext context) { + var animatable = context.animatable(); + var renderPipeline = context.rendererPipeline(); + var textureLocation = renderPipeline.config().textureLocation(animatable); + var renderType = AutoGlowingTexture.getRenderType(textureLocation); + + if (context.renderType() != null) { + var prevRenderType = context.renderType(); + var prevPackedLight = context.packedLight(); + var prevVertexConsumer = context.vertexConsumer(); + + context.setRenderType(renderType); + context.setPackedLight(0xF00000); + context.setVertexConsumer(context.multiBufferSource().getBuffer(renderType)); + + renderPipeline.reRender(context); + + // Restore context for sanity + // TODO: Should probably cache the context as a whole somewhere and then restore it (a "previous" context). + context.setRenderType(prevRenderType); + context.setPackedLight(prevPackedLight); + context.setVertexConsumer(prevVertexConsumer); + } + } + + @Override + public void renderForBone(AzRendererPipelineContext context, AzBone bone) {} +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java new file mode 100644 index 000000000..99f5c0957 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzBlockAndItemLayer.java @@ -0,0 +1,180 @@ +package mod.azure.azurelib.core2.render.layer; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.function.Function; + +import mod.azure.azurelib.common.internal.client.util.RenderUtils; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * A {@link AzRenderLayer} responsible for rendering {@link net.minecraft.world.level.block.state.BlockState + * BlockStates} or {@link net.minecraft.world.item.ItemStack ItemStacks} onto a specified {@link AzRendererPipeline}. + * This layer handles the rendering of physical elements, such as blocks and items, associated with animation bones. + */ +public class AzBlockAndItemLayer implements AzRenderLayer { + + protected final Function itemStackProvider; + + protected final Function blockStateProvider; + + public AzBlockAndItemLayer() { + this(bone -> null, bone -> null); + } + + public AzBlockAndItemLayer( + Function itemStackProvider, + Function blockStateProvider + ) { + super(); + + this.itemStackProvider = itemStackProvider; + this.blockStateProvider = blockStateProvider; + } + + @Override + public void preRender(AzRendererPipelineContext context) {} + + @Override + public void render(AzRendererPipelineContext context) {} + + /** + * Renders an {@link ItemStack} or {@link BlockState} associated with the specified bone in the rendering context. + * If both the {@link ItemStack} and {@link BlockState} are {@code null}, no rendering occurs. + *

    + * This method applies the bone's transformations to the current rendering matrix stack before rendering, ensuring + * the item or block appears correctly positioned and oriented relative to the bone. + *

    + * + * @param context the rendering pipeline context, containing rendering state and utilities + * @param bone the bone for which to render associated elements + */ + @Override + public void renderForBone(AzRendererPipelineContext context, AzBone bone) { + var stack = itemStackForBone(bone); + var blockState = blockStateForBone(bone); + + if (stack == null && blockState == null) + return; + + context.poseStack().pushPose(); + RenderUtils.translateAndRotateMatrixForBone(context.poseStack(), bone); + + if (stack != null) + renderItemForBone(context, bone, stack); + + if (blockState != null) + renderBlockForBone(context, bone, blockState); + + context.poseStack().popPose(); + } + + /** + * Retrieves the {@link ItemStack} associated with the given bone for rendering purposes. Returns {@code null} if + * there is no {@link ItemStack} to render for this bone. + * + * @param bone the bone for which to retrieve the {@link ItemStack} + * @return the {@link ItemStack} relevant to the specified bone, or {@code null} if none exists + */ + public ItemStack itemStackForBone(AzBone bone) { + return itemStackProvider.apply(bone); + } + + /** + * Retrieves the {@link BlockState} associated with the given bone for rendering purposes. Returns {@code null} if + * there is no {@link BlockState} to render for this bone. + * + * @param bone the bone for which to retrieve the {@link BlockState} + * @return the {@link BlockState} relevant to the specified bone, or {@code null} if none exists + */ + public BlockState blockStateForBone(AzBone bone) { + return blockStateProvider.apply(bone); + } + + /** + * Determines the specific {@link ItemDisplayContext} to use for rendering the given {@link ItemStack} on the + * specified bone. By default, this method returns {@link ItemDisplayContext#NONE}. + * + * @param bone the bone where the {@link ItemStack} will be rendered + * @param stack the {@link ItemStack} to render + * @return the {@link ItemDisplayContext} to use for rendering + */ + protected ItemDisplayContext getTransformTypeForStack(AzBone bone, ItemStack stack) { + return ItemDisplayContext.NONE; + } + + /** + * Renders the given {@link ItemStack} for the specified bone in the rendering context. The rendering adjusts based + * on whether the animatable object is a {@link LivingEntity}. + * + * @param context the rendering pipeline context + * @param bone the bone where the {@link ItemStack} will be rendered + * @param itemStack the {@link ItemStack} to render + */ + protected void renderItemForBone(AzRendererPipelineContext context, AzBone bone, ItemStack itemStack) { + if (context.animatable() instanceof LivingEntity livingEntity) { + Minecraft.getInstance() + .getItemRenderer() + .renderStatic( + livingEntity, + itemStack, + getTransformTypeForStack(bone, itemStack), + false, + context.poseStack(), + context.multiBufferSource(), + livingEntity.level(), + context.packedLight(), + context.packedOverlay(), + livingEntity.getId() + ); + } else { + Minecraft.getInstance() + .getItemRenderer() + .renderStatic( + itemStack, + getTransformTypeForStack(bone, itemStack), + context.packedLight(), + context.packedOverlay(), + context.poseStack(), + context.multiBufferSource(), + Minecraft.getInstance().level, + context.animatable().hashCode() + ); + } + } + + /** + * Renders the given {@link BlockState} for the specified bone in the rendering context. The block is rendered with + * adjusted position and scale to fit within the bone's space. + * + * @param context the rendering pipeline context + * @param bone the bone where the {@link BlockState} will be rendered + * @param blockState the {@link BlockState} to render + */ + protected void renderBlockForBone(AzRendererPipelineContext context, AzBone bone, BlockState blockState) { + context.poseStack().pushPose(); + + context.poseStack().translate(-0.25f, -0.25f, -0.25f); + context.poseStack().scale(0.5f, 0.5f, 0.5f); + + Minecraft.getInstance() + .getBlockRenderer() + .renderSingleBlock( + blockState, + context.poseStack(), + context.multiBufferSource(), + context.packedLight(), + OverlayTexture.NO_OVERLAY + ); + + context.poseStack().popPose(); + } + +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java new file mode 100644 index 000000000..d91580b3b --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/render/layer/AzRenderLayer.java @@ -0,0 +1,42 @@ +package mod.azure.azurelib.core2.render.layer; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; + +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.AzRendererPipeline; +import mod.azure.azurelib.core2.render.AzRendererPipelineContext; + +/** + * Render layer base class for rendering additional layers of effects or textures over an existing model at runtime.
    + * Contains the base boilerplate and helper code for various render layer features + */ +public interface AzRenderLayer { + + /** + * This method is called by the {@link AzRendererPipeline} before rendering, immediately after + * {@link AzRendererPipeline#preRender} has been called.
    + * This allows for RenderLayers to perform pre-render manipulations such as hiding or showing bones + */ + void preRender(AzRendererPipelineContext context); + + /** + * This is the method that is actually called by the render for your render layer to function.
    + * This is called after the animatable has been rendered, but before supplementary rendering like nametags. + */ + void render(AzRendererPipelineContext context); + + /** + * This method is called by the {@link AzRendererPipeline} for each bone being rendered.
    + * This is a more expensive call, particularly if being used to render something on a different buffer.
    + * It does however have the benefit of having the matrix translations and other transformations already applied from + * render-time.
    + * It's recommended to avoid using this unless necessary.
    + *
    + * The {@link AzBone} in question has already been rendered by this stage.
    + *
    + * If you do use it, and you render something that changes the {@link VertexConsumer buffer}, you need to + * reset it back to the previous buffer using {@link MultiBufferSource#getBuffer} before ending the method + */ + void renderForBone(AzRendererPipelineContext context, AzBone bone); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/codec/AzListStreamCodec.java b/common/src/main/java/mod/azure/azurelib/core2/util/codec/AzListStreamCodec.java new file mode 100644 index 000000000..106620fb9 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/codec/AzListStreamCodec.java @@ -0,0 +1,35 @@ +package mod.azure.azurelib.core2.util.codec; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class AzListStreamCodec implements StreamCodec> { + + private final StreamCodec codec; + + public AzListStreamCodec(StreamCodec codec) { + this.codec = codec; + } + + @Override + public @NotNull List decode(FriendlyByteBuf buf) { + var size = buf.readByte(); + var list = new ArrayList(size); + + for (int i = 0; i < size; i++) { + list.add(codec.decode(buf)); + } + + return list; + } + + @Override + public void encode(FriendlyByteBuf buf, List elements) { + buf.writeByte(elements.size()); + elements.forEach(element -> codec.encode(buf, element)); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/state/State.java b/common/src/main/java/mod/azure/azurelib/core2/util/state/State.java new file mode 100644 index 000000000..4c486f639 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/state/State.java @@ -0,0 +1,21 @@ +package mod.azure.azurelib.core2.util.state; + +/** + * Represents a state within a state machine. A state defines the behavior that occurs when entering, updating, and + * exiting the state. The lifecycle of a state consists of three main methods:
    + *
      + *
    1. onEnter - Triggered when the state is entered, providing an opportunity to perform initialization.
    2. + *
    3. onUpdate - Called during state execution, typically to update or process logic related to the state.
    4. + *
    5. onExit - Triggered when transitioning out of the state, used for cleanup or finalization.
    6. + *
    + * + * @param the type of the context associated with the state, which must extend {@link StateMachineContext} + */ +public interface State { + + void onEnter(C context); + + void onUpdate(C context); + + void onExit(C context); +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachine.java b/common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachine.java new file mode 100644 index 000000000..e9eb62572 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachine.java @@ -0,0 +1,40 @@ +package mod.azure.azurelib.core2.util.state; + +/** + * Represents a state machine that handles transitions between different states. A state machine maintains a current + * state and allows transitions to new states, invoking lifecycle methods on each state during transitions. + * + * @param the type of the context associated with the state machine, which extends {@link StateMachineContext} + * @param the type of the states managed by the state machine, which extends {@link State} + */ +public abstract class StateMachine> { + + private final C reusableContext; + + private T state; + + public StateMachine(T initialState) { + this.state = initialState; + this.reusableContext = createContext(); + } + + protected abstract C createContext(); + + public void update(C context) { + state.onUpdate(context); + } + + public C getContext() { + return reusableContext; + } + + public T getState() { + return state; + } + + public void setState(T newState) { + state.onExit(reusableContext); + this.state = newState; + newState.onEnter(reusableContext); + } +} diff --git a/common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachineContext.java b/common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachineContext.java new file mode 100644 index 000000000..8c0b037c8 --- /dev/null +++ b/common/src/main/java/mod/azure/azurelib/core2/util/state/StateMachineContext.java @@ -0,0 +1,14 @@ +package mod.azure.azurelib.core2.util.state; + +/** + * Represents the contract for a state machine context. A state machine context serves as an intermediary object that + * provides necessary data and functionality to state machine components or processes. It is generally used to + * encapsulate and manage shared resources, state-related details, and other dependencies required during the lifecycle + * of state transitions within a state machine.
    + * Implementations of this interface can define custom context-specific properties and methods, tailored to the + * requirements of a specific state machine.
    + * The context is typically associated with the {@link State} and {@link StateMachine} interfaces. Implementing classes + * provide relevant properties or methods that a state or state machine would require during its lifecycle operations + * (e.g., onEnter, onUpdate, onExit for states). + */ +public interface StateMachineContext {} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/APIOnly.java b/common/src/main/java/mod/azure/azurelib/sblforked/APIOnly.java deleted file mode 100644 index 15d396a64..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/APIOnly.java +++ /dev/null @@ -1,20 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Methods marked with this annotation should only be used internally, or by abstract-subclasses. - * This is usually done to avoid accidentally overriding methods handled in the super class. - */ -@Retention(RetentionPolicy.SOURCE) -@Target(ElementType.METHOD) -public @interface APIOnly {} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/SBLConstants.java b/common/src/main/java/mod/azure/azurelib/sblforked/SBLConstants.java deleted file mode 100644 index 214308383..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/SBLConstants.java +++ /dev/null @@ -1,13 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked; - -import java.util.ServiceLoader; - -public class SBLConstants { - public static final SBLLoader SBL_LOADER = ServiceLoader.load(SBLLoader.class).findFirst().get(); -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/SBLLoader.java b/common/src/main/java/mod/azure/azurelib/sblforked/SBLLoader.java deleted file mode 100644 index 3923615a2..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/SBLLoader.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked; - -import com.mojang.serialization.Codec; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import org.jetbrains.annotations.ApiStatus; - -import java.util.Optional; -import java.util.function.Supplier; - -public interface SBLLoader { - void init(Object eventBus); - boolean isDevEnv(); - - @ApiStatus.Internal - Supplier> registerMemoryType(String id); - @ApiStatus.Internal - Supplier> registerMemoryType(String id, Optional> codec); - @ApiStatus.Internal - > Supplier> registerSensorType(String id, Supplier sensor); -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/SmartBrainOwner.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/SmartBrainOwner.java deleted file mode 100644 index 0baab1b88..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/SmartBrainOwner.java +++ /dev/null @@ -1,150 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api; - -import com.google.common.collect.ImmutableSet; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.schedule.Activity; -import mod.azure.azurelib.sblforked.APIOnly; -import mod.azure.azurelib.sblforked.api.core.BrainActivityGroup; -import mod.azure.azurelib.sblforked.api.core.SmartBrain; -import mod.azure.azurelib.sblforked.api.core.schedule.SmartBrainSchedule; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Implement this class for any entity you want to use the SmartBrain system.
    - * This interface contains the helper and constructive methods for initialising your entity's brain. - * - * @param Your entity - */ -public interface SmartBrainOwner> { - /** - * The list of {@link ExtendedSensor Sensors} that your entity will be using.
    - * Only supports ExtendedSensors. - * @return A {@link List} of {@link ExtendedSensor Sensors} that the entity will use to fill memories for tasks. - */ - List> getSensors(); - - /** - * Override this for tasks that ideally should always be running, regardless of anything else.
    - * Usually you'd use this for things like moving towards the current target, floating on water, looking at a certain target, etc.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category - *

    - * Tasks returned in this category take up the {@link Activity#CORE} activity category - * - * @return a {@link BrainActivityGroup} containing the core tasks your entity should run. - */ - default BrainActivityGroup getCoreTasks() { - return BrainActivityGroup.empty(); - } - - /** - * Override this for tasks that would normally run when your entity is doing nothing else.
    - * Usually you'd use this for things like random walking, setting targets, or just standing still and doing nothing at all.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category - *

    - * Tasks returned in this category take up the {@link Activity#IDLE} activity category - * - * @return a {@link BrainActivityGroup} containing the idle tasks your entity should run. - */ - default BrainActivityGroup getIdleTasks() { - return BrainActivityGroup.empty(); - } - - /** - * Override this to add the tasks that would normally run when your entity attacking something, or is otherwise in combat.
    - * Usually you'd use this for things melee attacking, invalidating attack targets, or setting walk targets based off the current attack target.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category - *

    - * Tasks returned in this category take up the {@link Activity#FIGHT} activity category - * - * @return a {@link BrainActivityGroup} containing the fight tasks your entity should run. - */ - default BrainActivityGroup getFightTasks() { - return BrainActivityGroup.empty(); - } - - /** - * Override this to add any additional tasks that don't fit into the categories already handled in the pre-defined activity task methods.
    - * Like all task groups, this method is optional, if you have no tasks that apply to this category - * - * @return a {@link Map} of Activities to BrainActivityGroups group containing the additional tasks your entity should run. - */ - default Map> getAdditionalTasks() { - return new Object2ObjectOpenHashMap<>(0); - } - - /** - * The activity categories that should always be running, regardless of any other conditions or situations.
    - * This is usually just left as {@link Activity#CORE}, but it can be modified as needed - * - * @return A {@link Set} of {@link Activity Activities} - */ - default Set getAlwaysRunningActivities() { - return ImmutableSet.of(Activity.CORE); - } - - /** - * The activity category that is used as a fallback, for when no other activity categories meet the conditions to run.
    - * This is almost always left as {@link Activity#IDLE}, but it can be modified as needed. - * - * @return The {@link Activity} to use as a fallback - */ - default Activity getDefaultActivity() { - return Activity.IDLE; - } - - /** - * Override this to return the order of activity categories the brain should attempt to run things in.
    - * The list is ordered in order of insertion - I.E. earlier elements have higher priority - * - * @return An ordered {@link List} of {@link Activity} categories - */ - default List getActivityPriorities() { - return ObjectArrayList.of(Activity.FIGHT, Activity.IDLE); - } - - /** - * Override this to do any additional work after the brain has been built and readied.
    - * By this stage, the brain has had all its memories, sensors, activities, and priorities set. - * - * @param brain The brain that the entity will be using. - */ - default void handleAdditionalBrainSetup(SmartBrain brain) {} - - /** - * Override this to return the {@link net.minecraft.world.entity.schedule.Schedule schedule} for your entity.
    - * This can be set at any time via {@link SmartBrain#setSchedule(SmartBrainSchedule)}, but it's recommended to - * do so statically if possible and provide it through this method - * @return The schedule for the brain, or null if no schedule - */ - @Nullable - default SmartBrainSchedule getSchedule() { - return null; - } - - /** - * SmartBrainOwners MUST call this from the entity's {@link LivingEntity#serverAiStep}, or {@link Mob#customServerAiStep} if extending Mob.
    - * Brains should only be ticked server side.
    - * This method does not need to be overridden. - * @param entity The brain owner - */ - @APIOnly - default void tickBrain(T entity) { - ((Brain)entity.getBrain()).tick((ServerLevel)entity.level(), entity); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/BrainActivityGroup.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/BrainActivityGroup.java deleted file mode 100644 index 5f5c70f68..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/BrainActivityGroup.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core; - -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.Behavior; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.schedule.Activity; -import mod.azure.azurelib.sblforked.api.SmartBrainOwner; - -import java.util.List; -import java.util.Set; - -public class BrainActivityGroup> { - private final Activity activity; - private int priorityStart = 0; - private final List> behaviours = new ObjectArrayList<>(); - private final Set, MemoryStatus>> activityStartMemoryConditions = new ObjectOpenHashSet<>(); - private Set> wipedMemoriesOnFinish = null; - - public BrainActivityGroup(Activity activity) { - this.activity = activity; - } - - public BrainActivityGroup priority(int priorityStart) { - this.priorityStart = priorityStart; - - return this; - } - - public BrainActivityGroup behaviours(Behavior... behaviours) { - this.behaviours.addAll(new ObjectArrayList<>(behaviours)); - - return this; - } - - public BrainActivityGroup onlyStartWithMemoryStatus(MemoryModuleType memory, MemoryStatus status) { - this.activityStartMemoryConditions.add(Pair.of(memory, status)); - - return this; - } - - public BrainActivityGroup wipeMemoriesWhenFinished(MemoryModuleType... memories) { - if (this.wipedMemoriesOnFinish == null) { - this.wipedMemoriesOnFinish = new ObjectOpenHashSet<>(memories); - } - else { - this.wipedMemoriesOnFinish.addAll(new ObjectOpenHashSet<>(memories)); - } - - return this; - } - - public BrainActivityGroup requireAndWipeMemoriesOnUse(MemoryModuleType... memories) { - for (MemoryModuleType memory : memories) { - onlyStartWithMemoryStatus(memory, MemoryStatus.VALUE_PRESENT); - } - - wipeMemoriesWhenFinished(memories); - - return this; - } - - public Activity getActivity() { - return this.activity; - } - - public List> getBehaviours() { - return this.behaviours; - } - - public int getPriorityStart() { - return this.priorityStart; - } - - public Set, MemoryStatus>> getActivityStartMemoryConditions() { - return this.activityStartMemoryConditions; - } - - public Set> getWipedMemoriesOnFinish() { - return this.wipedMemoriesOnFinish != null ? this.wipedMemoriesOnFinish : Set.of(); - } - - public ImmutableList>> pairBehaviourPriorities() { - int priority = this.priorityStart; - ImmutableList.Builder>> pairedBehaviours = ImmutableList.builder(); - - for (Behavior behaviour : this.behaviours) { - pairedBehaviours.add(Pair.of(priority++, behaviour)); - } - - return pairedBehaviours.build(); - } - - public static > BrainActivityGroup empty() { - return new BrainActivityGroup(Activity.REST); - } - - public static > BrainActivityGroup coreTasks(Behavior... behaviours) { - return new BrainActivityGroup(Activity.CORE).priority(0).behaviours(behaviours); - } - - public static > BrainActivityGroup idleTasks(Behavior... behaviours) { - return new BrainActivityGroup(Activity.IDLE).priority(10).behaviours(behaviours); - } - - public static > BrainActivityGroup fightTasks(Behavior... behaviours) { - return new BrainActivityGroup(Activity.FIGHT).priority(10).behaviours(behaviours).requireAndWipeMemoriesOnUse(MemoryModuleType.ATTACK_TARGET); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrain.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrain.java deleted file mode 100644 index 9d6eea5c8..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrain.java +++ /dev/null @@ -1,436 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core; - -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Codec; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.behavior.Behavior; -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import net.minecraft.world.entity.ai.behavior.GateBehavior; -import net.minecraft.world.entity.ai.memory.ExpirableValue; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.sensing.Sensor; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.schedule.Activity; -import net.minecraft.world.entity.schedule.Schedule; -import mod.azure.azurelib.sblforked.api.SmartBrainOwner; -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; -import mod.azure.azurelib.sblforked.api.core.schedule.SmartBrainSchedule; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.object.BrainBehaviourConsumer; -import mod.azure.azurelib.sblforked.object.BrainBehaviourPredicate; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.apache.commons.lang3.mutable.MutableObject; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.Consumer; -import java.util.stream.Stream; - -/** - * Supercedes vanilla's {@link Brain}. One of the core components of the SBL - * library.
    - * Any entity that returns a {@link SmartBrainProvider} from - * {@link LivingEntity#brainProvider()} will have one of these. - * - * @param The entity - */ -public class SmartBrain> extends Brain { - private final List> expirableMemories = new ObjectArrayList<>(); - private final List> behaviours = new ObjectArrayList<>(); - private final List>, ExtendedSensor>> sensors = new ObjectArrayList<>(); - private SmartBrainSchedule schedule = null; - - private boolean sortBehaviours = false; - - public SmartBrain(List> memories, List> sensors, @Nullable List> taskList) { - super(memories, ImmutableList.of(), ImmutableList.of(), SmartBrain::emptyBrainCodec); - - for (ExtendedSensor sensor : sensors) { - this.sensors.add(Pair.of((SensorType)sensor.type(), sensor)); - } - - if (taskList != null) { - for (BrainActivityGroup group : taskList) { - addActivity(group); - } - } - } - - @Override - public void tick(ServerLevel level, E entity) { - entity.level().getProfiler().push("SmartBrain"); - - if (this.sortBehaviours) - this.behaviours.sort(Comparator.comparingInt(ActivityBehaviours::priority)); - - forgetOutdatedMemories(); - tickSensors(level, entity); - checkForNewBehaviours(level, entity); - tickRunningBehaviours(level, entity); - findAndSetActiveActivity(entity); - - entity.level().getProfiler().pop(); - - if (entity instanceof Mob mob) - mob.setAggressive(BrainUtils.hasMemory(mob, MemoryModuleType.ATTACK_TARGET)); - } - - private void findAndSetActiveActivity(E entity) { - if (this.schedule != null) { - Activity scheduledActivity = this.schedule.tick(entity); - - if (scheduledActivity != null && !getActiveActivities().contains(scheduledActivity) && activityRequirementsAreMet(scheduledActivity)) { - setActiveActivity(scheduledActivity); - - return; - } - } - - setActiveActivityToFirstValid(entity.getActivityPriorities()); - } - - private void tickSensors(ServerLevel level, E entity) { - for (Pair>, ExtendedSensor> sensor : this.sensors) { - sensor.getSecond().tick(level, entity); - } - } - - private void checkForNewBehaviours(ServerLevel level, E entity) { - long gameTime = level.getGameTime(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - if (getActiveActivities().contains(pair.getFirst())) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.STOPPED) - behaviour.tryStart(level, entity, gameTime); - } - } - } - } - } - - private void tickRunningBehaviours(ServerLevel level, E entity) { - long gameTime = level.getGameTime(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.tickOrStop(level, entity, gameTime); - } - } - } - } - - @Override - public void forgetOutdatedMemories() { - Iterator> expirable = this.expirableMemories.iterator(); - - while (expirable.hasNext()) { - MemoryModuleType memoryType = expirable.next(); - Optional> memory = memories.get(memoryType); - - if (memory.isEmpty()) { - expirable.remove(); - } - else { - ExpirableValue value = memory.get(); - - if (!value.canExpire()) { - expirable.remove(); - } - else if (value.hasExpired()) { - expirable.remove(); - eraseMemory(memoryType); - } - else { - value.tick(); - } - } - } - } - - @Override - public void stopAll(ServerLevel level, E entity) { - long gameTime = level.getGameTime(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.doStop(level, entity, gameTime); - } - } - } - } - - @Override - public Optional getMemory(MemoryModuleType type) { - return (Optional) this.memories.computeIfAbsent(type, key -> Optional.empty()).map(ExpirableValue::getValue); - } - - @Override - public void setMemoryInternal(MemoryModuleType memoryType, Optional> memory) { - if (memory.isPresent() && memory.get().getValue()instanceof Collection collection && collection.isEmpty()) - memory = Optional.empty(); - - this.memories.put(memoryType, memory); - - if (memory.isPresent() && memory.get().canExpire() && !this.expirableMemories.contains(memoryType)) - this.expirableMemories.add(memoryType); - } - - @Override - public boolean isMemoryValue(MemoryModuleType memoryType, U memory) { - Optional value = getMemory(memoryType); - - return value.isPresent() && value.get().equals(memory); - } - - private static > Codec> emptyBrainCodec() { - MutableObject>> brainCodec = new MutableObject<>(); - - brainCodec.setValue(Codec.unit(() -> new Brain<>(ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), brainCodec::getValue))); - - return brainCodec.getValue(); - } - - private static > List>> convertSensorsToTypes(List> sensors) { - List>> types = new ObjectArrayList<>(sensors.size()); - - for (ExtendedSensor sensor : sensors) { - types.add((SensorType)sensor.type()); - } - - return types; - } - - @Override - public Brain copyWithoutBehaviors() { - SmartBrain brain = new SmartBrain<>(this.memories.keySet().stream().toList(), this.sensors.stream().map(pair -> (ExtendedSensor) pair.getSecond()).toList(), null); - - for (Map.Entry, Optional>> entry : this.memories.entrySet()) { - MemoryModuleType memoryType = entry.getKey(); - - if (entry.getValue().isPresent()) - brain.memories.put(memoryType, entry.getValue()); - } - - return brain; - } - - @Override - public List> getRunningBehaviors() { - List> runningBehaviours = new ObjectArrayList<>(); - - for (ActivityBehaviours behaviourGroup : this.behaviours) { - for (Pair>> pair : behaviourGroup.behaviours) { - for (BehaviorControl behaviour : pair.getSecond()) { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - runningBehaviours.add(behaviour); - } - } - } - - return runningBehaviours; - } - - /** - * Returns a stream of all {@link BehaviorControl Behaviours} registered to this brain - */ - public Stream> getBehaviours() { - return this.behaviours.stream().map(ActivityBehaviours::behaviours).flatMap(list -> list.stream().map(Pair::getSecond).flatMap(List::stream)); - } - - @Override - public void removeAllBehaviors() { - this.behaviours.clear(); - } - - @Override - public void addActivityAndRemoveMemoriesWhenStopped(Activity activity, ImmutableList>> tasks, Set, MemoryStatus>> memorieStatuses, Set> memoryTypes) { - this.activityRequirements.put(activity, memorieStatuses); - - if (!memoryTypes.isEmpty()) - this.activityMemoriesToEraseWhenStopped.put(activity, memoryTypes); - - for (Pair> pair : tasks) { - addBehaviour(pair.getFirst(), activity, pair.getSecond()); - } - } - - /** - * Adds a full {@link BrainActivityGroup} to the brain, inclusive of activities and conditions - */ - public void addActivity(BrainActivityGroup activityGroup) { - addActivityAndRemoveMemoriesWhenStopped(activityGroup.getActivity(), activityGroup.pairBehaviourPriorities(), activityGroup.getActivityStartMemoryConditions(), activityGroup.getWipedMemoriesOnFinish()); - } - - /** - * Add a behaviour to the behaviours list of this brain. - * - * @param priority The behaviour's priority value - * @param activity The behaviour's activity category - * @param behaviour The behaviour instance - */ - public void addBehaviour(int priority, Activity activity, BehaviorControl behaviour) { - for (ActivityBehaviours behaviourGroup : this.behaviours) { - if (behaviourGroup.priority == priority) { - for (Pair>> pair : behaviourGroup.behaviours) { - if (pair.getFirst() == activity) { - pair.getSecond().add(behaviour); - - return; - } - } - - behaviourGroup.behaviours.add(Pair.of(activity, ObjectArrayList.of(behaviour))); - - return; - } - } - - this.behaviours.add(new ActivityBehaviours<>(priority, ObjectArrayList.of(Pair.of(activity, ObjectArrayList.>of(behaviour))))); - this.sortBehaviours = true; - } - - /** - * Removes any behaviours matching the given predicate from the provided brain.
    - * Removed behaviours are stopped prior to removal - * @param entity The owner of the brain - * @param predicate The predicate checked for each (priority, activity, behaviour) - */ - public void removeBehaviour(E entity, BrainBehaviourPredicate predicate) { - for (ActivityBehaviours behaviourGroup : this.behaviours) { - int priority = behaviourGroup.priority; - - for (Pair>> pair : behaviourGroup.behaviours) { - Activity activity = pair.getFirst(); - - for (Iterator> iterator = pair.getSecond().iterator(); iterator.hasNext();) { - BehaviorControl behaviour = iterator.next(); - - checkBehaviour(priority, activity, behaviour, null, predicate, () -> { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.doStop((ServerLevel)entity.level(), entity, entity.level().getGameTime()); - - iterator.remove(); - }); - } - } - } - } - - /** - * Sets a {@link SmartBrainSchedule} for this brain, for scheduled functionality - * @param schedule The schedule to set for the brain - * @return this - */ - public SmartBrain setSchedule(SmartBrainSchedule schedule) { - this.schedule = schedule; - - return this; - } - - /** - * @return The {@link SmartBrainSchedule schedule} of this brain - */ - @Override - public SmartBrainSchedule getSchedule() { - return this.schedule; - } - - /** - * Cheekily (and conveniently) uses the {@link SmartBrainSchedule schedule} system to schedule a delayed runnable for this entity/brain. - * @param delay The delay (in ticks) before running the task - * @param task The task to run at the given tick - */ - public void scheduleTask(E brainOwner, int delay, Consumer task) { - if (this.schedule == null) - this.schedule = new SmartBrainSchedule(); - - this.schedule.scheduleTask(brainOwner, delay, (Consumer)task); - } - - private static void checkBehaviour(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parentBehaviour, BrainBehaviourPredicate predicate, Runnable callback) { - if (predicate.isBehaviour(priority, activity, behaviour, parentBehaviour)) { - callback.run(); - } - else if (behaviour instanceof GateBehavior groupBehaviour) { - for (Iterator> childBehaviourIterator = groupBehaviour.behaviors.iterator(); childBehaviourIterator.hasNext();) { - checkBehaviour(priority, activity, childBehaviourIterator.next(), groupBehaviour, predicate, childBehaviourIterator::remove); - } - - if (!groupBehaviour.behaviors.iterator().hasNext()) - callback.run(); - } - else if (behaviour instanceof GroupBehaviour groupBehaviour) { - for (Iterator> childBehaviourIterator = groupBehaviour.getBehaviours(); childBehaviourIterator.hasNext();) { - checkBehaviour(priority, activity, childBehaviourIterator.next(), groupBehaviour, predicate, childBehaviourIterator::remove); - } - - if (!groupBehaviour.getBehaviours().hasNext()) - callback.run(); - } - } - - /** - * Loops over all {@link BehaviorControl Behaviours} registered to this brain, calling the consumer for each - * @param consumer The consumer called for each (priority, activity, behaviour) - */ - public void forEachBehaviour(BrainBehaviourConsumer consumer) { - for (ActivityBehaviours behavioursGroup : this.behaviours) { - int priority = behavioursGroup.priority(); - - for (Pair>> behaviourList : behavioursGroup.behaviours()) { - Activity activity = behaviourList.getFirst(); - - for (BehaviorControl behaviour : behaviourList.getSecond()) { - consumeBehaviour(priority, activity, behaviour, null, consumer); - } - } - } - } - - private static void consumeBehaviour(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parentBehaviour, BrainBehaviourConsumer consumer) { - consumer.consume(priority, activity, behaviour, parentBehaviour); - - if (behaviour instanceof GateBehavior groupBehaviour) { - groupBehaviour.behaviors.stream().forEach(childBehaviour -> consumeBehaviour(priority, activity, (BehaviorControl)childBehaviour, groupBehaviour, consumer)); - } - else if (behaviour instanceof GroupBehaviour groupBehaviour) { - groupBehaviour.getBehaviours().forEachRemaining(childBehaviour -> consumeBehaviour(priority, activity, (BehaviorControl)childBehaviour, groupBehaviour, consumer)); - } - } - - /** - * Adds an {@link ExtendedSensor} to this brain - */ - public void addSensor(ExtendedSensor sensor) { - SensorType> sensorType = (SensorType)sensor.type(); - - this.sensors.add(Pair.of(sensorType, sensor)); - } - - /** - * Not supported, use {@link SmartBrain#setSchedule(SmartBrainSchedule)} instead - */ - @Deprecated(forRemoval = true) - @Override - public final void setSchedule(Schedule schedule) {} - - private record ActivityBehaviours> (int priority, List>>> behaviours) {} -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrainProvider.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrainProvider.java deleted file mode 100644 index aede4d53d..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/SmartBrainProvider.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core; - -import com.google.common.collect.ImmutableList; -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Dynamic; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.behavior.Behavior; -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import net.minecraft.world.entity.ai.behavior.GateBehavior; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.schedule.Activity; -import mod.azure.azurelib.sblforked.api.SmartBrainOwner; -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * The provider of {@link SmartBrain SmartBrains}. All entities intending to - * utilise this library should return a new instance of this in - * {@link LivingEntity#brainProvider()}
    - * All entities that use this provider use SmartBrains. - * - * @param The entity - */ -public class SmartBrainProvider> extends Brain.Provider { - private static final Map, ImmutableList>> BRAIN_MEMORY_CACHE = new Object2ObjectOpenHashMap<>(); - - private final E owner; - - private final boolean nonStaticMemories; - - /** - * @param owner The owner of the brain - */ - public SmartBrainProvider(E owner) { - this(owner, false); - } - - /** - * @param owner The owner of the brain - * @param nonStaticMemories Whether the entity has different behaviours or - * sensors depending on the entity instance - */ - public SmartBrainProvider(E owner, boolean nonStaticMemories) { - super(List.of(), List.of()); - - this.owner = owner; - this.nonStaticMemories = nonStaticMemories; - } - - @Override - public final SmartBrain makeBrain(Dynamic codecLoader) { - List> sensors = this.owner.getSensors(); - List> taskList = compileTasks(); - ImmutableList> memories; - - if (!this.nonStaticMemories && BRAIN_MEMORY_CACHE.containsKey(this.owner.getType())) { - memories = BRAIN_MEMORY_CACHE.get(this.owner.getType()); - } - else { - memories = createMemoryList(taskList, sensors); - - if (!this.nonStaticMemories) - BRAIN_MEMORY_CACHE.put((EntityType)this.owner.getType(), memories); - } - - SmartBrain brain = new SmartBrain(memories, sensors, taskList); - - finaliseBrain(brain); - - return brain; - } - - private ImmutableList> createMemoryList(List> taskList, List> sensors) { - Set> memoryTypes = new ObjectOpenHashSet<>(); - - taskList.forEach(activityGroup -> activityGroup.getBehaviours().forEach(behavior -> collectMemoriesFromTask(memoryTypes, behavior))); - sensors.forEach(sensor -> memoryTypes.addAll(sensor.memoriesUsed())); - - return ImmutableList.copyOf(memoryTypes); - } - - private void collectMemoriesFromTask(Set> memories, BehaviorControl behaviour) { - if (behaviour instanceof GateBehavior gateBehaviour) { - gateBehaviour.behaviors.stream().forEach(subBehaviour -> collectMemoriesFromTask(memories, subBehaviour)); - } - else if (behaviour instanceof GroupBehaviour groupBehaviour) { - groupBehaviour.getBehaviours().forEachRemaining(subBehaviour -> collectMemoriesFromTask(memories, subBehaviour)); - } - else if (behaviour instanceof Behavior behaviour2) { - memories.addAll(behaviour2.entryCondition.keySet()); - } - } - - private List> compileTasks() { - List> tasks = new ObjectArrayList<>(); - BrainActivityGroup activityGroup; - - if (!(activityGroup = owner.getCoreTasks()).getBehaviours().isEmpty()) - tasks.add(activityGroup); - - if (!(activityGroup = owner.getIdleTasks()).getBehaviours().isEmpty()) - tasks.add(activityGroup); - - if (!(activityGroup = owner.getFightTasks()).getBehaviours().isEmpty()) - tasks.add(activityGroup); - - tasks.addAll(owner.getAdditionalTasks().values()); - - return tasks; - } - - private void finaliseBrain(SmartBrain brain) { - brain.setCoreActivities(this.owner.getAlwaysRunningActivities()); - brain.setDefaultActivity(this.owner.getDefaultActivity()); - brain.useDefaultActivity(); - brain.setSchedule(this.owner.getSchedule()); - this.owner.handleAdditionalBrainSetup(brain); - } - - /** - * Use one of the startup 'getTasks' methods if adding at startup, or else use {@link mod.azure.azurelib.sblforked.util.BrainUtils#addActivity(Brain, BrainActivityGroup)} - */ - @Deprecated(forRemoval = true) - protected void addActivity(SmartBrain brain, Activity activity, BrainActivityGroup activityGroup) { - brain.activityRequirements.put(activity, activityGroup.getActivityStartMemoryConditions()); - - if (!activityGroup.getWipedMemoriesOnFinish().isEmpty()) - brain.activityMemoriesToEraseWhenStopped.put(activity, activityGroup.getWipedMemoriesOnFinish()); - - for (Pair> pair : activityGroup.pairBehaviourPriorities()) { - brain.addBehaviour(pair.getFirst(), activity, pair.getSecond()); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/AllApplicableBehaviours.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/AllApplicableBehaviours.java deleted file mode 100644 index c29ac491a..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/AllApplicableBehaviours.java +++ /dev/null @@ -1,126 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import mod.azure.azurelib.sblforked.object.SBLShufflingList; -import org.jetbrains.annotations.Nullable; - -import java.util.Set; -import java.util.stream.Collectors; - -/** - * Group behaviour that attempts to run all sub-behaviours in order, running any that apply.
    - * This allows for wrapping entire groups of behaviours in overarching conditions or nesting them in other groups.
    - * This will count this behaviour as running if any of the child behaviours are running. - * @param The entity - */ -public final class AllApplicableBehaviours extends GroupBehaviour { - public AllApplicableBehaviours(Pair, Integer>... behaviours) { - super(behaviours); - } - - public AllApplicableBehaviours(ExtendedBehaviour... behaviours) { - super(behaviours); - } - - @Override - protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { - if (this.cooldownFinishedAt > gameTime || !hasRequiredMemories(entity) || !this.startCondition.test(entity) || !checkExtraStartConditions(level, entity)) - return false; - - return (this.runningBehaviour = pickBehaviour(level, entity, gameTime, this.behaviours)) != null; - } - - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour(ServerLevel level, E entity, long gameTime, SBLShufflingList> extendedBehaviours) { - ExtendedBehaviour lastSuccessfulBehaviour = null; - - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (behaviour.tryStart(level, entity, gameTime)) - lastSuccessfulBehaviour = behaviour; - } - - return lastSuccessfulBehaviour; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - boolean stillOperational = false; - - for (ExtendedBehaviour behaviour : this.behaviours) { - stillOperational |= behaviour.getStatus() == Status.RUNNING && behaviour.canStillUse((ServerLevel)entity.level(), entity, entity.level().getGameTime()); - } - - return stillOperational; - } - - @Override - protected boolean timedOut(long gameTime) { - boolean timedOut = true; - - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING && !behaviour.timedOut(gameTime)) - timedOut = false; - } - - return timedOut; - } - - @Override - protected void tick(ServerLevel level, E owner, long gameTime) { - boolean stillRunning = false; - - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING) { - behaviour.tickOrStop(level, owner, gameTime); - - if (behaviour.getStatus() != Status.STOPPED) - stillRunning = true; - } - } - - if (!stillRunning) - doStop(level, owner, gameTime); - } - - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - this.cooldownFinishedAt = gameTime + cooldownProvider.apply(entity); - - this.taskStopCallback.accept(entity); - stop(entity); - - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING) - behaviour.doStop(level, entity, gameTime); - } - } - - @Override - public Status getStatus() { - for (ExtendedBehaviour behaviour : this.behaviours) { - if (behaviour.getStatus() == Status.RUNNING) - return Status.RUNNING; - } - - return Status.STOPPED; - } - - @Override - public String toString() { - final Set> activeBehaviours = this.behaviours.stream() - .filter(behaviorControl -> behaviorControl.getStatus() == Status.RUNNING) - .collect(Collectors.toSet()); - - return "(" + getClass().getSimpleName() + "): " + activeBehaviours; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/DelayedBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/DelayedBehaviour.java deleted file mode 100644 index 0936262c0..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/DelayedBehaviour.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; - -import java.util.function.Consumer; - -/** - * An abstract behaviour used for tasks that should have a start, and then a followup delayed action.
    - * This is most useful for things like attacks that have associated animations, or action which require a charge up or prep time.
    - * - * @param The entity - */ -public abstract class DelayedBehaviour extends ExtendedBehaviour { - protected final int delayTime; - protected long delayFinishedAt = 0; - protected Consumer delayedCallback = entity -> {}; - - public DelayedBehaviour(int delayTicks) { - this.delayTime = delayTicks; - - runFor(entity -> Math.max(delayTicks, 60)); - } - - /** - * A callback for when the delayed action is called. - * @param callback The callback - * @return this - */ - public final DelayedBehaviour whenActivating(Consumer callback) { - this.delayedCallback = callback; - - return this; - } - - @Override - protected final void start(ServerLevel level, E entity, long gameTime) { - if (this.delayTime > 0) { - this.delayFinishedAt = gameTime + this.delayTime; - - super.start(level, entity, gameTime); - } - else { - super.start(level, entity, gameTime); - doDelayedAction(entity); - } - } - - @Override - protected final void stop(ServerLevel level, E entity, long gameTime) { - super.stop(level, entity, gameTime); - - this.delayFinishedAt = 0; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.delayFinishedAt >= entity.level().getGameTime(); - } - - @Override - protected final void tick(ServerLevel level, E entity, long gameTime) { - super.tick(level, entity, gameTime); - - if (this.delayFinishedAt <= gameTime) { - doDelayedAction(entity); - this.delayedCallback.accept(entity); - } - } - - /** - * The action to take once the delay period has elapsed. - * - * @param entity The owner of the brain - */ - protected void doDelayedAction(E entity) {} -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/ExtendedBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/ExtendedBehaviour.java deleted file mode 100644 index 8db53125b..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/ExtendedBehaviour.java +++ /dev/null @@ -1,333 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.behavior.Behavior; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.APIOnly; - -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * An extension of the base Behavior class that is used for tasks in the brain - * system.
    - * This extension auto-handles some boilerplate and adds in some additional - * auto-handled functions:
    - *
      - *
    • Task start and stop callbacks for additional entity-interactions
    • - *
    • A functional implementation of a duration provider
    • - *
    • A functional implementation of a cooldown provider
    • - *
    - * Ideally, all custom behaviours should use at least this class as a base, - * instead of the core Behavior class - * - * @param Your entity - */ -public abstract class ExtendedBehaviour extends Behavior { - protected Predicate startCondition = entity -> true; - protected Predicate stopCondition = entity -> false; - protected Consumer taskStartCallback = entity -> {}; - protected Consumer taskStopCallback = entity -> {}; - - protected Function runtimeProvider = entity -> 60; - protected Function cooldownProvider = entity -> 0; - protected long cooldownFinishedAt = 0; - - public ExtendedBehaviour() { - super(new Object2ObjectOpenHashMap<>()); - - for (Pair, MemoryStatus> memoryReq : getMemoryRequirements()) { - this.entryCondition.put(memoryReq.getFirst(), memoryReq.getSecond()); - } - } - - /** - * A callback for when the task begins. Use this to trigger effects or handle - * things when the entity activates this task. - * - * @param callback The callback - * @return this - */ - public final ExtendedBehaviour whenStarting(Consumer callback) { - this.taskStartCallback = callback; - - return this; - } - - /** - * A callback for when the task stops. Use this to trigger effects or handle - * things when the entity ends this task.
    - * Note that the task stopping does not necessarily mean it was successful. - * - * @param callback The callback - * @return this - */ - public final ExtendedBehaviour whenStopping(Consumer callback) { - this.taskStopCallback = callback; - - return this; - } - - /** - * Set the length that the task should run for, once activated. The value used - * is in ticks. - * - * @param timeProvider A function for the tick value - * @return this - */ - public final ExtendedBehaviour runFor(Function timeProvider) { - this.runtimeProvider = timeProvider; - - return this; - } - - /** - * Set the length that the task should wait for between activations. This is the - * time between when the task stops, and it is able to start again. The value - * used is in ticks - * - * @param timeProvider A function for the tick value - * @return this - */ - public final ExtendedBehaviour cooldownFor(Function timeProvider) { - this.cooldownProvider = timeProvider; - - return this; - } - - /** - * Set an additional condition for the behaviour to be able to start. Useful for - * dynamically predicating behaviours.
    - * Prevents this behaviour starting unless this predicate returns true. - * - * @param predicate The predicate - * @return this - */ - public final ExtendedBehaviour startCondition(Predicate predicate) { - this.startCondition = predicate; - - return this; - } - - /** - * Set an automatic condition for the behavior to stop. Useful for dynamically - * stopping behaviours. Has no effect on one-shot behaviours that don't have a - * runtime.
    - * Stops the behaviour if it is active and this predicate returns true. - * - * @param predicate The predicate - * @return this - */ - public final ExtendedBehaviour stopIf(Predicate predicate) { - this.stopCondition = predicate; - - return this; - } - - /** - * Defines a maximum value timeout period for this behaviour. - *

    Functionally, this means that the behaviour will not timeout, and will rely on other factors to stop (such as memory conditions failing)

    - * @return this - */ - public final ExtendedBehaviour noTimeout() { - return runFor(entity -> Integer.MAX_VALUE); - } - - @Override - public final boolean tryStart(ServerLevel level, E entity, long gameTime) { - if (!doStartCheck(level, entity, gameTime)) - return false; - - this.status = Status.RUNNING; - this.endTimestamp = gameTime + this.runtimeProvider.apply(entity); - - start(level, entity, gameTime); - - return true; - } - - @APIOnly - protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { - return this.cooldownFinishedAt <= gameTime && hasRequiredMemories(entity) && this.startCondition.test(entity) - && checkExtraStartConditions(level, entity); - } - - /** - * Check any extra conditions required for this behaviour to start.
    - * By this stage, memory conditions from - * {@link ExtendedBehaviour#getMemoryRequirements()} have already been checked. - * - * @param level The level the entity is in - * @param entity The owner of the brain - * @return Whether the conditions have been met to start the behaviour - */ - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return true; - } - - /** - * The root stop method for when this behaviour stops. This method should only - * be overridden by other abstract subclasses.
    - * If overriding, ensure you either call {@code super} or manually call - * {@code stop(E)} yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - */ - @APIOnly - @Override - protected void start(ServerLevel level, E entity, long gameTime) { - this.taskStartCallback.accept(entity); - start(entity); - } - - /** - * Override this for custom behaviour implementations. This is a safe endpoint - * for behaviours so that all required auto-handling is safely contained without - * super calls.
    - * This is called when the behaviour is to start. Set up any instance variables - * needed or perform the required actions.
    - * By this stage any memory requirements set in - * {@link ExtendedBehaviour#getMemoryRequirements()} are true, so any memories - * paired with {@link MemoryStatus#VALUE_PRESENT} are safe to retrieve. - * - * @param entity The entity being handled (I.E. the owner of the brain) - */ - protected void start(E entity) { - } - - /** - * The root stop method for when this behaviour stops. This method should only - * be overridden by other abstract subclasses.
    - * If overriding, ensure you either call {@code super} or manually call - * {@code stop(E)} yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - */ - @APIOnly - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - this.cooldownFinishedAt = gameTime + cooldownProvider.apply(entity); - - this.taskStopCallback.accept(entity); - stop(entity); - } - - /** - * Override this for custom behaviour implementations. This is a safe endpoint - * for behaviours so that all required auto-handling is safely contained without - * super calls.
    - * This is called when the behaviour is to stop. Close off any instanced - * variables and such here, ready for the next start. - * - * @param entity The entity being handled (I.E. the owner of the brain) - */ - protected void stop(E entity) { - } - - /** - * The root method to check if this behaviour should continue running. This - * method should only be overridden by other abstract subclasses.
    - * If overriding, ensure you either call super or manually call the - * {@link ExtendedBehaviour#stopCondition} check yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - * @return Whether the behaviour should continue ticking - */ - @Override - protected boolean canStillUse(ServerLevel level, E entity, long gameTime) { - return shouldKeepRunning(entity) && !this.stopCondition.test(entity); - } - - /** - * Check whether the behaviour should continue running. This is checked before - * {@link ExtendedBehaviour#tick(E)}.
    - * Memories are not guaranteed to be in their required state here, so if you - * have required memories, it might be worth checking them here. - * - * @param entity The owner of the brain - * @return Whether the behaviour should continue ticking - */ - protected boolean shouldKeepRunning(E entity) { - return false; - } - - /** - * The root tick method for when this behaviour ticks. This method should only - * be overridden by other abstract subclasses.
    - * If overriding, ensure you either call {@code super} or manually call - * {@code tick(E)} yourself. - * - * @param level The level the entity is in - * @param entity The entity the brain belongs to - * @param gameTime The current gameTime (in ticks) of the level - */ - @APIOnly - @Override - protected void tick(ServerLevel level, E entity, long gameTime) { - tick(entity); - } - - /** - * Override this for custom behaviour implementations. This is a safe endpoint - * for behaviours so that all required auto-handling is safely contained without - * super calls.
    - * This is called when the behaviour is ticked. Be aware this is called every - * tick, so use tick reduction if needed to minimise performance impacts of - * goals.
    - * NOTE: Memory requirements are not guaranteed at this stage. If you are - * retrieving brain memories, you'll need to check their presence before use. - * - * @param entity The entity being handled (I.E. the owner of the brain) - */ - protected void tick(E entity) { - } - - @Override - protected boolean timedOut(long gameTime) { - return super.timedOut(gameTime); - } - - @APIOnly - @Override - public final boolean hasRequiredMemories(E entity) { - Brain brain = entity.getBrain(); - - for (Pair, MemoryStatus> memoryPair : getMemoryRequirements()) { - if (!brain.checkMemory(memoryPair.getFirst(), memoryPair.getSecond())) - return false; - } - - return true; - } - - /** - * The list of memory requirements this task has prior to starting. This - * outlines the approximate state the brain should be in, in order to allow this - * behaviour to run.
    - * Bonus points if it's a statically-initialised list. - * - * @return The {@link List} of {@link MemoryModuleType Memories} and their - * associated required {@link MemoryStatus status} - */ - protected abstract List, MemoryStatus>> getMemoryRequirements(); -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/FirstApplicableBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/FirstApplicableBehaviour.java deleted file mode 100644 index 260783d76..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/FirstApplicableBehaviour.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import mod.azure.azurelib.sblforked.object.SBLShufflingList; -import org.jetbrains.annotations.Nullable; - -/** - * Group behaviour that attempts to run all sub-behaviours in order, until the first successful one. - * @param The entity - */ -public final class FirstApplicableBehaviour extends GroupBehaviour { - public FirstApplicableBehaviour(Pair, Integer>... behaviours) { - super(behaviours); - } - - public FirstApplicableBehaviour(ExtendedBehaviour... behaviours) { - super(behaviours); - } - - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour(ServerLevel level, E entity, long gameTime, SBLShufflingList> extendedBehaviours) { - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (behaviour.tryStart(level, entity, gameTime)) - return behaviour; - } - - return null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/GroupBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/GroupBehaviour.java deleted file mode 100644 index b0d069c9c..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/GroupBehaviour.java +++ /dev/null @@ -1,107 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.object.SBLShufflingList; -import org.jetbrains.annotations.Nullable; - -import java.util.Iterator; -import java.util.List; - -/** - * Functional replacement to {@link net.minecraft.world.entity.ai.behavior.GateBehavior} due to the very poor way it is implemented.
    - * In particular, this allows nesting of group behaviours without breaking behaviour flow entirely.
    - * It also allows for utilising the various callbacks and conditions that {@link ExtendedBehaviour} offers.
    - * NOTE: Only supports ExtendedBehaviour implementations as sub-behaviours. This is due to access-modifiers on the vanilla behaviours making this prohibitively annoying to work with. - */ -public abstract class GroupBehaviour extends ExtendedBehaviour { - protected final SBLShufflingList> behaviours; - - @Nullable - protected ExtendedBehaviour runningBehaviour = null; - - public GroupBehaviour(Pair, Integer>... behaviours) { - this.behaviours = new SBLShufflingList<>(behaviours); - } - - public GroupBehaviour(ExtendedBehaviour... behaviours) { - this.behaviours = new SBLShufflingList<>(); - - for (ExtendedBehaviour behaviour : behaviours) { - this.behaviours.add(behaviour, 1); - } - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - public Iterator> getBehaviours() { - return this.behaviours.iterator(); - } - - @Nullable - protected abstract ExtendedBehaviour pickBehaviour(ServerLevel level, E entity, long gameTime, SBLShufflingList> behaviours); - - @Override - protected boolean doStartCheck(ServerLevel level, E entity, long gameTime) { - if (!super.doStartCheck(level, entity, gameTime)) - return false; - - return (this.runningBehaviour = pickBehaviour(level, entity, gameTime, this.behaviours)) != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.runningBehaviour != null && this.runningBehaviour.canStillUse((ServerLevel)entity.level(), entity, entity.level().getGameTime()); - } - - @Override - protected boolean timedOut(long gameTime) { - return this.runningBehaviour == null || this.runningBehaviour.timedOut(gameTime); - } - - @Override - protected void tick(ServerLevel level, E owner, long gameTime) { - this.runningBehaviour.tickOrStop(level, owner, gameTime); - - if (this.runningBehaviour.getStatus() == Status.STOPPED) { - this.runningBehaviour = null; - - doStop(level, owner, gameTime); - } - } - - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - super.stop(level, entity, gameTime); - - if (this.runningBehaviour != null) - this.runningBehaviour.stop(level, entity, gameTime); - - this.runningBehaviour = null; - } - - @Override - public Status getStatus() { - if (this.runningBehaviour == null) - return Status.STOPPED; - - return this.runningBehaviour.getStatus(); - } - - @Override - public String toString() { - return "(" + getClass().getSimpleName() + "): " + (this.runningBehaviour == null ? this.runningBehaviour.getClass().getSimpleName() : "{}"); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/HeldBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/HeldBehaviour.java deleted file mode 100644 index eb9d90066..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/HeldBehaviour.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; - -import java.util.function.Function; - -/** - * An abstract behaviour used for tasks that should have an ongoing effect, optionally with an early finish.
    - * This is most useful for things like attacks with multi-tick effects such as beams or flamethrowers, or other prolonged actions. - * @param The entity - */ -public abstract class HeldBehaviour extends ExtendedBehaviour { - protected Function tickConsumer = entity -> true; - protected int runningTime = 0; - - public HeldBehaviour() { - runFor(entity -> Integer.MAX_VALUE); - } - - /** - * Set the per-tick handler for this held behaviour - * @param tickConsumer The consumer to handle the per-action tick. Return false to end the behaviour, or true to continue running - */ - public HeldBehaviour onTick(Function tickConsumer) { - this.tickConsumer = tickConsumer; - - return this; - } - - /** - * Gets the amount of ticks this behaviour has been held for - */ - public int getRunningTime() { - return this.runningTime; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return true; - } - - @Override - protected void start(ServerLevel level, E entity, long gameTime) { - super.start(level, entity, gameTime); - - this.runningTime = 0; - } - - @Override - protected void tick(ServerLevel level, E owner, long gameTime) { - super.tick(level, owner, gameTime); - - if (!this.tickConsumer.apply(owner)) - doStop(level, owner, gameTime); - - this.runningTime++; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/OneRandomBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/OneRandomBehaviour.java deleted file mode 100644 index 1a94bce7d..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/OneRandomBehaviour.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import mod.azure.azurelib.sblforked.object.SBLShufflingList; -import org.jetbrains.annotations.Nullable; - -/** - * Group behaviour that attempts to run sub-behaviours in a - * @param The entity - */ -public final class OneRandomBehaviour extends GroupBehaviour { - public OneRandomBehaviour(Pair, Integer>... behaviours) { - super(behaviours); - } - - public OneRandomBehaviour(ExtendedBehaviour... behaviours) { - super(behaviours); - } - - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour(ServerLevel level, E entity, long gameTime, SBLShufflingList> extendedBehaviours) { - extendedBehaviours.shuffle(); - - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (behaviour.tryStart(level, entity, gameTime)) - return behaviour; - } - - return null; - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/SequentialBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/SequentialBehaviour.java deleted file mode 100644 index b4e901005..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/SequentialBehaviour.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import mod.azure.azurelib.sblforked.object.SBLShufflingList; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Predicate; - -/** - * Group behaviour that runs all child behaviours in order, one after another.
    - * Restarts from the first behaviour upon reaching the end of the list - * @param The entity - */ -public final class SequentialBehaviour extends GroupBehaviour { - private Predicate> earlyResetPredicate = behaviour -> false; - private ExtendedBehaviour lastRun = null; - - public SequentialBehaviour(Pair, Integer>... behaviours) { - super(behaviours); - } - - public SequentialBehaviour(ExtendedBehaviour... behaviours) { - super(behaviours); - } - - /** - * Adds an early short-circuit predicate to reset back to the start of the child behaviours at any time - */ - public SequentialBehaviour resetIf(Predicate> predicate) { - this.earlyResetPredicate = predicate; - - return this; - } - - @Nullable - @Override - protected ExtendedBehaviour pickBehaviour(ServerLevel level, E entity, long gameTime, SBLShufflingList> extendedBehaviours) { - boolean pickNext = this.lastRun == null; - - if (this.lastRun != null && this.earlyResetPredicate.test(this.lastRun)) { - pickNext = true; - this.lastRun = null; - } - - for (ExtendedBehaviour behaviour : extendedBehaviours) { - if (pickNext) { - if (behaviour.tryStart(level, entity, gameTime)) { - this.lastRun = behaviour; - - return behaviour; - } - - return null; - } - - if (behaviour == this.lastRun) - pickNext = true; - } - - this.lastRun = null; - - return null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableMeleeAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableMeleeAttack.java deleted file mode 100644 index 51c3c9e9e..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableMeleeAttack.java +++ /dev/null @@ -1,91 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.Function; - -/** - * Extended behaviour for melee attacking. Natively supports animation hit delays or other delays.
    - * Defaults: - *
      - *
    • 20 tick attack interval
    • - *
    - * @param The entity - */ -public class AnimatableMeleeAttack extends DelayedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT)); - - protected Function attackIntervalSupplier = entity -> 20; - - @Nullable - protected LivingEntity target = null; - - public AnimatableMeleeAttack(int delayTicks) { - super(delayTicks); - } - - /** - * Set the time between attacks. - * @param supplier The tick value provider - * @return this - */ - public AnimatableMeleeAttack attackInterval(Function supplier) { - this.attackIntervalSupplier = supplier; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.target = BrainUtils.getTargetOfEntity(entity); - - return entity.getSensing().hasLineOfSight(this.target) && entity.isWithinMeleeAttackRange(this.target); - } - - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); - BehaviorUtils.lookAtEntity(entity, this.target); - } - - @Override - protected void stop(E entity) { - this.target = null; - } - - @Override - protected void doDelayedAction(E entity) { - BrainUtils.setForgettableMemory(entity, MemoryModuleType.ATTACK_COOLING_DOWN, true, this.attackIntervalSupplier.apply(entity)); - - if (this.target == null) - return; - - if (!entity.getSensing().hasLineOfSight(this.target) || !entity.isWithinMeleeAttackRange(this.target)) - return; - - entity.doHurtTarget(this.target); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableRangedAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableRangedAttack.java deleted file mode 100644 index f614123a1..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/AnimatableRangedAttack.java +++ /dev/null @@ -1,106 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Difficulty; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.monster.RangedAttackMob; -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.Function; - -/** - * Extended behaviour for ranged attacking. Natively supports animation hit delays or other delays. - * Defaults: - *
      - *
    • 40-tick firing interval, decreased to 20 ticks when on {@link Difficulty Hard Difficulty}
    • - *
    • 16-block firing radius
    • - *
    - * @param - */ -public class AnimatableRangedAttack extends DelayedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT)); - - protected Function attackIntervalSupplier = entity -> entity.level().getDifficulty() == Difficulty.HARD ? 20 : 40; - protected float attackRadius; - - @Nullable - protected LivingEntity target = null; - - public AnimatableRangedAttack(int delayTicks) { - super(delayTicks); - - attackRadius(16); - } - - /** - * Set the time between attacks. - * @param supplier The tick value provider - * @return this - */ - public AnimatableRangedAttack attackInterval(Function supplier) { - this.attackIntervalSupplier = supplier; - - return this; - } - - /** - * Set the radius in blocks that the entity should be able to fire on targets. - * @param radius The radius, in blocks - * @return this - */ - public AnimatableRangedAttack attackRadius(float radius) { - this.attackRadius = radius * radius; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.target = BrainUtils.getTargetOfEntity(entity); - - return BrainUtils.canSee(entity, this.target) && entity.distanceToSqr(this.target) <= this.attackRadius; - } - - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); - BehaviorUtils.lookAtEntity(entity, this.target); - } - - @Override - protected void stop(E entity) { - this.target = null; - } - - @Override - protected void doDelayedAction(E entity) { - if (this.target == null) - return; - - if (!BrainUtils.canSee(entity, this.target) || entity.distanceToSqr(this.target) > this.attackRadius) - return; - - entity.performRangedAttack(this.target, 1); - BrainUtils.setForgettableMemory(entity, MemoryModuleType.ATTACK_COOLING_DOWN, true, this.attackIntervalSupplier.apply(entity)); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/BowAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/BowAttack.java deleted file mode 100644 index 376811667..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/BowAttack.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; - -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.monster.RangedAttackMob; -import net.minecraft.world.entity.projectile.ProjectileUtil; -import net.minecraft.world.item.BowItem; -import net.minecraft.world.item.Items; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Extended behaviour for charging and firing a - * {@link BowItem bow}. - * - * @param - */ -public class BowAttack extends AnimatableRangedAttack { - public BowAttack(int delayTicks) { - super(delayTicks); - } - - @Override - protected void start(E entity) { - BehaviorUtils.lookAtEntity(entity, this.target); - entity.startUsingItem(ProjectileUtil.getWeaponHoldingHand(entity, Items.BOW)); - } - - @Override - protected void doDelayedAction(E entity) { - if (this.target == null) - return; - - if (!BrainUtils.canSee(entity, this.target) || entity.distanceToSqr(this.target) > this.attackRadius) - return; - - entity.performRangedAttack(this.target, BowItem.getPowerForTime(entity.getTicksUsingItem())); - entity.stopUsingItem(); - BrainUtils.setForgettableMemory(entity, MemoryModuleType.ATTACK_COOLING_DOWN, true, this.attackIntervalSupplier.apply(entity)); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessAttack.java deleted file mode 100644 index 9142d83f6..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessAttack.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * Attack behaviour that doesn't require line of sight or proximity to target, or to even have a target at all. This is useful for special attacks.
    - * Set the actual condition for activation via {@link ExtendedBehaviour#startCondition(Predicate)} - * @param The entity - */ -public class ConditionlessAttack extends DelayedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT)); - - protected Function attackIntervalSupplier = entity -> 20; - protected boolean requireTarget = false; - protected Consumer effect = entity -> {}; - - @Nullable - protected LivingEntity target = null; - - public ConditionlessAttack(int delayTicks) { - super(delayTicks); - } - - /** - * Set the time between attacks. - * @param supplier The tick value provider - * @return this - */ - public ConditionlessAttack attackInterval(Function supplier) { - this.attackIntervalSupplier = supplier; - - return this; - } - - /** - * Set that the attack requires that the entity have an attack target set to activate. - * @return this - */ - public ConditionlessAttack requiresTarget() { - this.requireTarget = true; - - return this; - } - - /** - * Set the callback for the actual attack when the delay time has elapsed - * @param consumer The callback - * @return this - */ - public ConditionlessAttack attack(Consumer consumer) { - this.effect = consumer; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!this.requireTarget) - return true; - - this.target = BrainUtils.getTargetOfEntity(entity); - - return this.target != null; - } - - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); - - if (this.requireTarget) - BehaviorUtils.lookAtEntity(entity, this.target); - } - - @Override - protected void doDelayedAction(E entity) { - if (this.requireTarget && this.target == null) - return; - - this.effect.accept(entity); - BrainUtils.setForgettableMemory(entity, MemoryModuleType.ATTACK_COOLING_DOWN, true, this.attackIntervalSupplier.apply(entity)); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessHeldAttack.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessHeldAttack.java deleted file mode 100644 index b0bb1b2b5..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/attack/ConditionlessHeldAttack.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.attack; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.HeldBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * Attack behaviour for held attacks that doesn't require line of sight or proximity to target, or to even have a target at all. - * This is useful for special attacks.
    - * Set the actual condition for activation via {@link mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour#startCondition ExtendedBehaviour.startCondition} - * @param The entity - */ -public class ConditionlessHeldAttack extends HeldBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_COOLING_DOWN, MemoryStatus.VALUE_ABSENT)); - - protected boolean requireTarget = false; - - @Nullable - protected LivingEntity target = null; - - /** - * Set that the attack requires that the entity have an attack target set to activate. - * @return this - */ - public ConditionlessHeldAttack requiresTarget() { - this.requireTarget = true; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!this.requireTarget) - return true; - - this.target = BrainUtils.getTargetOfEntity(entity); - - return this.target != null; - } - - @Override - protected void start(E entity) { - entity.swing(InteractionHand.MAIN_HAND); - - if (this.requireTarget) - BehaviorUtils.lookAtEntity(entity, this.target); - } - - @Override - protected void stop(ServerLevel level, E entity, long gameTime) { - super.stop(level, entity, gameTime); - - this.target = null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtAttackTarget.java deleted file mode 100644 index e5cbd6f3f..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtAttackTarget.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.look; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * Set the {@link MemoryModuleType#LOOK_TARGET} of the brain owner to the current {@link MemoryModuleType#ATTACK_TARGET}, replacing the existing look target.
    - * This is mostly superceded by {@link mod.azure.azurelib.sblforked.api.core.behaviour.custom.path.SetWalkTargetToAttackTarget SetWalkTargetToAttackTarget}, but can be useful if you want the brain owner to look at the target without pathing to it - * @param The entity - */ -public class LookAtAttackTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED)); - - private LivingEntity target = null; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.target = BrainUtils.getTargetOfEntity(entity); - - return !(BrainUtils.getMemory(entity, MemoryModuleType.LOOK_TARGET) instanceof EntityTracker entityTracker) || entityTracker.getEntity() != this.target; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(this.target, true)); - } - - @Override - protected void stop(E entity) { - this.target = null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtTarget.java deleted file mode 100644 index 0cb302d98..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/look/LookAtTarget.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.look; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * Look at the look target for as long as it is present - * @param The entity - */ -public class LookAtTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_PRESENT)); - - public LookAtTarget() { - noTimeout(); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.LOOK_TARGET); - } - - @Override - protected void tick(E entity) { - BrainUtils.withMemory(entity, MemoryModuleType.LOOK_TARGET, target -> entity.getLookControl().setLookAt(target.currentPosition())); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/AvoidSun.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/AvoidSun.java deleted file mode 100644 index 857192957..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/AvoidSun.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -import java.util.List; - -/** Avoid the sun if not wearing a hat - * @param The entity - */ -public class AvoidSun extends ExtendedBehaviour { - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return level.isDay() && entity.getItemBySlot(EquipmentSlot.HEAD).isEmpty() && entity.getNavigation() instanceof GroundPathNavigation; - } - - @Override - protected void start(E entity) { - ((GroundPathNavigation)entity.getNavigation()).setAvoidSun(true); - } - - @Override - protected void stop(E entity) { - if (entity.getNavigation() instanceof GroundPathNavigation groundNavigation) - groundNavigation.setAvoidSun(true); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BlockWithShield.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BlockWithShield.java deleted file mode 100644 index ad088c304..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BlockWithShield.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.item.UseAnim; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -import java.util.List; -import java.util.function.Predicate; - -/** - * Makes the entity use (block) using a shield if it's currently in the entity's hands - */ -public class BlockWithShield extends ExtendedBehaviour { - protected InteractionHand hand = InteractionHand.MAIN_HAND; - - protected Predicate stopCondition = entity -> false; - - /** - * Sets the condition for when the entity should stop blocking.
    - * Deprecated, use {@link ExtendedBehaviour#stopIf} - * @param predicate The predicate - * @return this - */ - @Deprecated(forRemoval = true) - public BlockWithShield stopWhen(Predicate predicate) { - this.stopCondition = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (entity.getMainHandItem().getUseAnimation() == UseAnim.BLOCK) { - this.hand = InteractionHand.MAIN_HAND; - - return true; - } - else if (entity.getOffhandItem().getUseAnimation() == UseAnim.BLOCK) { - this.hand = InteractionHand.OFF_HAND; - - return true; - } - - return false; - } - - @Override - protected void start(E entity) { - entity.startUsingItem(this.hand); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - if (!entity.isUsingItem()) - return false; - - if (!(entity.getUseItem().getUseAnimation() == UseAnim.BLOCK)) - return false; - - return !this.stopCondition.test(entity); - } - - @Override - protected void stop(E entity) { - if (entity.getUseItem().getUseAnimation() == UseAnim.BLOCK) - entity.stopUsingItem(); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreakBlock.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreakBlock.java deleted file mode 100644 index 54845b881..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreakBlock.java +++ /dev/null @@ -1,142 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.LevelEvent; -import net.minecraft.world.level.block.state.BlockState; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.TriPredicate; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.apache.commons.lang3.function.TriFunction; - -import java.util.List; - -/** - * Gradually breaks then destroys a block.
    - * Finds blocks based on the {@link SBLMemoryTypes#NEARBY_BLOCKS} memory module.
    - * Defaults: - *
      - *
    • Breaks doors
    • - *
    • Takes 240 ticks to break the block
    • - *
    - */ -public class BreakBlock extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(SBLMemoryTypes.NEARBY_BLOCKS.get(), MemoryStatus.VALUE_PRESENT)); - - protected TriPredicate targetBlockPredicate = (entity, pos, state) -> state.is(BlockTags.DOORS); - protected TriPredicate stopPredicate = (entity, pos, state) -> false; - protected TriFunction digTimePredicate = (entity, pos, state) -> 240; - - protected BlockPos pos = null; - protected BlockState state = null; - protected int timeToBreak = 0; - protected int breakTime = 0; - protected int breakProgress = -1; - - /** - * Set the condition for when the entity should stop breaking the block. - * @param predicate The predicate - * @return this - */ - public BreakBlock stopBreakingIf(TriPredicate predicate) { - this.stopPredicate = predicate; - - return this; - } - - /** - * Sets the predicate for valid blocks to break. - * @param predicate The predicate - * @return this - */ - public BreakBlock forBlocks(TriPredicate predicate) { - this.targetBlockPredicate = predicate; - - return this; - } - - /** - * Determines the amount of time (in ticks) it takes to break the given block. - * @param function The function - * @return this - */ - public BreakBlock timeToBreak(TriFunction function) { - this.digTimePredicate = function; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean timedOut(long gameTime) { - return this.breakProgress < 0 && super.timedOut(gameTime); - } - - @Override - protected void stop(E entity) { - entity.level().destroyBlockProgress(entity.getId(), this.pos, -1); - - this.state = null; - this.pos = null; - this.timeToBreak = 0; - this.breakTime = 0; - this.breakProgress = -1; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - for (Pair pair : BrainUtils.getMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get())) { - if (this.targetBlockPredicate.test(entity, pair.getFirst(), pair.getSecond())) { - this.pos = pair.getFirst(); - this.state = pair.getSecond(); - this.timeToBreak = this.digTimePredicate.apply(entity, this.pos, this.state); - - return true; - } - } - - return false; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.breakTime <= this.timeToBreak && this.targetBlockPredicate.test(entity, this.pos, entity.level().getBlockState(this.pos)) && !this.stopPredicate.test(entity, this.pos, this.state); - } - - @Override - protected void tick(E entity) { - this.breakTime++; - int progress = (int)(this.breakTime / (float)this.timeToBreak * 10); - - if (progress != this.breakProgress) { - entity.level().destroyBlockProgress(entity.getId(), this.pos, progress); - - this.breakProgress = progress; - } - - if (this.breakTime >= this.timeToBreak) { - entity.level().removeBlock(this.pos, false); - entity.level().levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, this.pos, Block.getId(entity.level().getBlockState(this.pos))); - - doStop((ServerLevel)entity.level(), entity, entity.level().getGameTime()); - } - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreedWithPartner.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreedWithPartner.java deleted file mode 100644 index 2d1b8a2e0..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/BreedWithPartner.java +++ /dev/null @@ -1,126 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.animal.Animal; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.ToIntBiFunction; - -/** - * Functional replacement for vanilla's {@link net.minecraft.world.entity.ai.behavior.AnimalMakeLove AnimalMakeLove}. - *

    Makes the entity find, move to, and breed with its target mate, producing offspring.

    - * Defaults: - *
      - *
    • 1x walk speed modifier when moving to its breeding partner
    • - *
    • Spend between 3 and 5.5 seconds to create the offspring
    • - *
    - */ -public class BreedWithPartner extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.BREED_TARGET, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT)); - - protected BiFunction speedMod = (entity, partner) -> 1f; - protected ToIntBiFunction closeEnoughDist = (entity, partner) -> 2; - protected BiFunction breedTime = (entity, partner) -> entity.getRandom().nextInt(60, 110); - protected BiPredicate partnerPredicate = (entity, partner) -> entity.getType() == partner.getType() && entity.canMate(partner); - - protected int childBreedTick = -1; - protected Animal partner = null; - - public BreedWithPartner() { - runFor(entity -> Integer.MAX_VALUE); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the movespeed modifier for the entity when moving to their partner. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public BreedWithPartner speedMod(final BiFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Sets the amount (in blocks) that the animal can be considered 'close enough' to their partner that they can stop pathfinding - * @param closeEnoughDist The distance function - * @return this - */ - public BreedWithPartner closeEnoughDist(final ToIntBiFunction closeEnoughDist) { - this.closeEnoughDist = closeEnoughDist; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!entity.isInLove()) - return false; - - this.partner = findPartner(entity); - - return this.partner != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return this.partner != null && this.partner.isAlive() && entity.tickCount <= this.childBreedTick && BehaviorUtils.entityIsVisible(entity.getBrain(), this.partner) && this.partnerPredicate.test(entity, this.partner); - } - - @Override - protected void start(E entity) { - this.childBreedTick = entity.tickCount + this.breedTime.apply(entity, this.partner); - - BrainUtils.setMemory(entity, MemoryModuleType.BREED_TARGET, this.partner); - BrainUtils.setMemory(this.partner, MemoryModuleType.BREED_TARGET, entity); - BehaviorUtils.lockGazeAndWalkToEachOther(entity, this.partner, this.speedMod.apply(entity, this.partner), this.closeEnoughDist.applyAsInt(entity, this.partner)); - } - - @Override - protected void tick(E entity) { - BehaviorUtils.lockGazeAndWalkToEachOther(entity, this.partner, this.speedMod.apply(entity, this.partner), this.closeEnoughDist.applyAsInt(entity, this.partner)); - - if (entity.closerThan(this.partner, 3) && entity.tickCount == this.childBreedTick) { - entity.spawnChildFromBreeding((ServerLevel)entity.level(), this.partner); - BrainUtils.clearMemory(entity, MemoryModuleType.BREED_TARGET); - BrainUtils.clearMemory(this.partner, MemoryModuleType.BREED_TARGET); - } - } - - @Override - protected void stop(E entity) { - BrainUtils.clearMemories(entity, MemoryModuleType.BREED_TARGET, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET); - - if (this.partner != null) - BrainUtils.clearMemories(this.partner, MemoryModuleType.BREED_TARGET, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET); - - this.childBreedTick = -1; - this.partner = null; - } - - @Nullable - protected Animal findPartner(E entity) { - return BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).findClosest(entity2 -> entity2 instanceof Animal partner && this.partnerPredicate.test(entity, partner)).map(Animal.class::cast).orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomBehaviour.java deleted file mode 100644 index 990f563fa..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomBehaviour.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Predicate; - -/** - * A behaviour module that invokes a callback.
    - * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth implementing into a full behaviour.
    - * Set the condition for running via {@link ExtendedBehaviour#startCondition(Predicate)} - */ -public final class CustomBehaviour extends ExtendedBehaviour { - private Consumer callback; - - public CustomBehaviour(Consumer callback) { - this.callback = callback; - } - - /** - * Replace the callback function - * @return this - */ - public CustomBehaviour callback(Consumer callback) { - this.callback = callback; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected void start(E entity) { - this.callback.accept(entity); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomDelayedBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomDelayedBehaviour.java deleted file mode 100644 index 37f63be4d..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomDelayedBehaviour.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.DelayedBehaviour; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -import java.util.List; -import java.util.function.Predicate; - -/** - * A behaviour module that acts as a default implementation of {@link DelayedBehaviour}.
    - * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth implementing into a full behaviour.
    - * Set the condition for running via {@link ExtendedBehaviour#startCondition(Predicate)} - */ -public final class CustomDelayedBehaviour extends DelayedBehaviour { - public CustomDelayedBehaviour(int delayTicks) { - super(delayTicks); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomHeldBehaviour.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomHeldBehaviour.java deleted file mode 100644 index 7415e0584..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/CustomHeldBehaviour.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.api.core.behaviour.HeldBehaviour; - -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Predicate; - -/** - * A behaviour module that invokes a callback every tick until stopped.
    - * Useful for handling custom minor actions that are either too specific to warrant a new behaviour, or not worth implementing into a full behaviour.
    - * Set the condition for running via {@link ExtendedBehaviour#startCondition(Predicate)}
    - * Set the condition for stopping via {@link ExtendedBehaviour#stopIf(Predicate)} - */ -public final class CustomHeldBehaviour extends HeldBehaviour { - private Consumer callback; - - public CustomHeldBehaviour(Consumer callback) { - this.callback = callback; - } - - /** - * Replace the callback function - * @return this - */ - public CustomHeldBehaviour callback(Consumer callback) { - this.callback = callback; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected void tick(E entity) { - this.callback.accept(entity); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/HoldItem.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/HoldItem.java deleted file mode 100644 index 0ce689eff..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/HoldItem.java +++ /dev/null @@ -1,91 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.item.ItemStack; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -import java.util.List; -import java.util.function.BiPredicate; -import java.util.function.Function; - -/** - * Equips the entity with an item in its {@link InteractionHand hand}.
    - * Can be set to an {@link ItemStack#EMPTY empty ItemStack} to act as unequipping.
    - * Defaults: - *
      - *
    • Equips to the main hand
    • - *
    • Deletes the item it was holding prior to equipping the new item
    • - *
    - */ -public class HoldItem extends ExtendedBehaviour { - protected Function stackFunction = entity -> ItemStack.EMPTY; - protected Function handDecider = entity -> InteractionHand.MAIN_HAND; - protected BiPredicate dropItemOnUnequip = (entity, stack) -> false; - - /** - * Sets the function to determine which hand to equip the item in. - * @param function The function - * @return this - */ - public HoldItem toHand(Function function) { - this.handDecider = function; - - return this; - } - - /** - * Sets the function to determine the item to equip. - * @param function The itemstack function - * @return this - */ - public HoldItem withStack(Function function) { - this.stackFunction = function; - - return this; - } - - /** - * Sets the behaviour to drop the previously equipped item when equipping the new item. - * @return this - */ - public HoldItem dropItemOnUnequip() { - return dropItemOnUnequip((entity, stack) -> true); - } - - /** - * Sets the predicate to determine whether the entity should drop the previously equipped item when equipping the new item. - * @param dropPredicate The predicate - * @return this - */ - public HoldItem dropItemOnUnequip(BiPredicate dropPredicate) { - this.dropItemOnUnequip = dropPredicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected void start(E entity) { - InteractionHand hand = this.handDecider.apply(entity); - ItemStack previousStack = entity.getItemInHand(hand); - - if (this.dropItemOnUnequip.test(entity, previousStack)) - entity.spawnAtLocation(previousStack); - - entity.setItemInHand(hand, this.stackFunction.apply(entity)); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Idle.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Idle.java deleted file mode 100644 index c30f1e035..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Idle.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -import java.util.List; - -/** - * Do nothing at all. - * @param The entity - */ -public class Idle extends ExtendedBehaviour { - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return true; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/InvalidateMemory.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/InvalidateMemory.java deleted file mode 100644 index 5dec830a6..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/InvalidateMemory.java +++ /dev/null @@ -1,71 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; -import java.util.function.BiPredicate; - -/** - * Custom behaviour for conditionally invalidating/resetting existing memories.
    - * This allows for custom handling of stored memories, and clearing them at will.
    - *
    - * Invalidates the memory unconditionally once the behaviour runs. Use {@link InvalidateMemory#invalidateIf} and {@link ExtendedBehaviour#startCondition} to quantify its operating conditions - * @param The brain owner - * @param The data type of the memory - */ -public class InvalidateMemory extends ExtendedBehaviour { - private List, MemoryStatus>> memoryRequirements; - - protected BiPredicate customPredicate = (entity, target) -> true; - protected MemoryModuleType memory; - - public InvalidateMemory(MemoryModuleType memory) { - super(); - - this.memory = memory; - this.memoryRequirements = List.of(Pair.of(this.memory, MemoryStatus.VALUE_PRESENT)); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return this.memoryRequirements == null ? List.of() : this.memoryRequirements; - } - - /** - * Sets the {@link MemoryModuleType memory} to check and invalidate. - */ - public InvalidateMemory forMemory(MemoryModuleType memory) { - this.memory = memory; - this.memoryRequirements = List.of(Pair.of(this.memory, MemoryStatus.VALUE_PRESENT)); - - return this; - } - - /** - * Sets a custom predicate to invalidate the memory if none of the previous checks invalidate it first. - */ - public InvalidateMemory invalidateIf(BiPredicate predicate) { - this.customPredicate = predicate; - - return this; - } - - @Override - protected void start(E entity) { - M memory = BrainUtils.getMemory(entity, this.memory); - - if (memory != null && this.customPredicate.test(entity, memory)) - BrainUtils.clearMemory(entity, this.memory); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Panic.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Panic.java deleted file mode 100644 index 966b74aa1..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/Panic.java +++ /dev/null @@ -1,185 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.Object2FloatFunction; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.FluidTags; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; - -/** - * Functional equivalent of the goal system's {@link net.minecraft.world.entity.ai.goal.PanicGoal panic goal}.
    - * Rapidly sets a runaway position based on its last damage.
    - * Defaults: - *
      - *
    • 1.25x Speed modifier when panicking
    • - *
    • Panics if freezing, on fire, or was recently hurt by a living entity
    • - *
    • Runs to a nearby location within 5x4 blocks radius
    • - *
    • Panics for a minimum of 5-6 seconds
    • - *
    - * @param The entity - */ -public class Panic extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.HURT_BY, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.IS_PANICKING, MemoryStatus.REGISTERED)); - - protected BiPredicate shouldPanicPredicate = (entity, damageSource) -> entity.isFreezing() || entity.isOnFire() || damageSource.getEntity() instanceof LivingEntity; - protected Object2FloatFunction speedMod = entity -> 1.25f; - protected SquareRadius radius = new SquareRadius(5, 4); - protected BiFunction panicFor = (entity, damageSource) -> entity.getRandom().nextInt(100, 120); - - protected Vec3 targetPos = null; - protected int panicEndTime = 0; - - public Panic() { - noTimeout(); - } - - /** - * Set a custom predicate for if the entity should panic based on its current conditions. - * @param predicate The predicate - * @return this - */ - public Panic panicIf(final BiPredicate predicate) { - this.shouldPanicPredicate = predicate; - - return this; - } - - /** - * Determine the length of time (in ticks) that the entity should panic for once starting - * @param function The predicate - * @return this - */ - public Panic panicFor(final BiFunction function) { - this.panicFor = function; - - return this; - } - - /** - * Set the movespeed modifier for the entity when panicking. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public Panic speedMod(final Object2FloatFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Set the radius in which to look for walk positions. - * @param radius The coordinate radius, in blocks - * @return this - */ - public Panic setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for walk positions. - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public Panic setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!this.shouldPanicPredicate.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY))) - return false; - - setPanicTarget(entity); - - return this.targetPos != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return entity.tickCount < this.panicEndTime; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.targetPos, this.speedMod.apply(entity), 0)); - BrainUtils.setMemory(entity, MemoryModuleType.IS_PANICKING, true); - - this.panicEndTime = entity.tickCount + this.panicFor.apply(entity, BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY)); - } - - @Override - protected void tick(E entity) { - if (entity.getNavigation().isDone()) { - this.targetPos = null; - setPanicTarget(entity); - - if (this.targetPos != null) { - BrainUtils.clearMemory(entity, MemoryModuleType.PATH); - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.targetPos, this.speedMod.apply(entity), 1)); - } - } - } - - @Override - protected void stop(E entity) { - this.targetPos = null; - this.panicEndTime = 0; - - BrainUtils.setMemory(entity, MemoryModuleType.IS_PANICKING, false); - } - - @Nullable - protected Vec3 findNearbyWater(E entity) { - final BlockPos pos = entity.blockPosition(); - final Level level = entity.level(); - - return !level.getBlockState(pos).getCollisionShape(level, pos).isEmpty() ? null : BlockPos.findClosestMatch(entity.blockPosition(), (int)this.radius.xzRadius(), (int)this.radius.yRadius(), checkPos -> level.getFluidState(checkPos).is(FluidTags.WATER)).map(Vec3::atBottomCenterOf).orElse(null); - } - - protected void setPanicTarget(E entity) { - if (entity.isOnFire()) - this.targetPos = findNearbyWater(entity); - - if (this.targetPos == null) { - final DamageSource lastDamage = BrainUtils.getMemory(entity, MemoryModuleType.HURT_BY); - - if (lastDamage != null && lastDamage.getEntity() instanceof LivingEntity attacker) - this.targetPos = DefaultRandomPos.getPosAway(entity, (int)this.radius.xzRadius(), (int)this.radius.yRadius(), attacker.position()); - - if (this.targetPos == null) - this.targetPos = DefaultRandomPos.getPos(entity, (int)this.radius.xzRadius(), (int)this.radius.yRadius()); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/ReactToUnreachableTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/ReactToUnreachableTarget.java deleted file mode 100644 index 39dd4149f..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/misc/ReactToUnreachableTarget.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.misc; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; - -import java.util.List; -import java.util.function.BiConsumer; -import java.util.function.Function; - -/** - * Calls a callback when the entity has been obstructed for a given period of time. - * @param The entity - */ -public class ReactToUnreachableTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.VALUE_PRESENT), Pair.of(SBLMemoryTypes.TARGET_UNREACHABLE.get(), MemoryStatus.VALUE_PRESENT)); - - protected Function ticksToReact = entity -> 100; - protected BiConsumer callback = (entity, towering) -> {}; - - protected long reactAtTime = 0; - - /** - * Set the amount of ticks that the target should be unreachable before reacting. - * @param ticksToReact The function to provide the time to wait before reacting - * @return this - */ - public ReactToUnreachableTarget timeBeforeReacting(Function ticksToReact) { - this.ticksToReact = ticksToReact; - - return this; - } - - /** - * Set the function to run when the given time has elapsed and the target is still unreachable. - * @param callback The function to run - * @return this - */ - public ReactToUnreachableTarget reaction(BiConsumer callback) { - this.callback = callback; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean timedOut(long gameTime) { - return this.reactAtTime == 0 || this.reactAtTime < gameTime; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return hasRequiredMemories(entity); - } - - @Override - protected void start(E entity) { - this.reactAtTime = entity.level().getGameTime() + this.ticksToReact.apply(entity); - } - - @Override - protected void stop(E entity) { - this.reactAtTime = 0; - } - - @Override - protected void tick(E entity) { - if (entity.level().getGameTime() == this.reactAtTime) - this.callback.accept(entity, BrainUtils.getMemory(entity, SBLMemoryTypes.TARGET_UNREACHABLE.get())); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/AvoidEntity.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/AvoidEntity.java deleted file mode 100644 index e74cf174a..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/AvoidEntity.java +++ /dev/null @@ -1,137 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; -import java.util.Optional; -import java.util.function.Predicate; - -/** - * Try to move away from certain entities when they get too close.
    - * Defaults: - *
      - *
    • 3 block minimum distance
    • - *
    • 7 block maximum distance
    • - *
    • 1x move speed modifier
    • - *
    - */ -public class AvoidEntity extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT)); - - protected Predicate avoidingPredicate = target -> false; - protected float noCloserThanSqr = 9f; - protected float stopAvoidingAfterSqr = 49f; - protected float speedModifier = 1; - - private Path runPath = null; - - public AvoidEntity() { - noTimeout(); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the minimum distance the target entity should be allowed to come before the entity starts retreating. - * @param blocks The distance, in blocks - * @return this - */ - public AvoidEntity noCloserThan(float blocks) { - this.noCloserThanSqr = blocks * blocks; - - return this; - } - - /** - * Set the maximum distance the target entity should be before the entity stops retreating. - * @param blocks The distance, in blocks - * @return this - */ - public AvoidEntity stopCaringAfter(float blocks) { - this.stopAvoidingAfterSqr = blocks * blocks; - - return this; - } - - /** - * Sets the predicate for entities to avoid. - * @param predicate The predicate - * @return this - */ - public AvoidEntity avoiding(Predicate predicate) { - this.avoidingPredicate = predicate; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is running away. - * @param mod The speed multiplier modifier - * @return this - */ - public AvoidEntity speedModifier(float mod) { - this.speedModifier = mod; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - Optional target = BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).findClosest(this.avoidingPredicate); - - if (target.isEmpty()) - return false; - - LivingEntity avoidingEntity = target.get(); - double distToTarget = avoidingEntity.distanceToSqr(entity); - - if (distToTarget > this.noCloserThanSqr) - return false; - - Vec3 runPos = DefaultRandomPos.getPosAway(entity, 16, 7, avoidingEntity.position()); - - if (runPos == null || avoidingEntity.distanceToSqr(runPos.x, runPos.y, runPos.z) < distToTarget) - return false; - - this.runPath = entity.getNavigation().createPath(runPos.x, runPos.y, runPos.z, 0); - - return this.runPath != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return !this.runPath.isDone(); - } - - @Override - protected void start(E entity) { - entity.getNavigation().moveTo(this.runPath, this.speedModifier); - } - - @Override - protected void stop(E entity) { - this.runPath = null; - - entity.getNavigation().setSpeedModifier(1); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/EscapeSun.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/EscapeSun.java deleted file mode 100644 index e7f586d40..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/EscapeSun.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * Sets the {@link MemoryModuleType#WALK_TARGET walk target} to a safe position if caught in the sun.
    - * Defaults: - *
      - *
    • Only if not currently fighting something
    • - *
    • Only if already burning from the sun
    • - *
    - * @param The entity - */ -public class EscapeSun extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED)); - - protected float speedModifier = 1; - - protected Vec3 hidePos = null; - - public EscapeSun() { - noTimeout(); - } - - /** - * Set the movespeed modifier for when the entity tries to escape the sun - * @param speedMod The speed modifier - * @return this - */ - public EscapeSun speedModifier(float speedMod) { - this.speedModifier = speedMod; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - if (!level.isDay() || !entity.isOnFire() || !level.canSeeSky(entity.blockPosition())) - return false; - - if (!entity.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) - return false; - - this.hidePos = getHidePos(entity); - - return this.hidePos != null; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.hidePos, this.speedModifier, 0)); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - if (this.hidePos == null) - return false; - - WalkTarget walkTarget = BrainUtils.getMemory(entity, MemoryModuleType.WALK_TARGET); - - if (walkTarget == null) - return false; - - return walkTarget.getTarget().currentBlockPosition().equals(BlockPos.containing(this.hidePos)) && !entity.getNavigation().isDone(); - } - - @Override - protected void stop(E entity) { - this.hidePos = null; - } - - @Nullable - protected Vec3 getHidePos(E entity) { - RandomSource randomsource = entity.getRandom(); - BlockPos entityPos = entity.blockPosition(); - - for(int i = 0; i < 10; ++i) { - BlockPos hidePos = entityPos.offset(randomsource.nextInt(20) - 10, randomsource.nextInt(6) - 3, randomsource.nextInt(20) - 10); - - if (!entity.level().canSeeSky(hidePos) && entity.getWalkTargetValue(hidePos) < 0.0F) - return Vec3.atBottomCenterOf(hidePos); - } - - return null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FleeTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FleeTarget.java deleted file mode 100644 index 0e42c98a2..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FleeTarget.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * Flee the current attack target.
    - * Defaults: - *
      - *
    • 20 block flee distance
    • - *
    • 1x move speed modifier
    • - *
    - * @param The entity - */ -public class FleeTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT)); - - protected int fleeDistance = 20; - protected float speedModifier = 1; - - protected Path runPath = null; - - public FleeTarget() { - noTimeout(); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the maximum distance the entity should try to flee to - * @param blocks The distance, in blocks - * @return this - */ - public FleeTarget fleeDistance(int blocks) { - this.fleeDistance = blocks; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is running away. - * @param mod The speed multiplier modifier - * @return this - */ - public FleeTarget speedModifier(float mod) { - this.speedModifier = mod; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - double distToTarget = entity.distanceToSqr(target); - Vec3 runPos = DefaultRandomPos.getPosAway(entity, this.fleeDistance, 10, target.position()); - - if (runPos == null || target.distanceToSqr(runPos.x, runPos.y, runPos.z) < distToTarget) - return false; - - this.runPath = entity.getNavigation().createPath(runPos.x, runPos.y, runPos.z, 0); - - return this.runPath != null; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return entity.getNavigation().getPath() == this.runPath && !entity.getNavigation().isDone(); - } - - @Override - protected void start(E entity) { - entity.getNavigation().moveTo(this.runPath, this.speedModifier); - BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } - - @Override - protected void stop(E entity) { - if (entity.getNavigation().getPath() == this.runPath) - entity.getNavigation().setSpeedModifier(1); - - this.runPath = null; - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FloatToSurfaceOfFluid.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FloatToSurfaceOfFluid.java deleted file mode 100644 index b025ece6f..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FloatToSurfaceOfFluid.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.FluidTags; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; - -import java.util.List; - -/** - * Replacement for {@link net.minecraft.world.entity.ai.goal.FloatGoal} or {@link net.minecraft.world.entity.ai.behavior.Swim}.
    - * Causes the entity to rise to the surface of water and float at the surface. - * Defaults: - *
      - *
    • 80% chance per tick to jump
    • - *
    • Applies to water
    • - *
    - */ -public class FloatToSurfaceOfFluid extends ExtendedBehaviour { - protected float riseChance = 0.8f; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - /** - * Set the chance per tick that the entity will 'jump' in water, rising up towards the surface. - * @param chance The chance, between 0 and 1 (inclusive) - * @return this - */ - public FloatToSurfaceOfFluid riseChance(float chance) { - this.riseChance = chance; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return entity.isInWater() && entity.getFluidHeight(FluidTags.WATER) > entity.getFluidJumpThreshold() || entity.isInLava(); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return checkExtraStartConditions((ServerLevel)entity.level(), entity); - } - - @Override - protected void tick(E entity) { - if (entity.getRandom().nextFloat() < this.riseChance) - entity.getJumpControl().jump(); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowEntity.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowEntity.java deleted file mode 100644 index 72840a6c4..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowEntity.java +++ /dev/null @@ -1,210 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.PathType; -import net.minecraft.world.level.pathfinder.PathfindingContext; -import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.RandomUtil; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.Function; - -/** - * A movement behaviour for automatically following a given entity.
    - * Defaults: - *
      - *
    • Will stop attempting to move closer than 2 blocks from the target
    • - *
    • Won't attempt to follow until the target is more than 10 blocks away
    • - *
    • Won't teleport to the target if it gets too far away
    • - *
    • 1x movespeed modifier for following
    • - *
    - * @param The owner of the brain - * @param The minimum common class of the entity expected to be following - */ -public class FollowEntity extends ExtendedBehaviour { - protected Function followingEntityProvider = entity -> null; - - protected BiFunction teleportDistance = (entity, target) -> Double.MAX_VALUE; - protected BiFunction followDistMin = (entity, target) -> 4d; - protected BiFunction speedMod = (entity, target) -> 1f; - - protected float oldWaterPathMalus = 0; - protected float oldLavaPathMalus = 0; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - /** - * Determines the entity that the brain owner should follow. - * @param following The function that provides the entity to follow - * @return this - */ - public FollowEntity following(Function following) { - this.followingEntityProvider = following; - - return this; - } - - /** - * Determines the distance (in blocks) after which the entity should just attempt to teleport closer to the target entity - * @param distance The function to provide the distance to teleport after - * @return this - */ - public FollowEntity teleportToTargetAfter(double distance) { - return teleportToTargetAfter((entity, target) -> distance); - } - - /** - * Determines the distance (in blocks) after which the entity should just attempt to teleport closer to the target entity - * @param distanceProvider The function to provide the distance to teleport after - * @return this - */ - public FollowEntity teleportToTargetAfter(BiFunction distanceProvider) { - this.teleportDistance = distanceProvider; - - return this; - } - - /** - * Determines the distance (in blocks) within which the entity will stop pathing and will do other activities - * @param distance The distance to stop following within - * @return this - */ - public FollowEntity stopFollowingWithin(double distance) { - return stopFollowingWithin((entity, target) -> distance); - } - - /** - * Determines the distance (in blocks) within which the entity will stop pathing and will do other activities - * @param distanceProvider The function to provide the distance to stop following within - * @return this - */ - public FollowEntity stopFollowingWithin(BiFunction distanceProvider) { - this.followDistMin = distanceProvider; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * @param modifier The multiplier for movement speed - * @return this - */ - public FollowEntity speedMod(float modifier) { - return speedMod((entity, target) -> modifier); - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * @param modifier The multiplier function for movement speed - * @return this - */ - public FollowEntity speedMod(BiFunction modifier) { - this.speedMod = modifier; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - T target = this.followingEntityProvider.apply(entity); - - if (target == null || target.isSpectator()) - return false; - - double minDist = this.followDistMin.apply(entity, target); - - return entity.distanceToSqr(target) > minDist * minDist; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - T target = this.followingEntityProvider.apply(entity); - - if (target == null) - return false; - - double dist = entity.distanceToSqr(target); - double minDist = this.followDistMin.apply(entity, target); - - return dist > minDist * minDist; - } - - @Override - protected void start(E entity) { - T target = this.followingEntityProvider.apply(entity); - double minDist = this.followDistMin.apply(entity, target); - float speedMod = this.speedMod.apply(entity, target); - this.oldWaterPathMalus = entity.getPathfindingMalus(PathType.WATER); - - if (entity.fireImmune()) { - this.oldLavaPathMalus = entity.getPathfindingMalus(PathType.LAVA); - - entity.setPathfindingMalus(PathType.LAVA, 0); - } - - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(target, speedMod, (int)minDist)); - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); - entity.setPathfindingMalus(PathType.WATER, 0); - } - - @Override - protected void stop(E entity) { - entity.setPathfindingMalus(PathType.WATER, this.oldWaterPathMalus); - - if (entity.fireImmune()) - entity.setPathfindingMalus(PathType.LAVA, this.oldLavaPathMalus); - - entity.getNavigation().stop(); - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - - @Override - protected void tick(E entity) { - T target = this.followingEntityProvider.apply(entity); - double teleportDist = this.teleportDistance.apply(entity, target); - - if (entity.distanceToSqr(target) >= teleportDist * teleportDist) - teleportToTarget(entity, target); - } - - protected void teleportToTarget(E entity, T target) { - Level level = entity.level(); - BlockPos entityPos = target.blockPosition(); - - BlockPos pos = RandomUtil.getRandomPositionWithinRange(entityPos, 5, 5, 5, 1, 1, 1, true, level, 10, (state, statePos) -> { - PathType pathTypes = entity.getNavigation().getNodeEvaluator().getPathType(new PathfindingContext(level, entity), statePos.getX(), statePos.getY(), statePos.getZ()); - - if (pathTypes != PathType.WALKABLE) - return false; - - return level.noCollision(entity, entity.getBoundingBox().move(Vec3.atBottomCenterOf(statePos).subtract(entity.position()))); - }); - - if (pos != entityPos) { - entity.moveTo(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, entity.getYRot(), entity.getXRot()); - entity.getNavigation().stop(); - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowOwner.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowOwner.java deleted file mode 100644 index 7ab3510fa..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowOwner.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.TamableAnimal; - -/** - * A movement behaviour for automatically following the owner of a {@link TamableAnimal TameableAnimal}.
    - * @param The owner of the brain - */ -public class FollowOwner extends FollowEntity { - protected LivingEntity owner = null; - - public FollowOwner() { - following(this::getOwner); - teleportToTargetAfter(12); - } - - protected LivingEntity getOwner(E entity) { - if (this.owner == null) - this.owner = entity.getOwner(); - - if (this.owner != null && this.owner.isRemoved()) - this.owner = null; - - return this.owner; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowParent.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowParent.java deleted file mode 100644 index f9eed1fce..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowParent.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.AgeableMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiPredicate; - -/** - * A movement behaviour for automatically following the parent of an {@link AgeableMob AgeableMob}. - *

    Note that because vanilla animals do not store a reference to their parent or child, by default this behaviour just grabs the nearest - * animal of the same class and presumes it is the parent.

    - */ -public class FollowParent extends FollowEntity { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT)); - - private BiPredicate parentPredicate = (entity, other) -> entity.getClass() == other.getClass() && other.getAge() >= 0; - - public FollowParent() { - following(this::getParent); - stopFollowingWithin(2); - } - - /** - * Set the predicate that determines whether a given entity is a suitable 'parent' to follow - */ - public FollowParent parentPredicate(BiPredicate predicate) { - this.parentPredicate = predicate; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return entity.getAge() < 0 && super.checkExtraStartConditions(level, entity); - } - - @Override - public List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Nullable - protected AgeableMob getParent(E entity) { - return BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).findClosest(other -> other instanceof AgeableMob ageableMob && this.parentPredicate.test(entity, ageableMob)).map(AgeableMob.class::cast).orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowTemptation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowTemptation.java deleted file mode 100644 index 454107215..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/FollowTemptation.java +++ /dev/null @@ -1,145 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.Object2IntFunction; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.entity.animal.Animal; -import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; - -/** - * {@link ExtendedBehaviour ExtendedBehaviour} equivalent of vanilla's {@link net.minecraft.world.entity.ai.behavior.FollowTemptation FollowTemptation}.
    - * Has the entity follow a relevant temptation target (I.E. a player holding a tempting item).
    - * Will continue running for as long as the entity is being tempted.
    - * Defaults: - *
      - *
    • Follows the temptation target indefinitely
    • - *
    • Will stop following if panicked or if it has an active breed target
    • - *
    • Will not follow a temptation target again for 5 seconds after stopping
    • - *
    • Considers 2.5 blocks 'close enough' for the purposes of following temptation
    • - *
    • 1x speed modifier while following
    • - *
    - */ -public class FollowTemptation extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.IS_TEMPTED, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.TEMPTING_PLAYER, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.IS_PANICKING, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.BREED_TARGET, MemoryStatus.REGISTERED)); - - protected BiFunction speedMod = (entity, temptingPlayer) -> 1f; - protected BiPredicate shouldFollow = (entity, temptingPlayer) -> (!(entity instanceof Animal animal) || animal.getAge() == 0) && !BrainUtils.memoryOrDefault(entity, MemoryModuleType.IS_PANICKING, () -> false); - protected BiFunction closeEnoughWhen = (owner, temptingPlayer) -> 2.5f; - protected Object2IntFunction temptationCooldown = entity -> 100; - - public FollowTemptation() { - super(); - - this.runFor(entity -> Integer.MAX_VALUE); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the movespeed modifier for the entity when following the tempting player. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public FollowTemptation speedMod(final BiFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Determine whether the entity should follow the tempting player or not - * @param predicate The temptation predicate - * @return this - */ - public FollowTemptation followIf(final BiPredicate predicate) { - this.shouldFollow = predicate; - - return this; - } - - /** - * Sets the amount (in blocks) that the mob can be considered 'close enough' to their temptation that they can stop pathfinding - * @param closeEnoughMod The distance modifier - * @return this - */ - public FollowTemptation closeEnoughDist(final BiFunction closeEnoughMod) { - this.closeEnoughWhen = closeEnoughMod; - - return this; - } - - /** - * Sets the length of time (in ticks) the entity should ignore temptation after having previously been tempted.
    - * NOTE: This could be ignored if the {@link FollowTemptation#followIf} predicate has been overriden - * @param cooldownFunction The cooldown function - * @return this - */ - public FollowTemptation temptationCooldown(final Object2IntFunction cooldownFunction) { - this.temptationCooldown = cooldownFunction; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return this.shouldFollow.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER)); - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.TEMPTING_PLAYER) && - !BrainUtils.hasMemory(entity, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS) && - !BrainUtils.hasMemory(entity, MemoryModuleType.BREED_TARGET) && - this.shouldFollow.test(entity, BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER)); - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.IS_TEMPTED, true); - } - - @Override - protected void tick(E entity) { - final Player temptingPlayer = BrainUtils.getMemory(entity, MemoryModuleType.TEMPTING_PLAYER); - final float closeEnough = this.closeEnoughWhen.apply(entity, temptingPlayer); - - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(temptingPlayer, true)); - - if (entity.distanceToSqr(temptingPlayer) < closeEnough * closeEnough) { - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(new EntityTracker(temptingPlayer, false), this.speedMod.apply(entity, temptingPlayer), (int)closeEnough)); - } - } - - @Override - protected void stop(E entity) { - final int cooldownTicks = this.temptationCooldown.apply(entity); - - BrainUtils.setForgettableMemory(entity, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, cooldownTicks, cooldownTicks); - BrainUtils.setMemory(entity, MemoryModuleType.IS_TEMPTED, false); - BrainUtils.clearMemories(entity, MemoryModuleType.WALK_TARGET, MemoryModuleType.LOOK_TARGET); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/MoveToWalkTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/MoveToWalkTarget.java deleted file mode 100644 index 41d186f33..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/MoveToWalkTarget.java +++ /dev/null @@ -1,158 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public class MoveToWalkTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.PATH, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_PRESENT)); - - @Nullable - protected Path path; - @Nullable - protected BlockPos lastTargetPos; - protected float speedModifier; - - public MoveToWalkTarget() { - runFor(entity -> entity.getRandom().nextInt(100) + 150); - cooldownFor(entity -> entity.getRandom().nextInt(40)); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - WalkTarget walkTarget = BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET); - - if (!hasReachedTarget(entity, walkTarget) && attemptNewPath(entity, walkTarget, false)) { - this.lastTargetPos = walkTarget.getTarget().currentBlockPosition(); - - return true; - } - - BrainUtils.clearMemory(brain, MemoryModuleType.WALK_TARGET); - BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - return false; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - if (this.path == null || this.lastTargetPos == null) - return false; - - if (entity.getNavigation().isDone()) - return false; - - WalkTarget walkTarget = BrainUtils.getMemory(entity, MemoryModuleType.WALK_TARGET); - - return walkTarget != null && !hasReachedTarget(entity, walkTarget); - } - - @Override - protected void start(E entity) { - startOnNewPath(entity); - } - - @Override - protected void tick(E entity) { - Path path = entity.getNavigation().getPath(); - Brain brain = entity.getBrain(); - - if (this.path != path) { - this.path = path; - - BrainUtils.setMemory(brain, MemoryModuleType.PATH, path); - } - - if (path != null && this.lastTargetPos != null) { - WalkTarget walkTarget = BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET); - - if (walkTarget.getTarget().currentBlockPosition().distSqr(this.lastTargetPos) > 4 && attemptNewPath(entity, walkTarget, hasReachedTarget(entity, walkTarget))) { - this.lastTargetPos = walkTarget.getTarget().currentBlockPosition(); - - startOnNewPath(entity); - } - } - } - - @Override - protected void stop(E entity) { - Brain brain = entity.getBrain(); - - if (!entity.getNavigation().isStuck() || !BrainUtils.hasMemory(brain, MemoryModuleType.WALK_TARGET) || hasReachedTarget(entity, BrainUtils.getMemory(brain, MemoryModuleType.WALK_TARGET))) - this.cooldownFinishedAt = 0; - - entity.getNavigation().stop(); - BrainUtils.clearMemories(brain, MemoryModuleType.WALK_TARGET, MemoryModuleType.PATH); - - this.path = null; - } - - protected boolean attemptNewPath(E entity, WalkTarget walkTarget, boolean reachedCurrentTarget) { - Brain brain = entity.getBrain(); - BlockPos pos = walkTarget.getTarget().currentBlockPosition(); - this.path = entity.getNavigation().createPath(pos, 0); - this.speedModifier = walkTarget.getSpeedModifier(); - - if (reachedCurrentTarget) { - BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - return false; - } - - if (this.path != null && this.path.canReach()) { - BrainUtils.clearMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - } - else { - BrainUtils.setMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, entity.level().getGameTime()); - } - - if (this.path != null) - return true; - - Vec3 newTargetPos = DefaultRandomPos.getPosTowards(entity, 10, 7, Vec3.atBottomCenterOf(pos), Mth.HALF_PI); - - if (newTargetPos != null) { - this.path = entity.getNavigation().createPath(newTargetPos.x(), newTargetPos.y(), newTargetPos.z(), 0); - - return this.path != null; - } - - return false; - } - - protected boolean hasReachedTarget(E entity, WalkTarget target) { - return target.getTarget().currentBlockPosition().distManhattan(entity.blockPosition()) <= target.getCloseEnoughDist(); - } - - protected void startOnNewPath(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.PATH, this.path); - entity.getNavigation().moveTo(this.path, this.speedModifier); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StayWithinDistanceOfAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StayWithinDistanceOfAttackTarget.java deleted file mode 100644 index 021645e3e..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StayWithinDistanceOfAttackTarget.java +++ /dev/null @@ -1,162 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; -import net.minecraft.world.entity.ai.navigation.PathNavigation; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.Predicate; - -/** - * Movement behaviour to handle proximal strafing. Will run away if too close, or run towards if too far.
    - * Useful for ranged attackers.
    - * Defaults: - *
      - *
    • Continues strafing until the target is no longer in memory
    • - *
    • Stays between 5 and 20 blocks of the target
    • - *
    • Normal strafing speed
    • - *
    • 30% speed boost to repositioning
    • - *
    - * @param The entity - */ -public class StayWithinDistanceOfAttackTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected BiFunction distMax = (entity, target) -> 20f; - protected BiFunction distMin = (entity, target) -> 5f; - protected Predicate stopWhen = entity -> false; - protected float speedMod = 1; - protected float repositionSpeedMod = 1.3f; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set how far the entity should attempt to stay away from the target at a minimum. - * @param distance The distance, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget minDistance(float distance) { - return minDistance((entity, target) -> distance); - } - - /** - * Set how far the entity should attempt to stay away from the target at a minimum. - * @param distance The distance function, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget minDistance(BiFunction distance) { - this.distMin = distance; - - return this; - } - - /** - * Set how far the entity should attempt to stay away from the target at most. - * @param distance The distance, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget maxDistance(float distance) { - return maxDistance((entity, target) -> distance); - } - - /** - * Set how far the entity should attempt to stay away from the target at most. - * @param distance The distance function, in blocks - * @return this - */ - public StayWithinDistanceOfAttackTarget maxDistance(BiFunction distance) { - this.distMax = distance; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * @param modifier The multiplier for movement speed - * @return this - */ - public StayWithinDistanceOfAttackTarget speedMod(float modifier) { - this.speedMod = modifier; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is repositioning due to being too close or too far. - * @param modifier The multiplier for movement speed - * @return this - */ - public StayWithinDistanceOfAttackTarget repositionSpeedMod(float modifier) { - this.speedMod = modifier; - - return this; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.ATTACK_TARGET) && !this.stopWhen.test(entity); - } - - @Override - protected void tick(E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - double distanceToTarget = target.distanceToSqr(entity); - float maxDist = this.distMax.apply(entity, target); - double maxDistSq = Math.pow(maxDist, 2); - double minDistSq = Math.pow(this.distMin.apply(entity, target), 2); - PathNavigation navigation = entity.getNavigation(); - - if (distanceToTarget > maxDistSq || !entity.hasLineOfSight(target)) { - if (navigation.isDone()) - navigation.moveTo(target, this.repositionSpeedMod); - - return; - } - - if (distanceToTarget < minDistSq) { - if (navigation.isDone()) { - Vec3 runPos = DefaultRandomPos.getPosAway(entity, (int)maxDist, 5, target.position()); - - if (runPos != null) - navigation.moveTo(navigation.createPath(BlockPos.containing(runPos), 1), this.repositionSpeedMod); - } - - return; - } - - if (navigation instanceof GroundPathNavigation) - navigation.stop(); - - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); - - if (distanceToTarget > maxDistSq * 0.5f) { - entity.lookAt(target, 30, 30); - entity.getMoveControl().strafe(0.5f * this.speedMod, 0); - } - else if (distanceToTarget < minDistSq * 3f) { - entity.lookAt(target, 30, 30); - entity.getMoveControl().strafe(-0.5f * this.speedMod, 0); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StrafeTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StrafeTarget.java deleted file mode 100644 index ecef83daa..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/StrafeTarget.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; -import java.util.function.Predicate; - -/** - * Movement behaviour to handle strafing.
    - * Defaults: - *
      - *
    • Continues strafing until the target is no longer in memory
    • - *
    - * @param The entity - */ -public class StrafeTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected boolean strafingLaterally = false; - protected boolean strafingBack = false; - protected int strafeCounter = -1; - - protected float strafeDistanceSqr = 244; - protected Predicate stopStrafingWhen = entity -> false; - protected float speedMod = 1; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set a custom condition for when the strafing should end. - * @param predicate The predicate - * @return this - */ - public StrafeTarget stopStrafingWhen(Predicate predicate) { - this.stopStrafingWhen = predicate; - - return this; - } - - /** - * Set how far the entity should attempt to stay away from the target whilst strafing. - * @param distance The distance, in blocks - * @return this - */ - public StrafeTarget strafeDistance(float distance) { - this.strafeDistanceSqr = distance * distance; - - return this; - } - - /** - * Set the movespeed modifier for when the entity is strafing. - * @param modifier The multiplier for movement speed - * @return this - */ - public StrafeTarget speedMod(float modifier) { - this.speedMod = modifier; - - return this; - } - - @Override - protected boolean shouldKeepRunning(E entity) { - return BrainUtils.hasMemory(entity, MemoryModuleType.ATTACK_TARGET) && !this.stopStrafingWhen.test(entity); - } - - @Override - protected void tick(E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - double distanceToTarget = target.distanceToSqr(entity); - - if (distanceToTarget <= this.strafeDistanceSqr) { - entity.getNavigation().stop(); - this.strafeCounter++; - } - else { - entity.getNavigation().moveTo(target, this.speedMod); - this.strafeCounter = -1; - } - - if (this.strafeCounter >= 20) { - if (entity.getRandom().nextFloat() < 0.3) - this.strafingLaterally = !this.strafingLaterally; - - if (entity.getRandom().nextFloat() < 0.3) - this.strafingBack = !this.strafingBack; - - this.strafeCounter = 0; - } - - if (this.strafeCounter > -1) { - if (distanceToTarget > this.strafeDistanceSqr * 0.75f) { - this.strafingBack = false; - } - else if (distanceToTarget < this.strafeDistanceSqr * 0.25f) { - this.strafingBack = true; - } - - entity.lookAt(target, 30, 30); - entity.getMoveControl().strafe(this.strafingBack ? -0.5f : 0.5f, this.strafingLaterally ? 0.5f : -0.5f); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/WalkOrRunToWalkTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/WalkOrRunToWalkTarget.java deleted file mode 100644 index 47a96cd7e..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/move/WalkOrRunToWalkTarget.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.move; - -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -/** - * Extension of MoveToWalkTarget, but auto-marking the sprinting flag depending on the movespeed. - * This can be useful for using sprint animations on the client. - * @param - */ -public class WalkOrRunToWalkTarget extends MoveToWalkTarget { - @Override - protected void startOnNewPath(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.PATH, this.path); - - if (entity.getNavigation().moveTo(this.path, this.speedModifier)) - entity.setSharedFlag(3, this.speedModifier > 1); - } - - @Override - protected void stop(E entity) { - super.stop(entity); - - entity.setSharedFlag(3, false); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SeekRandomNearbyPosition.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SeekRandomNearbyPosition.java deleted file mode 100644 index 3369afecc..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SeekRandomNearbyPosition.java +++ /dev/null @@ -1,147 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.RandomUtil; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.Function; - -/** - * Walk target class that finds a random position nearby and sets it as the walk target if applicable.
    - * Useful for finding quick alternate paths for specific purposes.
    - * Defaults: - *
      - *
    • 10x6 block search radius
    • - *
    • 1x Movespeed modifier
    • - *
    • 10 Attempts at finding a position before giving up
    • - *
    - * @param The entity - */ -public class SeekRandomNearbyPosition extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORIES = ObjectArrayList.of(Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected BiPredicate validPosition = (entity, state) -> false; - protected BiFunction speedModifier = (entity, targetPos) -> 1f; - protected SquareRadius radius = new SquareRadius(10, 6); - protected Function tries = entity -> 10; - - protected Vec3 targetPos = null; - - /** - * Set the radius in which to look for walk positions. - * @param radius The coordinate radius, in blocks - * @return this - */ - public SeekRandomNearbyPosition setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for walk positions. - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SeekRandomNearbyPosition setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param modifier The movespeed modifier/multiplier - * @return this - */ - public SeekRandomNearbyPosition speedModifier(float modifier) { - return speedModifier((entity, targetPos) -> modifier); - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param function The movespeed modifier/multiplier function - * @return this - */ - public SeekRandomNearbyPosition speedModifier(BiFunction function) { - this.speedModifier = function; - - return this; - } - - /** - * Sets the number of positions to check before giving up on finding a valid target. - * @param attempts The number of attempts - * @return this - */ - public SeekRandomNearbyPosition attempts(int attempts) { - return attempts(entity -> attempts); - } - - /** - * Sets the number of positions to check before giving up on finding a valid target. - * @param function The attempts function - * @return this - */ - public SeekRandomNearbyPosition attempts(Function function) { - this.tries = function; - - return this; - } - - /** - * Set the predicate that determines the validity of positions when searching - * @param predicate The predicate - * @return this - */ - public SeekRandomNearbyPosition validPositions(BiPredicate predicate) { - this.validPosition = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORIES; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - this.targetPos = getTargetPos(entity); - - return this.targetPos != null; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.targetPos, this.speedModifier.apply(entity, this.targetPos), 0)); - } - - @Nullable - protected Vec3 getTargetPos(E entity) { - BlockPos entityPos = entity.blockPosition(); - BlockPos targetPos = RandomUtil.getRandomPositionWithinRange(entityPos, (int)this.radius.xzRadius(), (int)this.radius.yRadius(), (int)this.radius.xzRadius(), 0, 0, 0, false, entity.level(), 10, (state, pos) -> this.validPosition.test(entity, state)); - - return targetPos == entityPos ? null : Vec3.atBottomCenterOf(targetPos); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomFlyingTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomFlyingTarget.java deleted file mode 100644 index e4a8522e9..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomFlyingTarget.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import net.minecraft.util.Mth; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.util.AirAndWaterRandomPos; -import net.minecraft.world.entity.ai.util.HoverRandomPos; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -import java.util.function.ToIntFunction; - -/** - * Extension of {@link SetRandomHoverTarget}, with a configurable weight to allow for more 'flying'-like movement - *

    Additionally expands the vertical path search radius to 10, over the default of 7

    - */ -public class SetRandomFlyingTarget extends SetRandomHoverTarget { - protected ToIntFunction verticalWeight = entity -> -2; - - public SetRandomFlyingTarget() { - setRadius(10, 10); - } - - /** - * Sets the function that determines a vertical position offset for target positions.
    - * Flight patterns will tend towards this direction, with bigger values pulling more strongly - * @param function The function - * @return this - */ - public SetRandomFlyingTarget verticalWeight(ToIntFunction function) { - this.verticalWeight = function; - - return this; - } - - @Nullable - @Override - protected Vec3 getTargetPos(E entity) { - Vec3 entityFacing = entity.getViewVector(0); - Vec3 hoverPos = HoverRandomPos.getPos(entity, (int)(Math.ceil(this.radius.xzRadius())), (int)Math.ceil(this.radius.yRadius()), entityFacing.x, entityFacing.z, Mth.HALF_PI, 3, 1); - - if (hoverPos != null) - return hoverPos; - - return AirAndWaterRandomPos.getPos(entity, (int)(Math.ceil(this.radius.xzRadius())), (int)Math.ceil(this.radius.yRadius()), this.verticalWeight.applyAsInt(entity), entityFacing.x, entityFacing.z, Mth.HALF_PI); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomHoverTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomHoverTarget.java deleted file mode 100644 index 6adf5b847..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomHoverTarget.java +++ /dev/null @@ -1,128 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.entity.ai.util.AirAndWaterRandomPos; -import net.minecraft.world.entity.ai.util.HoverRandomPos; -import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; - -/** - * Set a random position to fly to, taking into account the entity's current heading.
    - * Keeps the entity roughly near ground level, encouraging hover-flight rather than floating off into the sky.
    - * Defaults: - *
      - *
    • 1x movespeed modifier
    • - *
    • 10-block lateral radius
    • - *
    • 7-block vertical radius
    • - *
    - * @param - */ -public class SetRandomHoverTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected BiFunction speedModifier = (entity, targetPos) -> 1f; - protected SquareRadius radius = new SquareRadius(10, 7); - protected BiPredicate positionPredicate = (entity, pos) -> true; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the radius in which to look for flight positions. - * @param radius The coordinate radius, in blocks - * @return this - */ - public SetRandomHoverTarget setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for flight positions. - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SetRandomHoverTarget setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param modifier The movespeed modifier/multiplier - * @return this - */ - public SetRandomHoverTarget speedModifier(float modifier) { - return speedModifier((entity, targetPos) -> modifier); - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param function The movespeed modifier/multiplier function - * @return this - */ - public SetRandomHoverTarget speedModifier(BiFunction function) { - this.speedModifier = function; - - return this; - } - - /** - * Sets a predicate to check whether the target movement position is valid or not - * @param predicate The predicate - * @return this - */ - public SetRandomHoverTarget flightTargetPredicate(BiPredicate predicate) { - this.positionPredicate = predicate; - - return this; - } - - @Override - protected void start(E entity) { - Vec3 targetPos = getTargetPos(entity); - - if (!this.positionPredicate.test(entity, targetPos)) - targetPos = null; - - if (targetPos == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0)); - } - } - - @Nullable - protected Vec3 getTargetPos(E entity) { - Vec3 entityFacing = entity.getViewVector(0); - Vec3 hoverPos = HoverRandomPos.getPos(entity, (int)(Math.ceil(this.radius.xzRadius())), (int)Math.ceil(this.radius.yRadius()), entityFacing.x, entityFacing.z, Mth.HALF_PI, 3, 1); - - if (hoverPos != null) - return hoverPos; - - return AirAndWaterRandomPos.getPos(entity, (int)(Math.ceil(this.radius.xzRadius())), (int)Math.ceil(this.radius.yRadius()), -2, entityFacing.x, entityFacing.z, Mth.HALF_PI); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomSwimTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomSwimTarget.java deleted file mode 100644 index b4f27e2a7..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomSwimTarget.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; - -/** - * Set a random position to swim to.
    - * Defaults: - *
      - *
    • 1x movespeed modifier
    • - *
    • 10-block lateral radius
    • - *
    • 10-block vertical radius
    • - *
    - * @param - */ -public class SetRandomSwimTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected BiFunction speedModifier = (entity, targetPos) -> 1f; - protected SquareRadius radius = new SquareRadius(10, 7); - protected BiPredicate positionPredicate = (entity, pos) -> true; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the radius in which to look for swim positions. - * @param radius The coordinate radius, in blocks - * @return this - */ - public SetRandomSwimTarget setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for swim positions. - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SetRandomSwimTarget setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param modifier The movespeed modifier/multiplier - * @return this - */ - public SetRandomSwimTarget speedModifier(float modifier) { - return speedModifier((entity, targetPos) -> modifier); - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param function The movespeed modifier/multiplier function - * @return this - */ - public SetRandomSwimTarget speedModifier(BiFunction function) { - this.speedModifier = function; - - return this; - } - - /** - * Sets a predicate to check whether the target movement position is valid or not - * @param predicate The predicate - * @return this - */ - public SetRandomSwimTarget swimTargetPredicate(BiPredicate predicate) { - this.positionPredicate = predicate; - - return this; - } - - @Override - protected void start(E entity) { - Vec3 targetPos = getTargetPos(entity); - - if (!this.positionPredicate.test(entity, targetPos)) - targetPos = null; - - if (targetPos == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0)); - } - } - - @Nullable - protected Vec3 getTargetPos(E entity) { - return BehaviorUtils.getRandomSwimmablePos(entity, (int)this.radius.xzRadius(), (int)this.radius.yRadius()); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomWalkTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomWalkTarget.java deleted file mode 100644 index 7a86c2deb..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetRandomWalkTarget.java +++ /dev/null @@ -1,148 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.entity.ai.util.DefaultRandomPos; -import net.minecraft.world.entity.ai.util.LandRandomPos; -import net.minecraft.world.phys.Vec3; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.Predicate; - -/** - * Set a random position to walk to.
    - * Defaults: - *
      - *
    • 1x movespeed modifier
    • - *
    • 10-block lateral radius
    • - *
    • 7-block vertical radius
    • - *
    • Avoids walk targets with fluid
    • - *
    - * @param - */ -public class SetRandomWalkTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected BiFunction speedModifier = (entity, targetPos) -> 1f; - protected Predicate avoidWaterPredicate = entity -> true; - protected SquareRadius radius = new SquareRadius(10, 7); - protected BiPredicate positionPredicate = (entity, pos) -> true; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the radius in which to look for walk positions. - * @param radius The coordinate radius, in blocks - * @return this - */ - public SetRandomWalkTarget setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius in which to look for walk positions. - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SetRandomWalkTarget setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param modifier The movespeed modifier/multiplier - * @return this - */ - public SetRandomWalkTarget speedModifier(float modifier) { - return speedModifier((entity, targetPos) -> modifier); - } - - /** - * Set the movespeed modifier for the path when chosen. - * @param function The movespeed modifier/multiplier function - * @return this - */ - public SetRandomWalkTarget speedModifier(BiFunction function) { - this.speedModifier = function; - - return this; - } - - /** - * Sets a predicate to check whether the target movement position is valid or not - * @param predicate The predicate - * @return this - */ - public SetRandomWalkTarget walkTargetPredicate(BiPredicate predicate) { - this.positionPredicate = predicate; - - return this; - } - - /** - * Sets the behaviour to allow finding of positions that might be in water.
    - * Useful for hybrid or water-based entities. - * @return this - */ - public SetRandomWalkTarget dontAvoidWater() { - return avoidWaterWhen(entity -> false); - } - - /** - * Set the predicate to determine when the entity should avoid water walk targets; - * @param predicate The predicate - * @return this - */ - public SetRandomWalkTarget avoidWaterWhen(Predicate predicate) { - this.avoidWaterPredicate = predicate; - - return this; - } - - @Override - protected void start(E entity) { - Vec3 targetPos = getTargetPos(entity); - - if (!this.positionPredicate.test(entity, targetPos)) - targetPos = null; - - if (targetPos == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.WALK_TARGET); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(targetPos, this.speedModifier.apply(entity, targetPos), 0)); - } - } - - @Nullable - protected Vec3 getTargetPos(E entity) { - if (this.avoidWaterPredicate.test(entity)) { - return LandRandomPos.getPos(entity, (int)this.radius.xzRadius(), (int)this.radius.yRadius()); - } - else { - return DefaultRandomPos.getPos(entity, (int)this.radius.xzRadius(), (int)this.radius.yRadius()); - } - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToAttackTarget.java deleted file mode 100644 index 369402c91..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToAttackTarget.java +++ /dev/null @@ -1,88 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.ToIntBiFunction; - -/** - * Set the walk target of the entity to its current attack target. - * @param The entity - */ -public class SetWalkTargetToAttackTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT)); - - @Deprecated(forRemoval = true) - protected float speedModifier = 1; - protected BiFunction speedMod = (owner, target) -> 1f; - protected ToIntBiFunction closeEnoughWhen = (owner, target) -> 0; - - /** - * Set the movespeed modifier for the entity when moving to the target. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - @Deprecated(forRemoval = true) - public SetWalkTargetToAttackTarget speedMod(float speedModifier) { - return speedMod((owner, target) -> speedModifier); - } - - /** - * Set the movespeed modifier for the entity when moving to the target. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public SetWalkTargetToAttackTarget speedMod(BiFunction speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Sets the amount (in blocks) that the mob can be considered 'close enough' to their target that they can stop pathfinding - * @param closeEnoughMod The distance modifier - * @return this - */ - public SetWalkTargetToAttackTarget closeEnoughDist(ToIntBiFunction closeEnoughMod) { - this.closeEnoughWhen = closeEnoughMod; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected void start(E entity) { - Brain brain = entity.getBrain(); - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - - if (entity.getSensing().hasLineOfSight(target) && BehaviorUtils.isWithinAttackRange(entity, target, 1)) { - BrainUtils.clearMemory(brain, MemoryModuleType.WALK_TARGET); - } - else { - BrainUtils.setMemory(brain, MemoryModuleType.LOOK_TARGET, new EntityTracker(target, true)); - BrainUtils.setMemory(brain, MemoryModuleType.WALK_TARGET, new WalkTarget(new EntityTracker(target, false), this.speedMod.apply(entity, target), this.closeEnoughWhen.applyAsInt(entity, target))); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToBlock.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToBlock.java deleted file mode 100644 index f931516e4..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/path/SetWalkTargetToBlock.java +++ /dev/null @@ -1,101 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.path; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.PathfinderMob; -import net.minecraft.world.entity.ai.behavior.BlockPosTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.WalkTarget; -import net.minecraft.world.level.block.state.BlockState; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; - -/** - * Path setting behaviour for walking to/near a block position. - * @param The entity - */ -public class SetWalkTargetToBlock extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(SBLMemoryTypes.NEARBY_BLOCKS.get(), MemoryStatus.VALUE_PRESENT)); - - protected BiPredicate> predicate = (entity, block) -> true; - protected BiFunction, Float> speedMod = (owner, pos) -> 1f; - protected BiFunction, Integer> closeEnoughDist = (entity, pos) -> 2; - - protected Pair target = null; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Set the predicate to determine whether a given position/state should be the target path - * @param predicate The predicate - * @return this - */ - public SetWalkTargetToBlock predicate(final BiPredicate> predicate) { - this.predicate = predicate; - - return this; - } - - /** - * Set the movespeed modifier for the entity when moving to the target. - * @param speedModifier The movespeed modifier/multiplier - * @return this - */ - public SetWalkTargetToBlock speedMod(BiFunction, Float> speedModifier) { - this.speedMod = speedModifier; - - return this; - } - - /** - * Set the distance (in blocks) that is 'close enough' for the entity to be considered at the target position - * @param function The function - * @return this - */ - public SetWalkTargetToBlock closeEnoughWhen(final BiFunction, Integer> function) { - this.closeEnoughDist = function; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - for (Pair position : BrainUtils.getMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get())) { - if (this.predicate.test(entity, position)) { - this.target = position; - - break; - } - } - - return this.target != null; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.WALK_TARGET, new WalkTarget(this.target.getFirst(), this.speedMod.apply(entity, this.target), this.closeEnoughDist.apply(entity, this.target))); - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new BlockPosTracker(this.target.getFirst())); - } - - @Override - protected void stop(E entity) { - this.target = null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/InvalidateAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/InvalidateAttackTarget.java deleted file mode 100644 index 69a084f6b..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/InvalidateAttackTarget.java +++ /dev/null @@ -1,98 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; -import java.util.function.BiPredicate; - -/** - * Invalidates the current {@link MemoryModuleType#ATTACK_TARGET attack target} if the given conditions are met.
    - * Defaults: - *
      - *
    • Will give up trying to path to the target if it hasn't been able to reach it in 200 ticks
    • - *
    • Invalidates the target if it's a creative or spectator mode player
    • - *
    - */ -public class InvalidateAttackTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryStatus.REGISTERED)); - - protected BiPredicate customPredicate = (entity, target) -> target instanceof Player pl && (pl.isCreative() || pl.isSpectator()); - protected long pathfindingAttentionSpan = 200; - - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - /** - * Sets a custom predicate to invalidate the attack target if none of the previous checks invalidate it first.
    - * Overrides the default player gamemode check - */ - public InvalidateAttackTarget invalidateIf(BiPredicate predicate) { - this.customPredicate = predicate; - - return this; - } - - /** - * Skips the check to see if the entity has been unable to path to its target for a while - */ - public InvalidateAttackTarget ignoreFailedPathfinding() { - return stopTryingToPathAfter(0); - } - - /** - * Sets the attention span for the brain owner's pathfinding. If the entity has been unable to find a good path to - * the target after this time, it will invalidate the target. - */ - public InvalidateAttackTarget stopTryingToPathAfter(long ticks) { - this.pathfindingAttentionSpan = ticks; - - return this; - } - - @Override - protected void start(E entity) { - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - - if (target == null) - return; - - if (isTargetInvalid(entity, target) || !canAttack(entity, target) || - isTiredOfPathing(entity) || this.customPredicate.test(entity, target)) { - BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } - } - - protected boolean isTargetInvalid(E entity, LivingEntity target) { - if (entity.level() != target.level()) - return true; - - return target.isDeadOrDying() || target.isRemoved(); - } - - protected boolean canAttack(E entity, LivingEntity target) { - return entity.canAttack(target); - } - - protected boolean isTiredOfPathing(E entity) { - if (this.pathfindingAttentionSpan <= 0) - return false; - - Long time = BrainUtils.getMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - return time != null && entity.level().getGameTime() - time > this.pathfindingAttentionSpan; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAdditionalAttackTargets.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAdditionalAttackTargets.java deleted file mode 100644 index 4ddf6f4ba..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAdditionalAttackTargets.java +++ /dev/null @@ -1,137 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.object.TriPredicate; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.apache.logging.log4j.util.TriConsumer; - -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -/** - * Special-case behaviour for setting secondary, tertiary, etc attack targets.
    - * This is useful for entities that concurrently target multiple entities, and use additional memory modules to store the additional targets.
    - * Uses {@link MemoryModuleType#NEAREST_PLAYERS} and {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} for its retrieval of additional targets.
    - * This behaviour will skip the usual pathing and alerting functionality as it is assumed they will be handled under the primary target.
    - *
    - * Defaults:
    - *
      - *
    • Will target any not-invulnerable player
    • - *
    • Avoids setting memories if a previous memory in the list is already set to the same target, and including {@link MemoryModuleType#ATTACK_TARGET}
    • - *
    - */ -public class SetAdditionalAttackTargets extends ExtendedBehaviour { - private final List> targetingMemories = new ObjectArrayList<>(); - - protected TriPredicate, LivingEntity> canAttackPredicate = (owner, memory, target) -> target.isAlive() && target instanceof Player player && !player.getAbilities().invulnerable; - protected TriConsumer, LivingEntity> targetCallback = (owner, memory, target) -> {}; - protected boolean avoidDuplicateTargets = true; - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return List.of(); - } - - /** - * Set the predicate to determine whether a given entity should be targeted or not. - * @param predicate The predicate - * @return this - */ - public SetAdditionalAttackTargets attackablePredicate(TriPredicate, LivingEntity> predicate) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Sets the callback for when a target is being successfully set to a memory. - */ - public SetAdditionalAttackTargets whenTargeting(TriConsumer, LivingEntity> callback) { - this.targetCallback = callback; - - return this; - } - - /** - * Add {@link MemoryModuleType memories} to the list of tertiary memories to set targets for.
    - * This appends to any existing memories already added to this behaviour, and the functionality of this behaviour is order-dependent. - */ - public SetAdditionalAttackTargets withMemories(MemoryModuleType... targetMemories) { - this.targetingMemories.addAll(List.of(targetMemories)); - - return this; - } - - /** - * Allow for the tertiary target memories to be set to the same as the previous modules if no new target is available - */ - public SetAdditionalAttackTargets allowDuplicateTargeting() { - this.avoidDuplicateTargets = false; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - - for (MemoryModuleType memory : this.targetingMemories) { - if (!BrainUtils.hasMemory(brain, memory)) - return true; - } - - return BrainUtils.hasMemory(brain, MemoryModuleType.NEAREST_PLAYERS) || BrainUtils.hasMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); - } - - @Override - protected void start(E entity) { - Brain brain = entity.getBrain(); - Set targetPool = new ObjectOpenHashSet<>(); - - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_PLAYERS, targetPool::addAll); - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, memory -> memory.findAll(target -> true).forEach(targetPool::add)); - - if (targetPool.isEmpty()) - return; - - for (MemoryModuleType memory : this.targetingMemories) { - LivingEntity target = BrainUtils.getMemory(brain, memory); - - if (target == null) { - LivingEntity newTarget = null; - - for (Iterator iterator = targetPool.iterator(); iterator.hasNext(); newTarget = null) { - newTarget = iterator.next(); - - if (this.canAttackPredicate.test(entity, memory, newTarget)) { - BrainUtils.setMemory(brain, (MemoryModuleType)memory, newTarget); - this.targetCallback.accept(entity, memory, newTarget); - iterator.remove(); - - break; - } - } - - if (newTarget != null && !this.avoidDuplicateTargets) - targetPool.add(newTarget); - } - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAttackTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAttackTarget.java deleted file mode 100644 index 58c526ea2..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetAttackTarget.java +++ /dev/null @@ -1,90 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * Sets the attack target of the entity if one is available.
    - * Defaults: - *
      - *
    • Will target anything set as the {@link MemoryModuleType#NEAREST_ATTACKABLE} memory
    • - *
    - * @see net.minecraft.world.entity.ai.behavior.StartAttacking - */ -public class SetAttackTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.NEAREST_ATTACKABLE, MemoryStatus.VALUE_PRESENT)); - private static final List, MemoryStatus>> CUSTOM_TARGETING_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected final boolean usingNearestAttackable; - protected Predicate canAttackPredicate = entity -> true; - protected Function targetFinder = entity -> BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE); - - public SetAttackTarget() { - this(true); - } - - public SetAttackTarget(boolean usingNearestAttackable) { - this.usingNearestAttackable = usingNearestAttackable; - } - - /** - * Set the predicate to determine whether the entity is ready to attack or not. - * @param predicate The predicate - * @return this - */ - public SetAttackTarget attackPredicate(Predicate predicate) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Set the target finding function. If replacing the {@link MemoryModuleType#NEAREST_ATTACKABLE} memory retrieval, set false in the constructor of the behaviour. - * @param targetFindingFunction The function - * @return this - */ - public SetAttackTarget targetFinder(Function targetFindingFunction) { - this.targetFinder = targetFindingFunction; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return this.usingNearestAttackable ? MEMORY_REQUIREMENTS : CUSTOM_TARGETING_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return this.canAttackPredicate.test(entity); - } - - @Override - protected void start(E entity) { - LivingEntity target = this.targetFinder.apply(entity); - - if (target == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.ATTACK_TARGET, target); - BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetPlayerLookTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetPlayerLookTarget.java deleted file mode 100644 index 7c59a63fb..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetPlayerLookTarget.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.EntityTracker; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; -import java.util.function.Predicate; - -/** - * Set the {@link MemoryModuleType#LOOK_TARGET} of the brain owner from {@link MemoryModuleType#NEAREST_PLAYERS} - * @param The entity - */ -public class SetPlayerLookTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.NEAREST_PLAYERS, MemoryStatus.VALUE_PRESENT)); - - protected Predicate predicate = pl -> true; - - protected Player target = null; - - /** - * Set the predicate for the player to look at. - * @param predicate The predicate - * @return this - */ - public SetPlayerLookTarget predicate(Predicate predicate) { - this.predicate = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - for (Player player : BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_PLAYERS)) { - if (this.predicate.test(player)) { - this.target = player; - - break; - } - } - - return this.target != null; - } - - @Override - protected void start(E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.LOOK_TARGET, new EntityTracker(this.target, true)); - } - - @Override - protected void stop(E entity) { - this.target = null; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRandomLookTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRandomLookTarget.java deleted file mode 100644 index b5a58c917..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRandomLookTarget.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.Mth; -import net.minecraft.util.valueproviders.ConstantFloat; -import net.minecraft.util.valueproviders.FloatProvider; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.object.FreePositionTracker; - -import java.util.List; -import java.util.function.Function; - -/** - * Set the look target to a random nearby position - * @param The entity - */ -public class SetRandomLookTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORIES = ObjectArrayList.of(Pair.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected FloatProvider runChance = ConstantFloat.of(0.02f); - protected Function lookTime = entity -> entity.getRandom().nextInt(20) + 20; - - /** - * Set the value provider for the chance of the look target being set. - * @param chance The float provider - * @return this - */ - public SetRandomLookTarget lookChance(FloatProvider chance) { - this.runChance = chance; - - return this; - } - - /** - * Set the value provider for how long the entity's look target should be set for - * @param function The tick providing function - * @return this - */ - public SetRandomLookTarget lookTime(Function function) { - this.lookTime = function; - - return this; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E entity) { - return entity.getRandom().nextFloat() < this.runChance.sample(entity.getRandom()); - } - - @Override - protected void start(E entity) { - double angle = Mth.TWO_PI * entity.getRandom().nextDouble(); - - BrainUtils.setForgettableMemory(entity, MemoryModuleType.LOOK_TARGET, new FreePositionTracker(entity.getEyePosition().add(Math.cos(angle), 0, Math.sin(angle))), this.lookTime.apply(entity)); - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORIES; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRetaliateTarget.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRetaliateTarget.java deleted file mode 100644 index 0967202df..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/SetRetaliateTarget.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.TamableAnimal; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -import java.util.List; -import java.util.function.BiPredicate; -import java.util.function.Predicate; - -/** - * Sets the attack target of the entity based on the last entity to hurt it if a target isn't already set.
    - * Defaults: - *
      - *
    • Targets any live entity, as long as it's not a creative mode player
    • - *
    • Does not alert nearby allies when retaliating
    • - *
    • If enabled, only alerts allies of the same class, if they don't already have a target themselves
    • - *
    - * @param The entity - */ -public class SetRetaliateTarget extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.HURT_BY_ENTITY, MemoryStatus.VALUE_PRESENT), Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT)); - - protected Predicate canAttackPredicate = entity -> entity.isAlive() && (!(entity instanceof Player player) || !player.isCreative()); - - protected LivingEntity toTarget = null; - protected BiPredicate alertAlliesPredicate = (owner, attacker) -> false; - protected BiPredicate allyPredicate = (owner, ally) -> owner.getClass().isAssignableFrom(ally.getClass()) && BrainUtils.getTargetOfEntity(ally) == null && (!(owner instanceof TamableAnimal pet) || pet.getOwner() == ((TamableAnimal)ally).getOwner()) && !ally.isAlliedTo(BrainUtils.getMemory(owner, MemoryModuleType.HURT_BY_ENTITY)); - - /** - * Set the predicate to determine whether a given entity should be targeted or not. - * @param predicate The predicate - * @return this - */ - public SetRetaliateTarget attackablePredicate(Predicate predicate) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Set the predicate to determine whether the brain owner should alert nearby allies of the same entity type when retaliating - * @param predicate The predicate - * @return this - */ - public SetRetaliateTarget alertAlliesWhen(BiPredicate predicate) { - this.alertAlliesPredicate = predicate; - - return this; - } - - /** - * Set the predicate to determine whether a given entity should be alerted to the target as an ally of the brain owner.
    - * Overriding replaces the default predicate, so be sure to include any portions of the default predicate in your own if applicable - * @param predicate The predicate - * @return this - */ - public SetRetaliateTarget isAllyIf(BiPredicate predicate) { - this.allyPredicate = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E owner) { - this.toTarget = BrainUtils.getMemory(owner, MemoryModuleType.HURT_BY_ENTITY); - - if (this.toTarget.isAlive() && this.toTarget.level() == level && this.canAttackPredicate.test(this.toTarget)) { - if (this.alertAlliesPredicate.test(owner, this.toTarget)) - alertAllies(level, owner); - - return true; - } - - return false; - } - - @Override - protected void start(E entity) { - BrainUtils.setTargetOfEntity(entity, this.toTarget); - BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - this.toTarget = null; - } - - protected void alertAllies(ServerLevel level, E owner) { - double followRange = owner.getAttributeValue(Attributes.FOLLOW_RANGE); - - for (LivingEntity ally : EntityRetrievalUtil.getEntities(level, owner.getBoundingBox().inflate(followRange, 10, followRange), - entity -> entity != owner && entity instanceof LivingEntity livingEntity && this.allyPredicate.test(owner, livingEntity))) { - BrainUtils.setTargetOfEntity(ally, this.toTarget); - } - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/TargetOrRetaliate.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/TargetOrRetaliate.java deleted file mode 100644 index 68fc2aeed..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/behaviour/custom/target/TargetOrRetaliate.java +++ /dev/null @@ -1,157 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.behaviour.custom.target; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.*; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.MemoryStatus; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.behaviour.ExtendedBehaviour; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -import java.util.List; -import java.util.function.BiPredicate; -import java.util.function.Predicate; - -/** - * Sets the attack target of the entity, utilising a few sources of targets.
    - * In order: - *
      - *
    1. The {@link MemoryModuleType#NEAREST_ATTACKABLE} memory value
    2. - *
    3. The {@link MemoryModuleType#HURT_BY_ENTITY} memory value
    4. - *
    5. The closest applicable entity from the {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory value
    6. - *
    - * Defaults: - *
      - *
    • Targets any live entity, as long as it's not a creative-mode player
    • - *
    • Does not alert nearby allies when retaliating
    • - *
    • If enabled, only alerts allies of the same class, if they don't already have a target themselves
    • - *
    - * @param The entity - */ -public class TargetOrRetaliate extends ExtendedBehaviour { - private static final List, MemoryStatus>> MEMORY_REQUIREMENTS = ObjectArrayList.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_ABSENT), Pair.of(MemoryModuleType.HURT_BY, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.NEAREST_ATTACKABLE, MemoryStatus.REGISTERED), Pair.of(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.REGISTERED)); - - protected Predicate canAttackPredicate = entity -> entity.isAlive() && (!(entity instanceof Player player) || !player.isCreative()); - protected BiPredicate alertAlliesPredicate = (owner, attacker) -> false; - protected BiPredicate allyPredicate = (owner, ally) -> { - if (!owner.getClass().isAssignableFrom(ally.getClass()) || BrainUtils.getTargetOfEntity(ally) != null) - return false; - - if (owner instanceof OwnableEntity pet && pet.getOwner() != ((OwnableEntity)ally).getOwner()) - return false; - - Entity lastHurtBy = BrainUtils.getMemory(ally, MemoryModuleType.HURT_BY_ENTITY); - - return lastHurtBy == null || !ally.isAlliedTo(lastHurtBy); - }; - - protected LivingEntity toTarget = null; - protected MemoryModuleType priorityTargetMemory = MemoryModuleType.NEAREST_ATTACKABLE; - - /** - * Set the predicate to determine whether a given entity should be targeted or not. - * @param predicate The predicate - * @return this - */ - public TargetOrRetaliate attackablePredicate(Predicate predicate) { - this.canAttackPredicate = predicate; - - return this; - } - - /** - * Set the memory type that is checked first to target an entity. - * Useful for switching to player-only targeting - * @return this - */ - public TargetOrRetaliate useMemory(MemoryModuleType memory) { - this.priorityTargetMemory = memory; - - return this; - } - - /** - * Set the predicate to determine whether the brain owner should alert nearby allies of the same entity type when retaliating - * @param predicate The predicate - * @return this - */ - public TargetOrRetaliate alertAlliesWhen(BiPredicate predicate) { - this.alertAlliesPredicate = predicate; - - return this; - } - - /** - * Set the predicate to determine whether a given entity should be alerted to the target as an ally of the brain owner.
    - * Overriding replaces the default predicate, so be sure to include any portions of the default predicate in your own if applicable - * @param predicate The predicate - * @return this - */ - public TargetOrRetaliate isAllyIf(BiPredicate predicate) { - this.allyPredicate = predicate; - - return this; - } - - @Override - protected List, MemoryStatus>> getMemoryRequirements() { - return MEMORY_REQUIREMENTS; - } - - @Override - protected boolean checkExtraStartConditions(ServerLevel level, E owner) { - Brain brain = owner.getBrain(); - this.toTarget = BrainUtils.getMemory(brain, this.priorityTargetMemory); - - if (this.toTarget == null) { - this.toTarget = BrainUtils.getMemory(brain, MemoryModuleType.HURT_BY_ENTITY); - - if (this.toTarget == null) { - NearestVisibleLivingEntities nearbyEntities = BrainUtils.getMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); - - if (nearbyEntities != null) - this.toTarget = nearbyEntities.findClosest(this.canAttackPredicate).orElse(null); - - if (this.alertAlliesPredicate.test(owner, this.toTarget)) - alertAllies(level, owner); - - if (this.toTarget == null) - return false; - } - } - - if (this.alertAlliesPredicate.test(owner, this.toTarget)) - alertAllies(level, owner); - - return this.canAttackPredicate.test(this.toTarget); - } - - @Override - protected void start(E entity) { - BrainUtils.setTargetOfEntity(entity, this.toTarget); - BrainUtils.clearMemory(entity, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - this.toTarget = null; - } - - protected void alertAllies(ServerLevel level, E owner) { - double followRange = owner.getAttributeValue(Attributes.FOLLOW_RANGE); - - for (LivingEntity ally : EntityRetrievalUtil.getEntities(level, owner.getBoundingBox().inflate(followRange, 10, followRange), - entity -> entity != owner && entity instanceof LivingEntity livingEntity && this.allyPredicate.test(owner, livingEntity))) { - BrainUtils.setTargetOfEntity(ally, this.toTarget); - } - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/ExtendedNavigator.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/ExtendedNavigator.java deleted file mode 100644 index fe5b48f79..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/ExtendedNavigator.java +++ /dev/null @@ -1,302 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.PathNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.PathNavigationRegion; -import net.minecraft.world.level.chunk.BulkSectionAccess; -import net.minecraft.world.level.pathfinder.*; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -import java.util.Set; - -/** - * Extracted interface to act as a helper utility for cleaner navigator implementations - *

    - * This expands on Vanilla's navigator functionality, fixing some issues, optimising it, and splitting it out to be properly extensible - */ -public interface ExtendedNavigator { - /** - * Minimum threshold representing a rounding error for the purposes of bounds collision - */ - float EPSILON = 1.0E-8F; - - /** - * Helper overload getter for retrieving the entity from {@link PathNavigation#mob} - */ - Mob getMob(); - - /** - * Helper overload getter for retrieving the path from {@link PathNavigation#path} - */ - Path getPath(); - - /** - * @return Whether the given path type can be pathed onto, or otherwise be considered a pathable surface - */ - default boolean canPathOnto(PathType pathType) { - return switch (pathType) { - case WATER, LAVA, OPEN -> false; - default -> true; - }; - } - - /** - * @return Whether the given path type should be considered safe to path into, or is otherwise a pathable free space - */ - default boolean canPathInto(PathType pathType) { - return switch (pathType) { - case DAMAGE_FIRE, DANGER_FIRE, DAMAGE_OTHER -> true; - default -> false; - }; - } - - /** - * Determine whether the entity should be considered close enough to the next node to be counted as having reached it - * - * @param distance The distance threshold which counts as 'close enough' to the next node - * @return Whether the entity is within reach of the next node in the path - * @see PathNavigation#getMaxDistanceToWaypoint() - */ - default boolean isCloseToNextNode(float distance) { - final Mob mob = getMob(); - final Path path = getPath(); - final Vec3 nextNodePos = getEntityPosAtNode(path.getNextNodeIndex()); - - return Math.abs(mob.getX() - nextNodePos.x) < distance && - Math.abs(mob.getZ() - nextNodePos.z) < distance && - Math.abs(mob.getY() - nextNodePos.y) < 1; - } - - /** - * @return Whether the path the mob is following is about to cause a change in elevation (either up or down), accounting for potentially skippable nodes based on the entity's stride size - */ - default boolean isAboutToTraverseVertically() { - final Mob mob = getMob(); - final Path path = getPath(); - final int fromNode = path.getNextNodeIndex(); - final int fromNodeHeight = path.getNode(fromNode).y; - final int toNode = Math.min(path.getNodeCount(), fromNode + Mth.ceil(mob.getBbWidth() * 0.5d) + 1); - - for (int i = fromNode + 1; i < toNode; i++) { - if (path.getNode(i).y != fromNodeHeight) - return true; - } - - return false; - } - - /** - * Wrap a Path instance in a new instance, patching out the {@link Path#getEntityPosAtNode(Entity, int)} implementation for smoother pathing - * - * @return A new Path instance, or null if the input Path was null - */ - @Nullable - default Path patchPath(@Nullable Path path) { - return path == null ? null : new Path(path.nodes, path.getTarget(), path.canReach()) { - @Override - public Vec3 getEntityPosAtNode(Entity entity, int nodeIndex) { - return ExtendedNavigator.this.getEntityPosAtNode(nodeIndex); - } - }; - } - - /** - * Create a PathFinder instance patching out the {@link Path#getEntityPosAtNode(Entity, int)} implementation for smoother pathing - */ - default PathFinder createSmoothPathFinder(NodeEvaluator nodeEvaluator, int maxVisitedNodes) { - return new PathFinder(nodeEvaluator, maxVisitedNodes) { - @Nullable - @Override - public Path findPath(PathNavigationRegion navigationRegion, Mob mob, Set targetPositions, float maxRange, int accuracy, float searchDepthMultiplier) { - return patchPath(super.findPath(navigationRegion, mob, targetPositions, maxRange, accuracy, searchDepthMultiplier)); - } - }; - } - - /** - * Attempt to skip to the target node, bypassing the intermediate notes depending on bounds collision for the intervening distance - *

    - * Typically, the target node should already have been checked for proximal relevance, as otherwise this could cause node skips to act strangely - * - * @param targetNode The target node index to shortcut to - * @param safeSurfacePos The baseline position of where the mob should traverse to (usually the nearest ground pos or surface of the fluid it's submerged in) - * @return Whether the shortcut was successful or not - */ - default boolean attemptShortcut(int targetNode, Vec3 safeSurfacePos) { - final Mob mob = getMob(); - final Path path = getPath(); - final Vec3 position = mob.position(); - final Vec3 minBounds = safeSurfacePos.add(-mob.getBbWidth() * 0.5d, 0, -mob.getBbWidth() * 0.5d); - final Vec3 maxBounds = minBounds.add(mob.getBbWidth(), mob.getBbHeight(), mob.getBbWidth()); - - for (int nodeIndex = targetNode - 1; nodeIndex > path.getNextNodeIndex(); nodeIndex--) { - final Vec3 nodeDelta = getEntityPosAtNode(nodeIndex).subtract(position); - - if (isCollisionFreeTraversal(nodeDelta, minBounds, maxBounds)) { - path.setNextNodeIndex(nodeIndex); - - return true; - } - } - - return false; - } - - /** - * Get the entity's predicted position at the time they reach the given node - *

    - * Functionally replaces {@link Path#getEntityPosAtNode} to better handle the double rounding - * - * @param nodeIndex The index of the node to check - * @return The approximate position of the entity for the given node - */ - default Vec3 getEntityPosAtNode(int nodeIndex) { - final Mob mob = getMob(); - final Path path = getPath(); - final double lateralOffset = Mth.floor(mob.getBbWidth() + 1d) / 2d; - - return Vec3.atLowerCornerOf(path.getNodePos(nodeIndex)).add(lateralOffset, 0, lateralOffset); - } - - /** - * Recursively sweep the edges of a given area, identifying collisions for colliding faces of a pseudo-bounds determined by ray-casts - * projected from the bounds leading edge, then cross-checking interceptions for the relevant face. - *

    - * This is a quick algorithm based on Andy Hall's voxel-aabb-sweep - * - * @param traversalVector The vector that represents the angle and length of traversal to cover - * @param minBoundsPos The negative-most position representing the minimum corner of the bounds - * @param leadingEdgePos The positive-most position representing the maximum corner of the bounds - * @return Whether the given traversal is free from collisions - */ - default boolean isCollisionFreeTraversal(Vec3 traversalVector, Vec3 minBoundsPos, Vec3 leadingEdgePos) { - final float traversalDistance = (float)traversalVector.length(); - - if (traversalDistance < EPSILON) - return true; - - final VoxelRayDetails ray = new VoxelRayDetails(); - - for (Direction.Axis axis : Direction.Axis.values()) { - final int index = axis.ordinal(); - final float axisLength = lengthForAxis(traversalVector, axis); - final boolean isPositive = axisLength >= 0; - final float maxPos = lengthForAxis(isPositive ? leadingEdgePos : minBoundsPos, axis); - - ray.absStep[index] = isPositive ? 1 : -1; - ray.minPos[index] = lengthForAxis(isPositive ? minBoundsPos : leadingEdgePos, axis); - ray.leadingEdgeBound[index] = Mth.floor(maxPos - ray.absStep[index] * EPSILON); - ray.trailingEdgeBound[index] = Mth.floor(ray.minPos[index] + ray.absStep[index] * EPSILON); - ray.axisLengthNormalised[index] = axisLength / traversalDistance; - ray.axisSteps[index] = Mth.abs(traversalDistance / axisLength); - final float dist = isPositive ? (ray.leadingEdgeBound[index] + 1 - maxPos) : (maxPos - ray.leadingEdgeBound[index]); - ray.rayTargetLength[index] = ray.axisSteps[index] < Float.POSITIVE_INFINITY ? ray.axisSteps[index] * dist : Float.POSITIVE_INFINITY; - } - - return collidesWhileTraversing(ray, traversalDistance); - } - - /** - * @param ray The details container for the ray traversal - * @param traversalDistance The direct length of the traversal vector - * @return Whether the given bounds would collide for the given trajectory - */ - default boolean collidesWhileTraversing(VoxelRayDetails ray, float traversalDistance) { - final Mob mob = getMob(); - final Level level = mob.level(); - - try (BulkSectionAccess sectionAccess = new BulkSectionAccess(level)) { - final NodeEvaluator nodeEvaluator = mob.getNavigation().getNodeEvaluator(); - final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); - float target = 0; - - do { - final Direction.Axis longestEdge = ray.rayTargetLength[0] < ray.rayTargetLength[1] ? - ray.rayTargetLength[0] < ray.rayTargetLength[2] ? Direction.Axis.X : Direction.Axis.Z : - ray.rayTargetLength[1] < ray.rayTargetLength[2] ? Direction.Axis.Y : Direction.Axis.Z; - final int index = longestEdge.ordinal(); - final float rayDelta = ray.rayTargetLength[index] - target; - target = ray.rayTargetLength[index]; - ray.leadingEdgeBound[index] += ray.absStep[index]; - ray.rayTargetLength[index] += ray.axisSteps[index]; - - for (Direction.Axis axis : Direction.Axis.values()) { - final int index2 = axis.ordinal(); - ray.minPos[index2] += rayDelta * ray.axisLengthNormalised[index2]; - ray.trailingEdgeBound[index2] = Mth.floor(ray.minPos[index2] + ray.absStep[index2] * EPSILON); - } - - final int xStep = ray.absStep[0]; - final int yStep = ray.absStep[1]; - final int zStep = ray.absStep[2]; - final int xBound = longestEdge == Direction.Axis.X ? ray.leadingEdgeBound[0] : ray.trailingEdgeBound[0]; - final int yBound = longestEdge == Direction.Axis.Y ? ray.leadingEdgeBound[1] : ray.trailingEdgeBound[1]; - final int zBound = longestEdge == Direction.Axis.Z ? ray.leadingEdgeBound[2] : ray.trailingEdgeBound[2]; - final int xStepBound = ray.leadingEdgeBound[0] + xStep; - final int yStepBound = ray.leadingEdgeBound[1] + yStep; - final int zStepBound = ray.leadingEdgeBound[2] + zStep; - - for (int x = xBound; x != xStepBound; x += xStep) { - for (int z = zBound; z != zStepBound; z += zStep) { - for (int y = yBound; y != yStepBound; y += yStep) { - if (!sectionAccess.getBlockState(pos.set(x, y, z)).isPathfindable(PathComputationType.LAND)) - return false; - } - - if (!canPathOnto(nodeEvaluator.getPathType(new PathfindingContext(level, mob), x, yBound - 1, z))) - return false; - - final PathType insidePathType = nodeEvaluator.getPathType(new PathfindingContext(level, mob), x, yBound, z); - final float pathMalus = mob.getPathfindingMalus(insidePathType); - - if (pathMalus < 0 || pathMalus >= 8) - return false; - - if (canPathInto(insidePathType)) - return false; - } - } - } while (target <= traversalDistance); - } - - return true; - } - - /** - * Container object for voxel ray traversal details - *

    - * Each array represent [x, y, z] vector coordinates - * - * @param minPos The minimum-pos coordinate for the given axis - * @param leadingEdgeBound The maximum-pos axis-aligned coordinate for the given axis - * @param trailingEdgeBound The mimimum-pos axis-aligned coordinate for the given axis - * @param absStep -1 or 1 value representing which direction to step for each axis - * @param axisSteps How many lengths of the given axis required to traverse the full distance - * @param rayTargetLength How long the ray should be to account for traversal - * @param axisLengthNormalised Fraction of the full distance the given length of this axis represents - */ - record VoxelRayDetails(float[] minPos, int[] leadingEdgeBound, int[] trailingEdgeBound, int[] absStep, float[] axisSteps, float[] rayTargetLength, float[] axisLengthNormalised) { - public VoxelRayDetails() { - this(new float[3], new int[3], new int[3], new int[3], new float[3], new float[3], new float[3]); - } - } - - /** - * @return The vector length for the given axis - */ - default float lengthForAxis(Vec3 vector, Direction.Axis axis) { - return (float)axis.choose(vector.x, vector.y, vector.z); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothAmphibiousPathNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothAmphibiousPathNavigation.java deleted file mode 100644 index 662364dd8..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothAmphibiousPathNavigation.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.AmphibiousPathNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.AmphibiousNodeEvaluator; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; -import org.jetbrains.annotations.Nullable; - -/** - * Extension of the vanilla {@link AmphibiousPathNavigation} with some tweaks for smoother pathfinding: - *

      - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Extensible {@link #prefersShallowSwimming()} implementation for ease-of-use
    • - *
    - *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based walking entity - */ -public class SmoothAmphibiousPathNavigation extends AmphibiousPathNavigation implements ExtendedNavigator { - public SmoothAmphibiousPathNavigation(Mob mob, Level level) { - super(mob, level); - } - - /** - * Determine whether the navigator should prefer shallow swimming patterns - *

    - * Adjusts path node penalty when determining paths - */ - public boolean prefersShallowSwimming() { - return false; - } - - @Override - public Mob getMob() { - return this.mob; - } - - @Nullable - @Override - public Path getPath() { - return super.getPath(); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new AmphibiousNodeEvaluator(prefersShallowSwimming()); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothFlyingPathNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothFlyingPathNavigation.java deleted file mode 100644 index 4b8f5a817..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothFlyingPathNavigation.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.FlyNodeEvaluator; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; -import org.jetbrains.annotations.Nullable; - -/** - * Extension of the vanilla {@link FlyingPathNavigation} with some tweaks for smoother pathfinding: - *

      - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    - *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based walking entity - */ -public class SmoothFlyingPathNavigation extends FlyingPathNavigation implements ExtendedNavigator { - public SmoothFlyingPathNavigation(Mob mob, Level level) { - super(mob, level); - } - - @Override - public Mob getMob() { - return this.mob; - } - - @Nullable - @Override - public Path getPath() { - return super.getPath(); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new FlyNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothGroundNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothGroundNavigation.java deleted file mode 100644 index 7ed2f8325..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothGroundNavigation.java +++ /dev/null @@ -1,105 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; -import net.minecraft.world.entity.ai.navigation.PathNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; -import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; - -/** - * Extension of the vanilla {@link GroundPathNavigation} with some tweaks for smoother pathfinding: - *

      - *
    • Smoothed unit rounding to better accommodate edge-cases
    • - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Skip to vertical traversal first before continuing path nodes if appropriate
    • - *
    • Accessible {@link GroundPathNavigation#getSurfaceY()} override for extensibility
    • - *
    - *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based walking entity - * @see ExtendedNavigator#canPathOnto - * @see ExtendedNavigator#canPathInto - */ -public class SmoothGroundNavigation extends GroundPathNavigation implements ExtendedNavigator { - public SmoothGroundNavigation(Mob mob, Level level) { - super(mob, level); - } - - @Override - public Mob getMob() { - return this.mob; - } - - @Nullable - @Override - public Path getPath() { - return super.getPath(); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new WalkNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } - - @Override - protected void followThePath() { - final Vec3 safeSurfacePos = getTempMobPos(); - final int shortcutNode = getClosestVerticalTraversal(Mth.floor(safeSurfacePos.y)); - this.maxDistanceToWaypoint = this.mob.getBbWidth() > 0.75f ? this.mob.getBbWidth() / 2f : 0.75f - this.mob.getBbWidth() / 2f; - - if (!attemptShortcut(shortcutNode, safeSurfacePos)) { - if (isCloseToNextNode(0.5f) || isAboutToTraverseVertically() && isCloseToNextNode(getMaxDistanceToWaypoint())) - this.path.advance(); - } - - doStuckDetection(safeSurfacePos); - } - - /** - * Helper override to allow end-users to modify the fluids an entity can swim in - *

    - * If using this to modify swimmable fluids, ensure you also override {@link PathNavigation#canUpdatePath()} as well - * - * @return The nearest safe surface height for the entity - */ - @Override - public int getSurfaceY() { - return super.getSurfaceY(); - } - - /** - * Find the nearest node in the path that accounts for a vertical traversal (either up or down) - *

    - * This can then be used to test if a collision-free traversal can be made, skipping the intermediate nodes as appropriate - * - * @param safeSurfaceHeight The baseline floored y-pos of where the mob should traverse to (usually the nearest ground pos or surface of the fluid it's submerged in) - * - * @return The node index for the nearest node representing a vertical traversal - */ - protected int getClosestVerticalTraversal(int safeSurfaceHeight) { - final int nodesLength = this.path.getNodeCount(); - - for (int nodeIndex = this.path.getNextNodeIndex(); nodeIndex < nodesLength; nodeIndex++) { - if (this.path.getNode(nodeIndex).y != safeSurfaceHeight) - return nodeIndex; - } - - return nodesLength; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWallClimberNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWallClimberNavigation.java deleted file mode 100644 index 9b9ee4a92..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWallClimberNavigation.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.GroundPathNavigation; -import net.minecraft.world.entity.ai.navigation.PathNavigation; -import net.minecraft.world.entity.ai.navigation.WallClimberNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; -import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; -import org.jetbrains.annotations.Nullable; - -/** - * Extension of the vanilla {@link WallClimberNavigation} with some tweaks for smoother pathfinding: - *

      - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Accessible {@link GroundPathNavigation#getSurfaceY()} override for extensibility
    • - *
    - *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a ground-based walking entity - */ -public class SmoothWallClimberNavigation extends WallClimberNavigation implements ExtendedNavigator { - public SmoothWallClimberNavigation(Mob mob, Level level) { - super(mob, level); - } - - @Override - public Mob getMob() { - return this.mob; - } - - @Nullable - @Override - public Path getPath() { - return super.getPath(); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new WalkNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } - - /** - * Helper override to allow end-users to modify the fluids an entity can swim in - *

    - * If using this to modify swimmable fluids, ensure you also override {@link PathNavigation#canUpdatePath()} as well - * - * @return The nearest safe surface height for the entity - */ - @Override - public int getSurfaceY() { - return super.getSurfaceY(); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWaterBoundPathNavigation.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWaterBoundPathNavigation.java deleted file mode 100644 index 457b0f4cc..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/navigation/SmoothWaterBoundPathNavigation.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.navigation; - -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.navigation.WaterBoundPathNavigation; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; -import net.minecraft.world.level.pathfinder.SwimNodeEvaluator; -import org.jetbrains.annotations.Nullable; - -/** - * Extension of the vanilla {@link WaterBoundPathNavigation} navigator with some tweaks for smoother pathfinding: - *

      - *
    • Smoothed unit rounding to better accommodate edge-cases
    • - *
    • Patched {@link Path} implementation to use proper rounding
    • - *
    • Extensible {@link #canBreach()} implementation for ease-of-use
    • - *
    - *

    - * Override {@link Mob#createNavigation(Level)} and return a new instance of this if your entity is a water-based swimming entity - */ -public class SmoothWaterBoundPathNavigation extends WaterBoundPathNavigation implements ExtendedNavigator { - public SmoothWaterBoundPathNavigation(Mob mob, Level level) { - super(mob, level); - } - - /** - * Determine whether the entity can breach the surface as part of its pathing - *

    - * Defaults to false for non-dolphins - */ - public boolean canBreach() { - return this.mob.getType() == EntityType.DOLPHIN; - } - - @Override - public Mob getMob() { - return this.mob; - } - - @Nullable - @Override - public Path getPath() { - return super.getPath(); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new SwimNodeEvaluator(this.allowBreaching = canBreach()); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/schedule/SmartBrainSchedule.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/schedule/SmartBrainSchedule.java deleted file mode 100644 index fe88cfa59..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/schedule/SmartBrainSchedule.java +++ /dev/null @@ -1,197 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.schedule; - -import com.google.common.collect.ListMultimap; -import com.google.common.collect.MultimapBuilder; -import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.schedule.Activity; -import net.minecraft.world.entity.schedule.Schedule; -import mod.azure.azurelib.sblforked.api.SmartBrainOwner; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.function.Consumer; -import java.util.function.ToIntBiFunction; -import java.util.function.ToIntFunction; - -/** - * SBL-implementation of the vanilla {@link net.minecraft.world.entity.schedule.Schedule Schedule}.
    - * It extends the vanilla {@link Schedule} purely for compatibility reasons, but does not utilise any of its functionality.
    - *
    - * This segment of the Brain system is used to timeline activities, allowing you to run activity groups and tasks on a tick-based schedule.
    - *
    - * Activities scheduled using this system will override the activity priorities from {@link SmartBrainOwner#getActivityPriorities()} at tick time - */ -public class SmartBrainSchedule extends Schedule { - private final Type type; - private final Int2ObjectArrayMap timeline = new Int2ObjectArrayMap<>(0); - private final ListMultimap> callbacks = MultimapBuilder.hashKeys(0).arrayListValues().build(); - - private boolean sortedTimeline = true; - - public SmartBrainSchedule() { - this(Type.DAYTIME); - } - - public SmartBrainSchedule(Type type) { - this.type = type; - } - - /** - * Set the active {@link Activity} for the brain at the given tick/time - * @param tick The tick/time to activate the activity - * @param activity The activity to set as active at the given time - * @return this - */ - public SmartBrainSchedule activityAt(int tick, Activity activity) { - this.timeline.put(tick, activity); - - this.sortedTimeline = false; - - return this; - } - - /** - * Add a callback to run at the given tick - * @param tick The tick/time to run the callback at - * @param callback The callback to run at the given time - * @return this - */ - public SmartBrainSchedule doAt(int tick, Consumer callback) { - this.callbacks.put(tick, callback); - - return this; - } - - /** - * Adds a dynamically-scheduled task for a given tick-time in the future - * @param brainOwner The owner of the brain - * @param delay The delay time (in ticks) before the task should be called - * @param task The task to run after the given delay - */ - public void scheduleTask(LivingEntity brainOwner, int delay, Consumer task) { - this.callbacks.put(this.type.resolveDelay(brainOwner, delay), entity -> task.accept(brainOwner)); - } - - /** - * Remove all entries from the schedule, clearing it out - */ - public void clearSchedule() { - this.callbacks.clear(); - this.timeline.clear(); - } - - /** - * Tick the schedule and return the activity to switch the entity to, if applicable - * @param brainOwner The owner of the brain that contains this schedule - * @return The activity to set as active based on the current tick, or null if none to set - */ - @Nullable - public Activity tick(LivingEntity brainOwner) { - int tick = this.type.resolve(brainOwner); - - if (!this.callbacks.isEmpty()) { - this.callbacks.get(tick).forEach(consumer -> consumer.accept(brainOwner)); - - if (this.type == Type.AGE) - this.callbacks.removeAll(tick); - } - - if (!this.timeline.isEmpty()) { - if (!this.sortedTimeline) - sortTimeline(); - - int index = -1; - Activity activity = null; - - for (Int2ObjectMap.Entry entry : this.timeline.int2ObjectEntrySet()) { - index++; - - if (entry.getIntKey() >= tick) { - if (entry.getIntKey() == tick) - activity = entry.getValue(); - - break; - } - - activity = entry.getValue(); - } - - if (this.type == Type.AGE && index + 1 >= this.timeline.size()) - this.timeline.clear(); - - return activity; - } - - return null; - } - - private void sortTimeline() { - Int2ObjectArrayMap copy = new Int2ObjectArrayMap<>(this.timeline); - int[] keys = copy.keySet().toArray(new int[0]); - - Arrays.sort(keys); - this.timeline.clear(); - - for (int key : keys) { - this.timeline.put(key, copy.get(key)); - } - - this.sortedTimeline = true; - } - - @Override - public final Activity getActivityAt(int tick) { - if (this.type == Type.AGE) - return Activity.IDLE; - - Activity activity = Activity.IDLE; - - for (Int2ObjectMap.Entry entry : this.timeline.int2ObjectEntrySet()) { - if (entry.getIntKey() >= tick) - return activity; - - activity = entry.getValue(); - } - - return activity; - } - - /** - * The type of scheduling this scheduler is using (I.E. how it determines the input tick) - */ - public enum Type { - /** - * Time of day (0-24000 ticks) - */ - DAYTIME(e -> (int)(e.level().getDayTime() % 24000L), (e, t) -> (int)((e.level().getDayTime() + t) % 24000L)), - /** - * Age of the brain owner (0+).
    - * This makes the schedule a 'run-once' per entity - */ - AGE(e -> e.tickCount, (e, t) -> e.tickCount + t); - - final ToIntFunction tickResolver; - final ToIntBiFunction delayResolver; - - Type(ToIntFunction tickResolver, ToIntBiFunction delayResolver) { - this.tickResolver = tickResolver; - this.delayResolver = delayResolver; - } - - public int resolve(LivingEntity entity) { - return this.tickResolver.applyAsInt(entity); - } - - public int resolveDelay(LivingEntity entity, int delay) { - return this.delayResolver.applyAsInt(entity, delay); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/EntityFilteringSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/EntityFilteringSensor.java deleted file mode 100644 index 128fab038..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/EntityFilteringSensor.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor; - -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiPredicate; - -/** - * An abstract class that is used to pick out certain entities from the existing {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory.
    - * This requires that another sensor has pre-filled that memory. - * @see net.minecraft.world.entity.ai.sensing.NearestVisibleLivingEntitySensor - * @param

    The target entity - * @param The entity - */ -public abstract class EntityFilteringSensor extends PredicateSensor { - /** - * Which memory the sensor should set if an entity meets the given criteria. - * - * @return The memory type to use - */ - protected abstract MemoryModuleType

    getMemory(); - - @Override - protected abstract BiPredicate predicate(); - - @Override - public List> memoriesUsed() { - return List.of(getMemory()); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.setMemory(entity, getMemory(), testForEntity(entity)); - } - - protected P testForEntity(E entity) { - NearestVisibleLivingEntities matcher = BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); - - if (matcher == null) - return null; - - return findMatches(entity, matcher); - } - - /** - * Find and return matches based on the provided list of entities.
    - * The returned value is saved as the memory for this sensor. - * @param entity The entity - * @param matcher The nearby entities list retrieved from the {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory - * @return The match(es) to save in memory - */ - @Nullable - protected abstract P findMatches(E entity, NearestVisibleLivingEntities matcher); -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/ExtendedSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/ExtendedSensor.java deleted file mode 100644 index 915ce3fae..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/ExtendedSensor.java +++ /dev/null @@ -1,101 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor; - -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.Sensor; -import net.minecraft.world.entity.ai.sensing.SensorType; - -import java.util.List; -import java.util.Set; -import java.util.function.Consumer; -import java.util.function.Function; - -/** - * An extension of the base Sensor. This adds some minor additional functionality and swaps the memory to a list for easier usage and faster iteration.
    - * All custom sensor implementations should use this superclass. - * - * @param The entity - */ -public abstract class ExtendedSensor extends Sensor { - protected Function scanRate = entity -> 20; - protected Consumer scanCallback = entity -> {}; - protected long nextTickTime = 0; - - public ExtendedSensor() { - super(); - } - - /** - * Set the scan rate provider for this sensor.
    - * The provider will be sampled every time the sensor does a scan. - * - * @param function The function to provide the tick rate - * @return this - */ - public ExtendedSensor setScanRate(Function function) { - this.scanRate = function; - - return this; - } - - /** - * Set a callback function for when the sensor completes a scan. - */ - public ExtendedSensor afterScanning(Consumer callback) { - this.scanCallback = callback; - - return this; - } - - @Override - public final void tick(ServerLevel level, E entity) { - if (nextTickTime < level.getGameTime()) { - nextTickTime = level.getGameTime() + scanRate.apply(entity); - - doTick(level, entity); - this.scanCallback.accept(entity); - } - } - - /** - * Handle the Sensor's actual function here. Be wary of performance implications of computation-heavy checks here. - * - * @param level The level the entity is in - * @param entity The owner of the brain - */ - @Override - protected void doTick(ServerLevel level, E entity) {} - - /** - * The list of memory types this sensor saves to. This should contain any memory the sensor sets a value for in the brain
    - * Bonus points if it's a statically-initialised list. - * - * @return The list of memory types saves by this sensor - */ - public abstract List> memoriesUsed(); - - /** - * The {@link SensorType} of the sensor, used for reverse lookups. - * @return The sensor type - */ - public abstract SensorType> type(); - - /** - * Vanilla's implementation of the required memory collection. Functionally replaced by {@link ExtendedSensor#memoriesUsed()}.
    - * Left in place for compatibility reasons. - * - * @return A set view of the list returned by {@code memoriesUsed()} - */ - @Override - public final Set> requires() { - return new ObjectOpenHashSet<>(memoriesUsed()); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/PredicateSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/PredicateSensor.java deleted file mode 100644 index 887183400..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/PredicateSensor.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor; - -import net.minecraft.world.entity.LivingEntity; - -import java.util.function.BiPredicate; - -/** - * An abstract sensor class used for sensors that utilise some form of predication in their function. - * This allows for instance-based SmartBrainLib of the predicate and the sensor. - * - * @param

    The predicate, used for whatever the sensor might need - * @param The entity - */ -public abstract class PredicateSensor extends ExtendedSensor { - private BiPredicate predicate; - - public PredicateSensor() { - this((obj, entity) -> true); - } - - public PredicateSensor(BiPredicate predicate) { - this.predicate = predicate; - } - - /** - * Set the predicate for the sensor. The subclass of this class determines its usage. - * - * @param predicate The predicate - * @return this - */ - public PredicateSensor setPredicate(BiPredicate predicate) { - this.predicate = predicate; - - return this; - } - - /** - * Retrieve the predicate this sensor is using. - * - * @return The predicate - */ - protected BiPredicate predicate() { - return this.predicate; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/GenericAttackTargetSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/GenericAttackTargetSensor.java deleted file mode 100644 index 1e2200075..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/GenericAttackTargetSensor.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.custom; - -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiPredicate; - -/** - * Sets the {@link MemoryModuleType#NEAREST_ATTACKABLE} memory based on visible nearby entities.
    - * Defaults: - *

      - *
    • Only targets that {@link net.minecraft.world.entity.ai.sensing.Sensor#isEntityAttackable(LivingEntity, LivingEntity)} passes.
    • - *
    - * @param - */ -public class GenericAttackTargetSensor extends EntityFilteringSensor { - @Override - protected MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_ATTACKABLE; - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> isEntityAttackable(entity, target); - } - - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } - - @Override - public SensorType> type() { - return SBLSensors.GENERIC_ATTACK_TARGET.get(); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/IncomingProjectilesSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/IncomingProjectilesSensor.java deleted file mode 100644 index 0bcc8ec64..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/IncomingProjectilesSensor.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.custom; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.projectile.Projectile; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -import java.util.Comparator; -import java.util.List; - -/** - * Custom sensor that detects incoming projectiles. - * Defaults: - *
      - *
    • 3-tick scan rate
    • - *
    • Only projectiles that are still in flight
    • - *
    • Only projectiles that will hit the entity before the next scan
    • - *
    - * @param - */ -public class IncomingProjectilesSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(SBLMemoryTypes.INCOMING_PROJECTILES.get()); - - public IncomingProjectilesSensor() { - setScanRate(entity -> 3); - setPredicate((projectile, entity) -> { - if (projectile.onGround() || projectile.horizontalCollision || projectile.verticalCollision) - return false; - - return entity.getBoundingBox().clip(projectile.position(), projectile.position().add(projectile.getDeltaMovement().multiply(3, 3, 3))).isPresent(); - }); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.INCOMING_PROJECTILES.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - List projectiles = EntityRetrievalUtil.getEntities(level, entity.getBoundingBox().inflate(7), target -> target instanceof Projectile projectile && predicate().test(projectile, entity)); - - if (!projectiles.isEmpty()) { - projectiles.sort(Comparator.comparingDouble(entity::distanceToSqr)); - BrainUtils.setMemory(entity, SBLMemoryTypes.INCOMING_PROJECTILES.get(), projectiles); - } - else { - BrainUtils.clearMemory(entity, SBLMemoryTypes.INCOMING_PROJECTILES.get()); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyBlocksSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyBlocksSensor.java deleted file mode 100644 index 685fcdebc..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyBlocksSensor.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.custom; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.level.block.state.BlockState; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * Sensor for identifying and memorising nearby blocks using the {@link SBLMemoryTypes#NEARBY_BLOCKS} memory module.
    - * Defaults: - *
      - *
    • 1-block radius
    • - *
    • Ignores air blocks
    • - *
    - */ -public class NearbyBlocksSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(SBLMemoryTypes.NEARBY_BLOCKS.get()); - - protected SquareRadius radius = new SquareRadius(1, 1); - - public NearbyBlocksSensor() { - setPredicate((state, entity) -> !state.isAir()); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_BLOCKS.get(); - } - - /** - * Set the radius for the sensor to scan - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyBlocksSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan. - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyBlocksSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - protected void doTick(ServerLevel level, E entity) { - List> blocks = new ObjectArrayList<>(); - - for (BlockPos pos : BlockPos.betweenClosed(entity.blockPosition().subtract(this.radius.toVec3i()), entity.blockPosition().offset(this.radius.toVec3i()))) { - BlockState state = level.getBlockState(pos); - - if (this.predicate().test(state, entity)) - blocks.add(Pair.of(pos.immutable(), state)); - } - - if (blocks.isEmpty()) { - BrainUtils.clearMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get()); - } - else { - BrainUtils.setMemory(entity, SBLMemoryTypes.NEARBY_BLOCKS.get(), blocks); - } - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyItemsSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyItemsSensor.java deleted file mode 100644 index 971954f96..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/NearbyItemsSensor.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.custom; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -import java.util.List; - -/** - * A sensor that looks for nearby {@link ItemEntity items} in the surrounding area.
    - * Defaults: - *
      - *
    • 32x16x32 radius
    • - *
    • Only items that return true for {@link Mob#wantsToPickUp(ItemStack)}
    • - *
    • Only items that return true for - * {@link net.minecraft.world.entity.LivingEntity#hasLineOfSight(Entity)}
    • - *
    - * - * @param The entity - */ -public class NearbyItemsSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(SBLMemoryTypes.NEARBY_ITEMS.get()); - - protected SquareRadius radius = new SquareRadius(32, 16); - - public NearbyItemsSensor() { - super((item, entity) -> entity.wantsToPickUp(item.getItem()) && entity.hasLineOfSight(item)); - } - - /** - * Set the radius for the item sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyItemsSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the item sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyItemsSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_ITEMS.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.setMemory(entity, SBLMemoryTypes.NEARBY_ITEMS.get(), EntityRetrievalUtil.getEntities(level, this.radius.inflateAABB(entity.getBoundingBox()), obj -> obj instanceof ItemEntity item && predicate().test(item, entity))); - } -} - - diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/UnreachableTargetSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/UnreachableTargetSensor.java deleted file mode 100644 index 6398a3d40..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/custom/UnreachableTargetSensor.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.custom; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * A sensor to attempt to track whether the entity's target is currently obstructed either by blocks or a wall/tower of blocks.
    - * This is differentiated from {@link MemoryModuleType#CANT_REACH_WALK_TARGET_SINCE} in that it only stores state if the entity is actively blocked, and not just completing a previous path that may have been blocked.
    - * The contract of the memory (when this sensor is used) is as follows:
    - *
      - *
    • If not present: entity is not blocked
    • - *
    • If false: entity is blocked at a similar or lower y-coordinate (wall-blocked)
    • - *
    • If true: entity is blocked at a higher y-coordinate (target has towered up, or is on cliff)
    • - *
    - * @param The entity - */ -public class UnreachableTargetSensor extends ExtendedSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.ATTACK_TARGET, SBLMemoryTypes.TARGET_UNREACHABLE.get()); - - protected long lastUnpathableTime = 0; - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.UNREACHABLE_TARGET.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - LivingEntity target = BrainUtils.getTargetOfEntity(entity); - - if (target == null) { - resetState(brain); - - return; - } - - Long unpathableTime = BrainUtils.getMemory(brain, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); - - if (unpathableTime == null) { - resetState(brain); - - return; - } - - if (this.lastUnpathableTime == 0) { - this.lastUnpathableTime = unpathableTime; - } - else if (this.lastUnpathableTime == unpathableTime) { - BrainUtils.clearMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get()); - } - else if (this.lastUnpathableTime < unpathableTime) { - this.lastUnpathableTime = unpathableTime; - - BrainUtils.setMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get(), target.getY() > entity.getEyeY()); - } - } - - private void resetState(Brain brain) { - if (this.lastUnpathableTime > 0) - BrainUtils.clearMemory(brain, SBLMemoryTypes.TARGET_UNREACHABLE.get()); - - this.lastUnpathableTime = 0; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/AxolotlSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/AxolotlSpecificSensor.java deleted file mode 100644 index 266ee4665..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/AxolotlSpecificSensor.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import net.minecraft.tags.EntityTypeTags; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.Sensor; -import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiPredicate; - -/** - * A replication of vanilla's - * {@link net.minecraft.world.entity.ai.sensing.AxolotlAttackablesSensor}. Not - * really useful, but included for completeness' sake and legibility.
    - * Handles the Axolotl's hostility and targets - * - * @param The entity - */ -public class AxolotlSpecificSensor extends EntityFilteringSensor { - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_ATTACKABLE; - } - - @Override - public List> memoriesUsed() { - return List.of(getMemory(), MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); - } - - @Override - public SensorType> type() { - return SBLSensors.AXOLOTL_SPECIFIC.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> { - if (target.distanceToSqr(entity) > 64) - return false; - - if (!target.isInWaterOrBubble()) - return false; - - if (!target.getType().is(EntityTypeTags.AXOLOTL_ALWAYS_HOSTILES) && (BrainUtils.hasMemory(target, MemoryModuleType.HAS_HUNTING_COOLDOWN) || !target.getType().is(EntityTypeTags.AXOLOTL_HUNT_TARGETS))) - return false; - - return Sensor.isEntityAttackable(entity, target); - }; - } - - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/FrogSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/FrogSpecificSensor.java deleted file mode 100644 index 24572c28f..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/FrogSpecificSensor.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.Sensor; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.animal.frog.Frog; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.UUID; -import java.util.function.BiPredicate; - -/** - * A replication of vanilla's - * {@link net.minecraft.world.entity.ai.sensing.FrogAttackablesSensor}. Not - * really useful, but included for completeness' sake and legibility.
    - * Handles the Frog's tongue target. - * - * @param The entity - */ -public class FrogSpecificSensor extends EntityFilteringSensor { - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_ATTACKABLE; - } - - @Override - public SensorType> type() { - return SBLSensors.FROG_SPECIFIC.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> { - if (BrainUtils.hasMemory(entity, MemoryModuleType.HAS_HUNTING_COOLDOWN)) - return false; - - if (!Sensor.isEntityAttackable(entity, target)) - return false; - - if (!Frog.canEat(target)) - return false; - - if (!target.closerThan(entity, 10)) - return false; - - List unreachableTargets = BrainUtils.getMemory(entity, MemoryModuleType.UNREACHABLE_TONGUE_TARGETS); - - return unreachableTargets == null || !unreachableTargets.contains(target.getUUID()); - }; - } - - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HoglinSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HoglinSpecificSensor.java deleted file mode 100644 index e554e49cf..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HoglinSpecificSensor.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.monster.hoglin.Hoglin; -import net.minecraft.world.entity.monster.piglin.Piglin; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * A replication of vanilla's - * {@link net.minecraft.world.entity.ai.sensing.HoglinSpecificSensor}. Not - * really useful, but included for completeness' sake and legibility.
    - * Handles most of Hoglin's memories at once - * - * @param The entity - */ -public class HoglinSpecificSensor extends ExtendedSensor { - private static final List> MEMORIES = ObjectArrayList.of( - MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, - MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, - MemoryModuleType.NEAREST_REPELLENT); - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.HOGLIN_SPECIFIC.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, entities -> { - int piglinCount = 0; - Piglin nearestPiglin = null; - List hoglins = new ObjectArrayList<>(); - - for (LivingEntity target : entities.findAll(mob -> !mob.isBaby())) { - if (target instanceof Piglin piglin) { - piglinCount++; - - if (nearestPiglin == null) - nearestPiglin = piglin; - } - else if (target instanceof Hoglin hoglin) { - hoglins.add(hoglin); - } - } - - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLIN, nearestPiglin); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_HOGLINS, hoglins); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, piglinCount); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, hoglins.size()); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_REPELLENT, BlockPos.findClosestMatch(entity.blockPosition(), 8, 4, pos -> level.getBlockState(pos).is(BlockTags.HOGLIN_REPELLENTS)).orElse(null)); - }); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HurtBySensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HurtBySensor.java deleted file mode 100644 index 4a6d8e0a1..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/HurtBySensor.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * A sensor that sets the memory state for the last damage source and attacker. - * - * @param The entity - */ -public class HurtBySensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.HURT_BY, MemoryModuleType.HURT_BY_ENTITY); - - public HurtBySensor() { - super((damageSource, entity) -> true); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.HURT_BY.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - DamageSource damageSource = entity.getLastDamageSource(); - - if (damageSource == null) { - BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY); - BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY_ENTITY); - } - else if (predicate().test(damageSource, entity)) { - BrainUtils.setMemory(brain, MemoryModuleType.HURT_BY, damageSource); - - if (damageSource.getEntity()instanceof LivingEntity attacker && attacker.isAlive() && attacker.level() == entity.level()) - BrainUtils.setMemory(brain, MemoryModuleType.HURT_BY_ENTITY, attacker); - } - else { - BrainUtils.withMemory(brain, MemoryModuleType.HURT_BY_ENTITY, attacker -> { - if (!attacker.isAlive() || attacker.level() != entity.level()) - BrainUtils.clearMemory(brain, MemoryModuleType.HURT_BY_ENTITY); - }); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/InWaterSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/InWaterSensor.java deleted file mode 100644 index 6960b2444..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/InWaterSensor.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.Unit; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * A sensor that sets or clears the {@link MemoryModuleType#IS_IN_WATER} memory - * depending on certain criteria.
    - * Defaults: - *
      - *
    • {@link LivingEntity#isInWater()}
    • - *
    - * - * @param The entity - */ -public class InWaterSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.IS_IN_WATER); - - public InWaterSensor() { - super((entity2, entity) -> entity.isInWater()); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.IN_WATER.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - if (predicate().test(entity, entity)) { - BrainUtils.setMemory(entity, MemoryModuleType.IS_IN_WATER, Unit.INSTANCE); - } - else { - BrainUtils.clearMemory(entity, MemoryModuleType.IS_IN_WATER); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/ItemTemptingSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/ItemTemptingSensor.java deleted file mode 100644 index bc43fb7cc..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/ItemTemptingSensor.java +++ /dev/null @@ -1,132 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -import java.util.Comparator; -import java.util.List; -import java.util.function.BiPredicate; - -/** - * Find the nearest player that is holding out a tempting item for the entity. - * Defaults: - *
      - *
    • 10x10x10 Radius
    • - *
    • No spectators
    • - *
    - * - * @see net.minecraft.world.entity.ai.sensing.TemptingSensor - * @param The entity - */ -public class ItemTemptingSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.TEMPTING_PLAYER); - - protected BiPredicate temptPredicate = (entity, stack) -> false; - protected SquareRadius radius = new SquareRadius(10, 10); - - public ItemTemptingSensor() { - setPredicate((target, entity) -> { - if (target.isSpectator() || !target.isAlive()) - return false; - - return this.temptPredicate.test(entity, target.getMainHandItem()) || this.temptPredicate.test(entity, target.getOffhandItem()); - }); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.ITEM_TEMPTING.get(); - } - - /** - * Set the items to temptable items for the entity. - * - * @param temptingItems An ingredient representing the temptations for the - * entity - * @deprecated Use {@link ItemTemptingSensor#temptedWith} - * @return this - */ - @Deprecated(forRemoval = true) - public ItemTemptingSensor setTemptingItems(Ingredient temptingItems) { - return temptedWith((entity, stack) -> temptingItems.test(stack)); - } - - /** - * Set the items to temptable items for the entity. - * - * @param predicate An ingredient representing the temptations for the - * entity - * @return this - */ - public ItemTemptingSensor temptedWith(final BiPredicate predicate) { - this.temptPredicate = predicate; - - return this; - } - - /** - * Set the radius for the player sensor to scan - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public ItemTemptingSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the player sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public ItemTemptingSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Player player; - final List nearbyPlayers = BrainUtils.getMemory(entity, MemoryModuleType.NEAREST_PLAYERS); - - if (nearbyPlayers != null) { - player = nearbyPlayers.stream().filter(pl -> predicate().test(pl, entity)).min(Comparator.comparing(pl -> pl.distanceToSqr(entity))).orElse(null); - } - else { - player = EntityRetrievalUtil.getNearestPlayer(entity, this.radius.xzRadius(), this.radius.yRadius(), this.radius.xzRadius(), target -> predicate().test(target, entity)); - } - - if (player == null) { - BrainUtils.clearMemory(entity, MemoryModuleType.TEMPTING_PLAYER); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.TEMPTING_PLAYER, player); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyAdultSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyAdultSensor.java deleted file mode 100644 index 0e89466a6..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyAdultSensor.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import net.minecraft.world.entity.AgeableMob; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiPredicate; - -/** - * A sensor that sets the {@link MemoryModuleType#NEAREST_VISIBLE_ADULT} memory - * by checking the existing visible entities for nearby adults of the same - * entity type.
    - * - * @see net.minecraft.world.entity.ai.sensing.AdultSensor - * @param The entity - */ -public class NearbyAdultSensor extends EntityFilteringSensor { - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_VISIBLE_ADULT; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_ADULT.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> target.getType() == entity.getType() && !target.isBaby(); - } - - @Nullable - @Override - protected AgeableMob findMatches(E entity, NearestVisibleLivingEntities matcher) { - return (AgeableMob) matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyBabySensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyBabySensor.java deleted file mode 100644 index 4bff95125..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyBabySensor.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import com.google.common.collect.ImmutableList; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.BiPredicate; - -/** - * A sensor that sets the {@link MemoryModuleType#VISIBLE_VILLAGER_BABIES} - * memory by checking the existing visible entities for nearby babies of the - * same entity type.
    - * - * @see net.minecraft.world.entity.ai.sensing.VillagerBabiesSensor - * @param The entity - */ -public class NearbyBabySensor extends EntityFilteringSensor, E> { - @Override - public MemoryModuleType> getMemory() { - return MemoryModuleType.VISIBLE_VILLAGER_BABIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_BABY.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> target.getType() == entity.getType() && target.isBaby(); - } - - @Nullable - @Override - protected List findMatches(E entity, NearestVisibleLivingEntities matcher) { - return ImmutableList.copyOf(matcher.findAll(target -> predicate().test(target, entity))); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyGolemSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyGolemSensor.java deleted file mode 100644 index bb908d297..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyGolemSensor.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * A sensor that sets the {@link MemoryModuleType#GOLEM_DETECTED_RECENTLY} - * memory by checking if any of the detected nearby entities are - * {@link net.minecraft.world.entity.animal.IronGolem Iron Golems}.
    - * Defaults: - *
      - *
    • 200-tick scan rate
    • - *
    • Only detects vanilla Iron Golems
    • - *
    • Remembers the nearby golem for 600 ticks
    • - *
    - * - * @see net.minecraft.world.entity.ai.sensing.GolemSensor - * @param The entity - */ -public class NearbyGolemSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.GOLEM_DETECTED_RECENTLY); - - private int timeToRemember = 600; - - public NearbyGolemSensor() { - setScanRate(entity -> 200); - setPredicate((target, entity) -> target.getType() == EntityType.IRON_GOLEM && target.isAlive()); - } - - /** - * Set the amount of ticks the entity should remember that the golem is there. - * - * @param ticks The number of ticks to remember for - * @return this - */ - public NearbyGolemSensor setMemoryTime(int ticks) { - this.timeToRemember = ticks; - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_GOLEM.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.withMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entityList -> { - if (entityList.isEmpty()) - return; - - for (LivingEntity target : entityList) { - if (predicate().test(target, entity)) { - BrainUtils.setForgettableMemory(entity, MemoryModuleType.GOLEM_DETECTED_RECENTLY, true, this.timeToRemember); - - return; - } - } - }); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyHostileSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyHostileSensor.java deleted file mode 100644 index efbd5b5b4..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyHostileSensor.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.EntityFilteringSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import org.jetbrains.annotations.Nullable; - -import java.util.Map; -import java.util.function.BiPredicate; - -/** - * A sensor that sets the {@link MemoryModuleType#NEAREST_HOSTILE} memory by - * checking the existing visible entities for nearby hostiles.
    - * By default, this is used for villager hostile detection, but it can be - * configured at instantiation for any types. - * - * @see net.minecraft.world.entity.ai.sensing.VillagerHostilesSensor - * @param The entity - */ -public class NearbyHostileSensor extends EntityFilteringSensor { - private final Map, Float> hostileDistanceMap = new Object2FloatOpenHashMap<>(11); - - public NearbyHostileSensor() { - setHostiles( - Pair.of(EntityType.DROWNED, 8f), - Pair.of(EntityType.HUSK, 8f), - Pair.of(EntityType.VEX, 8f), - Pair.of(EntityType.ZOMBIE, 8f), - Pair.of(EntityType.ZOMBIE_VILLAGER, 8f), - Pair.of(EntityType.VINDICATOR, 10f), - Pair.of(EntityType.ZOGLIN, 10f), - Pair.of(EntityType.EVOKER, 12f), - Pair.of(EntityType.ILLUSIONER, 12f), - Pair.of(EntityType.RAVAGER, 12f), - Pair.of(EntityType.PILLAGER, 15f)); - } - - /** - * Clear the hostile types map, and add all of the given entries. - * - * @param entries The collection of entity types and distances to set the - * hostile types map to - * @return this - */ - public NearbyHostileSensor setHostiles(Pair, Float>... entries) { - this.hostileDistanceMap.clear(); - - for (Pair, Float> entry : entries) { - this.hostileDistanceMap.put(entry.getFirst(), entry.getSecond()); - } - - return this; - } - - /** - * Add an entity type to the hostile types map. - * - * @param entry The entity type and distance to which it should be considered. - * @return this - */ - public NearbyHostileSensor addHostile(Pair, Float> entry) { - this.hostileDistanceMap.put(entry.getFirst(), entry.getSecond()); - - return this; - } - - @Override - public MemoryModuleType getMemory() { - return MemoryModuleType.NEAREST_HOSTILE; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_HOSTILE.get(); - } - - @Override - protected BiPredicate predicate() { - return (target, entity) -> { - Float distance = this.hostileDistanceMap.get(target.getType()); - - return distance != null && target.distanceToSqr(entity) <= distance * distance; - }; - } - - @Nullable - @Override - protected LivingEntity findMatches(E entity, NearestVisibleLivingEntities matcher) { - return matcher.findClosest(target -> predicate().test(target, entity)).orElse(null); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyLivingEntitySensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyLivingEntitySensor.java deleted file mode 100644 index 8d50fae93..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyLivingEntitySensor.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.FixedNearestVisibleLivingEntities; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; -import org.jetbrains.annotations.Nullable; - -import java.util.Comparator; -import java.util.List; - -/** - * A sensor that looks for nearby living entities in the surrounding area, - * sorted by proximity to the brain owner.
    - * Defaults: - *
      - *
    • Radius is equivalent to the entity's - * {@link Attributes#FOLLOW_RANGE} - * attribute
    • - *
    • Only alive entities
    • - *
    - * - * @param The entity - */ -public class NearbyLivingEntitySensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES); - - @Nullable - protected SquareRadius radius = null; - - public NearbyLivingEntitySensor() { - super((target, entity) -> target != entity && target.isAlive()); - } - - /** - * Set the radius for the sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyLivingEntitySensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyLivingEntitySensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_LIVING_ENTITY.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - SquareRadius radius = this.radius; - - if (radius == null) { - double dist = entity.getAttributeValue(Attributes.FOLLOW_RANGE); - - radius = new SquareRadius(dist, dist); - } - - List entities = EntityRetrievalUtil.getEntities(level, entity.getBoundingBox().inflate(radius.xzRadius(), radius.yRadius(), radius.xzRadius()), obj -> obj instanceof LivingEntity livingEntity && predicate().test(livingEntity, entity)); - - entities.sort(Comparator.comparingDouble(entity::distanceToSqr)); - - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities); - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, new FixedNearestVisibleLivingEntities(entity, entities)); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyPlayersSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyPlayersSensor.java deleted file mode 100644 index 3d09cdbb2..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearbyPlayersSensor.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.attributes.Attributes; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; -import org.jetbrains.annotations.Nullable; - -import java.util.Comparator; -import java.util.List; - -/** - * A sensor that looks for nearby players in the surrounding area, sorted by - * proximity to the brain owner.
    - * Defaults: - *
      - *
    • Radius is equivalent to the entity's - * {@link Attributes#FOLLOW_RANGE} - * attribute
    • - *
    • No spectators
    • - *
    - * - * @param The entity - */ -public class NearbyPlayersSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_PLAYERS, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER); - - @Nullable - protected SquareRadius radius = null; - - public NearbyPlayersSensor() { - super((player, entity) -> !player.isSpectator()); - } - - /** - * Set the radius for the sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearbyPlayersSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearbyPlayersSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEARBY_PLAYERS.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - SquareRadius radius = this.radius; - - if (radius == null) { - double dist = entity.getAttributeValue(Attributes.FOLLOW_RANGE); - - radius = new SquareRadius(dist, dist); - } - - List players = EntityRetrievalUtil.getPlayers(level, radius.inflateAABB(entity.getBoundingBox()), player -> predicate().test(player, entity)); - - players.sort(Comparator.comparingDouble(entity::distanceToSqr)); - - List targetablePlayers = new ObjectArrayList<>(players); - - targetablePlayers.removeIf(pl -> !isEntityTargetable(entity, pl)); - - List attackablePlayers = new ObjectArrayList<>(targetablePlayers); - - attackablePlayers.removeIf(pl -> !isEntityAttackable(entity, pl)); - - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_PLAYERS, players); - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_VISIBLE_PLAYER, targetablePlayers.isEmpty() ? null : targetablePlayers.get(0)); - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, attackablePlayers.isEmpty() ? null : attackablePlayers.get(0)); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestHomeSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestHomeSensor.java deleted file mode 100644 index 7bd595a53..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestHomeSensor.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.behavior.AcquirePoi; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.ai.village.poi.PoiManager; -import net.minecraft.world.entity.ai.village.poi.PoiType; -import net.minecraft.world.entity.ai.village.poi.PoiTypes; -import net.minecraft.world.level.pathfinder.Path; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -/** - * A sensor that looks for the nearest home point of interest in the surrounding - * area.
    - * Defaults: - *
      - *
    • 48 block radius
    • - *
    • Only runs if the owner of the brain is a baby
    • - *
    - * - * @param The entity - */ -public class NearestHomeSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_BED); - - protected int radius = 48; - - private final Object2LongOpenHashMap homesMap = new Object2LongOpenHashMap<>(5); - private int tries = 0; - - public NearestHomeSensor() { - super((brainOwner, entity) -> brainOwner.isBaby()); - } - - /** - * Set the radius for the item sensor to scan - * - * @param radius The radius - * @return this - */ - public NearestHomeSensor setRadius(int radius) { - this.radius = radius; - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEAREST_HOME.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - if (!predicate().test(entity, entity)) - return; - - this.tries = 0; - long nodeExpiryTime = level.getGameTime() + level.getRandom().nextInt(20); - PoiManager poiManager = level.getPoiManager(); - Predicate predicate = pos -> { - if (this.homesMap.containsKey(pos)) - return false; - - if (++this.tries >= 5) - return false; - - this.homesMap.put(pos, nodeExpiryTime + 40); - - return true; - }; - Set, BlockPos>> poiLocations = poiManager.findAllWithType(poiType -> poiType.is(PoiTypes.HOME), predicate, entity.blockPosition(), this.radius, PoiManager.Occupancy.ANY).collect(Collectors.toSet()); - Path pathToHome = AcquirePoi.findPathToPois(entity, poiLocations); - - if (pathToHome != null && pathToHome.canReach()) { - BlockPos targetPos = pathToHome.getTarget(); - - poiManager.getType(targetPos).ifPresent(poiType -> BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_BED, targetPos)); - } - else if (this.tries < 5) { - this.homesMap.object2LongEntrySet().removeIf(pos -> pos.getLongValue() < nodeExpiryTime); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestItemSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestItemSensor.java deleted file mode 100644 index ed1e232c8..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/NearestItemSensor.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.item.ItemStack; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.PredicateSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; -import mod.azure.azurelib.sblforked.util.EntityRetrievalUtil; - -import java.util.List; - -/** - * A sensor that looks for the nearest item entity in the surrounding area.
    - * Defaults: - *
      - *
    • 32x16x32 radius
    • - *
    • Only items that return true for {@link Mob#wantsToPickUp(ItemStack)}
    • - *
    • Only items that return true for - * {@link net.minecraft.world.entity.LivingEntity#hasLineOfSight(Entity)}
    • - *
    - * - * @param The entity - */ -public class NearestItemSensor extends PredicateSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM); - - protected SquareRadius radius = new SquareRadius(32, 16); - - public NearestItemSensor() { - super((item, entity) -> entity.wantsToPickUp(item.getItem()) && entity.hasLineOfSight(item)); - } - - /** - * Set the radius for the item sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public NearestItemSensor setRadius(double radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the item sensor to scan. - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public NearestItemSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.NEAREST_ITEM.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, EntityRetrievalUtil.getNearestEntity(level, this.radius.inflateAABB(entity.getBoundingBox()), entity.position(), obj -> obj instanceof ItemEntity item && predicate().test(item, entity))); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinBruteSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinBruteSpecificSensor.java deleted file mode 100644 index 90acabd85..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinBruteSpecificSensor.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.boss.wither.WitherBoss; -import net.minecraft.world.entity.monster.WitherSkeleton; -import net.minecraft.world.entity.monster.piglin.AbstractPiglin; -import net.minecraft.world.entity.monster.piglin.Piglin; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * A replication of vanilla's - * {@link net.minecraft.world.entity.ai.sensing.PiglinBruteSpecificSensor}. Not - * really useful, but included for completeness' sake and legibility.
    - * Keeps track of nearby {@link Piglin piglins} and - * {@link MemoryModuleType#NEAREST_VISIBLE_NEMESIS nemesis} - * - * @param The entity - */ -public class PiglinBruteSpecificSensor extends ExtendedSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEARBY_ADULT_PIGLINS); - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.PIGLIN_BRUTE_SPECIFIC.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - List nearbyPiglins = new ObjectArrayList<>(); - - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, entities -> BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_NEMESIS, (Mob)entities.findClosest(target -> target instanceof WitherSkeleton || target instanceof WitherBoss).orElse(null))); - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { - for (LivingEntity target : entities) { - if (target instanceof AbstractPiglin piglin && piglin.isAdult()) - nearbyPiglins.add(piglin); - } - }); - BrainUtils.setMemory(brain, MemoryModuleType.NEARBY_ADULT_PIGLINS, nearbyPiglins); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinSpecificSensor.java deleted file mode 100644 index 12f96a3c6..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/PiglinSpecificSensor.java +++ /dev/null @@ -1,132 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.boss.wither.WitherBoss; -import net.minecraft.world.entity.monster.WitherSkeleton; -import net.minecraft.world.entity.monster.hoglin.Hoglin; -import net.minecraft.world.entity.monster.piglin.AbstractPiglin; -import net.minecraft.world.entity.monster.piglin.Piglin; -import net.minecraft.world.entity.monster.piglin.PiglinAi; -import net.minecraft.world.entity.monster.piglin.PiglinBrute; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.CampfireBlock; -import net.minecraft.world.level.block.state.BlockState; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * A replication of vanilla's - * {@link net.minecraft.world.entity.ai.sensing.PiglinSpecificSensor}. Not - * really useful, but included for completeness' sake and legibility.
    - * Handles most of Piglin's memories at once. - * - * @param The entity - */ -public class PiglinSpecificSensor extends ExtendedSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_VISIBLE_NEMESIS, MemoryModuleType.NEAREST_VISIBLE_HUNTABLE_HOGLIN, MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD, MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, MemoryModuleType.NEAREST_REPELLENT, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEARBY_ADULT_PIGLINS); - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.PIGLIN_SPECIFIC.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - Brain brain = entity.getBrain(); - List adultPiglins = new ObjectArrayList<>(); - - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, entities -> { - Mob nemesis = null; - Hoglin nearestHuntableHoglin = null; - Hoglin nearestBabyHoglin = null; - LivingEntity nearestZombified = null; - Player nearestPlayerWithoutGold = null; - Player nearestPlayerWithWantedItem = null; - List visibleAdultPiglins = new ObjectArrayList<>(); - int adultHoglinCount = 0; - - for (LivingEntity target : entities.findAll(obj -> true)) { - if (target instanceof Hoglin hoglin) { - if (hoglin.isBaby() && nearestBabyHoglin == null) { - nearestBabyHoglin = hoglin; - } - else if (hoglin.isAdult()) { - adultHoglinCount++; - - if (nearestHuntableHoglin == null && hoglin.canBeHunted()) - nearestHuntableHoglin = hoglin; - } - } - else if (target instanceof PiglinBrute brute) { - visibleAdultPiglins.add(brute); - } - else if (target instanceof Piglin piglin) { - if (piglin.isAdult()) - visibleAdultPiglins.add(piglin); - } - else if (target instanceof Player player) { - if (nearestPlayerWithoutGold == null && !PiglinAi.isWearingGold(player) && entity.canAttack(player)) - nearestPlayerWithoutGold = player; - - if (nearestPlayerWithWantedItem == null && !player.isSpectator() && PiglinAi.isPlayerHoldingLovedItem(player)) - nearestPlayerWithWantedItem = player; - } - else if (nemesis != null || !(target instanceof WitherSkeleton) && !(target instanceof WitherBoss)) { - if (nearestZombified == null && PiglinAi.isZombified(target.getType())) - nearestZombified = target; - } - else { - nemesis = (Mob) target; - } - } - - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_NEMESIS, nemesis); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_HUNTABLE_HOGLIN, nearestHuntableHoglin); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, nearestBabyHoglin); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, nearestZombified); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD, nearestPlayerWithoutGold); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM, nearestPlayerWithWantedItem); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, visibleAdultPiglins); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, visibleAdultPiglins.size()); - BrainUtils.setMemory(brain, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, adultHoglinCount); - BrainUtils.setMemory(brain, MemoryModuleType.NEAREST_REPELLENT, - BlockPos.findClosestMatch(entity.blockPosition(), 8, 4, pos -> { - BlockState state = level.getBlockState(pos); - boolean isRepellent = state.is(BlockTags.PIGLIN_REPELLENTS); - - return isRepellent && state.is(Blocks.SOUL_CAMPFIRE) ? CampfireBlock.isLitCampfire(state) : isRepellent; - }).orElse(null)); - }); - - BrainUtils.withMemory(brain, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { - for (LivingEntity target : entities) { - if (target instanceof AbstractPiglin piglin && piglin.isAdult()) - adultPiglins.add(piglin); - } - }); - BrainUtils.setMemory(brain, MemoryModuleType.NEARBY_ADULT_PIGLINS, adultPiglins); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/SecondaryPoiSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/SecondaryPoiSensor.java deleted file mode 100644 index 9e4281282..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/SecondaryPoiSensor.java +++ /dev/null @@ -1,103 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import com.google.common.collect.ImmutableSet; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.core.BlockPos; -import net.minecraft.core.GlobalPos; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.npc.Villager; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.object.SquareRadius; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * A sensor that looks for a nearby - * {@link net.minecraft.world.entity.ai.village.poi.PoiTypes POI} block that - * matches a villager's secondary profession.
    - * Defaults: - *
      - *
    • 40-tick scan rate
    • - *
    • 8x4x8 radius
    • - *
    - * - * @param The entity - */ -public class SecondaryPoiSensor extends ExtendedSensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.SECONDARY_JOB_SITE); - - protected SquareRadius radius = new SquareRadius(8, 4); - - public SecondaryPoiSensor() { - setScanRate(entity -> 40); - } - - /** - * Set the radius for the sensor to scan. - * - * @param radius The coordinate radius, in blocks - * @return this - */ - public SecondaryPoiSensor setRadius(int radius) { - return setRadius(radius, radius); - } - - /** - * Set the radius for the sensor to scan - * - * @param xz The X/Z coordinate radius, in blocks - * @param y The Y coordinate radius, in blocks - * @return this - */ - public SecondaryPoiSensor setRadius(double xz, double y) { - this.radius = new SquareRadius(xz, y); - - return this; - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.SECONDARY_POI.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - ResourceKey dimension = level.dimension(); - BlockPos pos = entity.blockPosition(); - ImmutableSet testPoiBlocks = entity.getVillagerData().getProfession().secondaryPoi(); - List poiPositions = new ObjectArrayList<>(); - - if (testPoiBlocks.isEmpty()) - return; - - for (BlockPos testPos : BlockPos.betweenClosed(pos.getX() - (int) this.radius.xzRadius() / 2, pos.getY() - (int) this.radius.yRadius() / 2, pos.getZ() - (int) this.radius.xzRadius() / 2, pos.getX() + (int) this.radius.xzRadius() / 2, pos.getY() + (int) this.radius.yRadius() / 2, pos.getZ() + (int) this.radius.xzRadius() / 2)) { - if (testPoiBlocks.contains(level.getBlockState(testPos).getBlock())) - poiPositions.add(GlobalPos.of(dimension, testPos.immutable())); - } - - if (poiPositions.isEmpty()) { - BrainUtils.clearMemory(entity, MemoryModuleType.SECONDARY_JOB_SITE); - } - else { - BrainUtils.setMemory(entity, MemoryModuleType.SECONDARY_JOB_SITE, poiPositions); - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/WardenSpecificSensor.java b/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/WardenSpecificSensor.java deleted file mode 100644 index 91f1f4eec..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/api/core/sensor/vanilla/WardenSpecificSensor.java +++ /dev/null @@ -1,71 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.api.core.sensor.vanilla; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.monster.warden.Warden; -import net.minecraft.world.entity.player.Player; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import mod.azure.azurelib.sblforked.util.BrainUtils; - -import java.util.List; - -/** - * A replication of vanilla's {@link net.minecraft.world.entity.ai.sensing.WardenEntitySensor}. Not really useful, but included for completeness' sake and legibility.
    - * Handle's the Warden's nearest attackable target, prioritising players. - * @param The entity - */ -public class WardenSpecificSensor extends NearbyLivingEntitySensor { - private static final List> MEMORIES = ObjectArrayList.of(MemoryModuleType.NEAREST_ATTACKABLE); - - public WardenSpecificSensor() { - setRadius(24); - setPredicate((target, entity) -> entity.canTargetEntity(target)); - } - - @Override - public List> memoriesUsed() { - return MEMORIES; - } - - @Override - public SensorType> type() { - return SBLSensors.WARDEN_SPECIFIC.get(); - } - - @Override - protected void doTick(ServerLevel level, E entity) { - super.doTick(level, entity); - - BrainUtils.withMemory(entity, MemoryModuleType.NEAREST_LIVING_ENTITIES, entities -> { - LivingEntity fallbackTarget = null; - - for (LivingEntity target : entities) { - if (target instanceof Player) { - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE, target); - - return; - } - else if (fallbackTarget == null) { - fallbackTarget = target; - } - } - - if (fallbackTarget != null) { - BrainUtils.setMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE, fallbackTarget); - } - else { - BrainUtils.clearMemory(entity, MemoryModuleType.NEAREST_ATTACKABLE); - } - }); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourConsumer.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourConsumer.java deleted file mode 100644 index 81d4c2468..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourConsumer.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import net.minecraft.world.entity.schedule.Activity; -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; -import org.jetbrains.annotations.Nullable; - -/** - * Functional consumer for brain activity related functions - */ -@FunctionalInterface -public interface BrainBehaviourConsumer { - /** - * Accepts the given behaviour and the information related to it - * @param priority The priority the behaviour is nested under - * @param activity The activity category the behaviour is under - * @param behaviour The behaviour - * @param parent The {@link net.minecraft.world.entity.ai.behavior.GateBehavior GateBehaviour} or {@link GroupBehaviour GroupBehaviour} - * the behaviour is a child of, if applicable - */ - void consume(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parent); -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourPredicate.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourPredicate.java deleted file mode 100644 index c6201d8d1..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/BrainBehaviourPredicate.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import net.minecraft.world.entity.schedule.Activity; -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; -import org.jetbrains.annotations.Nullable; - -/** - * Functional interface to handle passing multiple arguments back for behaviour-predication handling - */ -@FunctionalInterface -public interface BrainBehaviourPredicate { - /** - * Tests whether the given behaviour is relevant to the predicate. - * @param priority The priority the behaviour is nested under - * @param activity The activity category the behaviour is under - * @param behaviour The behaviour to check - * @param parentBehaviour The {@link net.minecraft.world.entity.ai.behavior.GateBehavior GateBehaviour} or {@link GroupBehaviour GroupBehaviour} - * the behaviour is a child of, if applicable - */ - boolean isBehaviour(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parentBehaviour); -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/ExtendedTargetingConditions.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/ExtendedTargetingConditions.java deleted file mode 100644 index f9c0da313..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/ExtendedTargetingConditions.java +++ /dev/null @@ -1,132 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import net.minecraft.world.Difficulty; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.attributes.Attributes; -import mod.azure.azurelib.sblforked.util.SensoryUtils; -import org.jetbrains.annotations.Nullable; - -import java.util.function.BiPredicate; -import java.util.function.Function; - -/** - * Replacement for Vanilla's {@link net.minecraft.world.entity.ai.targeting.TargetingConditions} due to its somewhat limited implementation - */ -public class ExtendedTargetingConditions { - protected BiPredicate customFilter = null; - protected Function rangeRetriever = null; - protected boolean isAttacking = true; - protected boolean checkLineOfSight = true; - protected boolean ignoresInvisibility = false; - - public static ExtendedTargetingConditions forLookTarget() { - return new ExtendedTargetingConditions().isJustLooking(); - } - - public static ExtendedTargetingConditions forLookTargetIgnoringInvisibility() { - return forLookTarget().skipInvisibilityCheck(); - } - - public static ExtendedTargetingConditions forAttackTarget() { - return new ExtendedTargetingConditions(); - } - - public static ExtendedTargetingConditions forAttackTargetIgnoringInvisibility() { - return forAttackTarget().skipInvisibilityCheck(); - } - - /** - * Skip any attack-related checks in the predicate, such as difficulty, invulnerability, or teams - */ - public ExtendedTargetingConditions isJustLooking() { - this.isAttacking = false; - - return this; - } - - /** - * Filter out any targeting that occurs for entities larger than this distance away from the entity - */ - public ExtendedTargetingConditions withRange(double range) { - return withRange(entity -> range); - } - - /** - * Filter out any targeting that occurs for entities larger than the distance provided by this function from the entity - */ - public ExtendedTargetingConditions withRange(Function function) { - this.rangeRetriever = function; - - return this; - } - - /** - * Filter out any targeting that occurs for entities outside of the entity's {@link Attributes#FOLLOW_RANGE} attribute - */ - public ExtendedTargetingConditions withFollowRange() { - return withRange(entity -> entity.getAttribute(Attributes.FOLLOW_RANGE) != null ? entity.getAttributeValue(Attributes.FOLLOW_RANGE) : 16d); - } - - /** - * Additionally filter out any specific cases that may apply. This check is applied before any other conditions are checked - *

    Note that the targeting entity may be null, for generic checks

    - * @return true if the entity should be allowed to target the target, or false if not - */ - public ExtendedTargetingConditions onlyTargeting(BiPredicate<@Nullable LivingEntity, LivingEntity> predicate) { - this.customFilter = predicate; - - return this; - } - - /** - * Skip the line of sight checks in the predicate. This can be useful for entities that track with other senses, or for other special-case situations - */ - public ExtendedTargetingConditions ignoreLineOfSight() { - this.checkLineOfSight = false; - - return this; - } - - /** - * Skip the invisibility check for targeting. This is often used where the entity is already being targeted/tracked, and we're just checking for attackability. - */ - public ExtendedTargetingConditions skipInvisibilityCheck() { - this.ignoresInvisibility = true; - - return this; - } - - public boolean test(@Nullable LivingEntity entity, LivingEntity target) { - if (entity == target || !target.canBeSeenByAnyone()) - return false; - - if (this.customFilter != null && !this.customFilter.test(entity, target)) - return false; - - if (entity == null) - return !this.isAttacking || (target.canBeSeenAsEnemy() && target.level().getDifficulty() != Difficulty.PEACEFUL); - - if (this.isAttacking && (!entity.canAttack(target) || !entity.canAttackType(target.getType()) || entity.isAlliedTo(target))) - return false; - - double range = this.rangeRetriever.apply(entity); - - if (range > 0) { - double sightRange = Math.max(range * (this.ignoresInvisibility ? 1 : target.getVisibilityPercent(entity)), 2); - - if (entity.distanceToSqr(target) > sightRange * sightRange) - return false; - } - - if (this.checkLineOfSight) - return SensoryUtils.hasLineOfSight(entity, target); - - return true; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/FixedNearestVisibleLivingEntities.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/FixedNearestVisibleLivingEntities.java deleted file mode 100644 index 2894024ba..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/FixedNearestVisibleLivingEntities.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities; -import mod.azure.azurelib.sblforked.util.SensoryUtils; - -import java.util.List; -import java.util.function.Predicate; - -/** - * Wrapper for {@link NearestVisibleLivingEntities} that supports follow range for entities rather than a hardcoded 16-block limit - */ -public class FixedNearestVisibleLivingEntities extends NearestVisibleLivingEntities { - private FixedNearestVisibleLivingEntities() { - super(); - } - - public FixedNearestVisibleLivingEntities(LivingEntity entity, List entities) { - super(); - - this.nearbyEntities = entities; - this.lineOfSightTest = new Predicate<>() { - final Object2BooleanOpenHashMap cache = new Object2BooleanOpenHashMap<>(entities.size()); - - @Override - public boolean test(LivingEntity target) { - return this.cache.computeIfAbsent(target, (Predicate)target1 -> SensoryUtils.isEntityTargetable(entity, target1)); - } - }; - } - - public static FixedNearestVisibleLivingEntities empty() { - return new FixedNearestVisibleLivingEntities(); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/FreePositionTracker.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/FreePositionTracker.java deleted file mode 100644 index 5758c675d..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/FreePositionTracker.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.ai.behavior.PositionTracker; -import net.minecraft.world.phys.Vec3; - -public class FreePositionTracker implements PositionTracker { - private final Vec3 pos; - - public FreePositionTracker(Vec3 pos) { - this.pos = pos; - } - - @Override - public Vec3 currentPosition() { - return pos; - } - - @Override - public BlockPos currentBlockPosition() { - return BlockPos.containing(pos); - } - - @Override - public boolean isVisibleBy(LivingEntity entity) { - return true; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/SBLShufflingList.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/SBLShufflingList.java deleted file mode 100644 index 81b3aff73..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/SBLShufflingList.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import com.mojang.datafixers.util.Pair; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import it.unimi.dsi.fastutil.objects.ObjectIterators; -import net.minecraft.util.RandomSource; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.function.Consumer; -import java.util.stream.Stream; - -public class SBLShufflingList implements Iterable { - private final List> entries; - private final RandomSource random = RandomSource.createNewThreadLocalInstance(); - - public SBLShufflingList() { - this.entries = new ObjectArrayList<>(); - } - - public SBLShufflingList(int size) { - this.entries = new ObjectArrayList<>(size); - } - - public SBLShufflingList(Pair... entries) { - this.entries = new ObjectArrayList<>(entries.length); - - for (Pair entry : entries) { - this.entries.add(new WeightedEntry<>(entry.getFirst(), entry.getSecond())); - } - } - - public SBLShufflingList shuffle() { - this.entries.forEach(entry -> entry.setShuffledWeight(this.random.nextFloat())); - this.entries.sort(Comparator.comparingDouble(WeightedEntry::getShuffledWeight)); - - return this; - } - - public boolean add(T entry, int weight) { - return this.entries.add(new WeightedEntry<>(entry, weight)); - } - - @Nullable - public T get(int index) { - return this.entries.get(index).get(); - } - - @NotNull - @Override - public Iterator iterator() { - return new ObjectIterators.AbstractIndexBasedIterator<>(0, 0) { - @Override - protected T get(int location) { - return SBLShufflingList.this.entries.get(location).get(); - } - - @Override - protected void remove(int location) { - SBLShufflingList.this.entries.remove(location); - } - - @Override - protected int getMaxPos() { - return SBLShufflingList.this.entries.size(); - } - }; - } - - @Override - public void forEach(Consumer action) { - this.entries.forEach(entry -> action.accept(entry.get())); - } - - public Stream stream() { - return this.entries.stream().map(WeightedEntry::get); - } - - public static class WeightedEntry { - private final T object; - private final int weight; - private double shuffledWeight; - - WeightedEntry(T object, int weight) { - this.object = object; - this.weight = weight; - } - - double getShuffledWeight() { - return this.shuffledWeight; - } - - T get() { - return this.object; - } - - int getWeight() { - return this.weight; - } - - void setShuffledWeight(float mod) { - this.shuffledWeight = -Math.pow(mod, 1f / this.weight); - } - - @Override - public String toString() { - return this.object + ":" + this.weight; - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/SquareRadius.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/SquareRadius.java deleted file mode 100644 index 5d4775df5..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/SquareRadius.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Vec3i; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; - -/** - * Helper class to store radius values without needlessly using 3 values.
    - * Also comes with some handy helper methods. - * @param xzRadius The lateral radius value (X/Z direction) - * @param yRadius The vertical radius value (Y direction) - */ -public record SquareRadius(double xzRadius, double yRadius) { - public Vec3i toVec3i() { - return new Vec3i((int)this.xzRadius, (int)this.yRadius, (int)this.xzRadius); - } - - public BlockPos toBlockPos() { - return BlockPos.containing(this.xzRadius, this.yRadius, this.xzRadius); - } - - public Vec3 toVec3() { - return new Vec3(this.xzRadius, this.yRadius, this.xzRadius); - } - - public AABB inflateAABB(AABB bounds) { - return bounds.inflate(this.xzRadius, this.yRadius, this.xzRadius); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/object/TriPredicate.java b/common/src/main/java/mod/azure/azurelib/sblforked/object/TriPredicate.java deleted file mode 100644 index f68b3964d..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/object/TriPredicate.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.object; - -import java.util.Objects; - -/** - * Triple-argument variant of {@link java.util.function.Predicate} - */ -@FunctionalInterface -public interface TriPredicate { - boolean test(A a, B b, C c); - - default TriPredicate and(TriPredicate other) { - Objects.requireNonNull(other); - - return (A a, B b, C c) -> test(a, b, c) && other.test(a, b, c); - } - - default TriPredicate negate() { - return (A a, B b, C c) -> !test(a, b, c); - } - - default TriPredicate or(TriPredicate other) { - Objects.requireNonNull(other); - - return (A a, B b, C c) -> test(a, b, c) || other.test(a, b, c); - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLMemoryTypes.java b/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLMemoryTypes.java deleted file mode 100644 index 646486a59..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLMemoryTypes.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.registry; - -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Codec; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.projectile.Projectile; -import net.minecraft.world.level.block.state.BlockState; -import mod.azure.azurelib.sblforked.SBLConstants; - -import java.util.List; -import java.util.Optional; -import java.util.function.Supplier; - -/** - * Registry class for custom {@link MemoryModuleType Memory Types} - */ -public final class SBLMemoryTypes { - public static void init() {} - - public static final Supplier>> INCOMING_PROJECTILES = register("incoming_projectiles"); - public static final Supplier> TARGET_UNREACHABLE = register("target_unreachable"); - public static final Supplier> SPECIAL_ATTACK_COOLDOWN = register("special_attack_cooldown"); - public static final Supplier>>> NEARBY_BLOCKS = register("nearby_blocks"); - public static final Supplier>> NEARBY_ITEMS = register("nearby_items"); - - private static Supplier> register(String id) { - return register(id, Optional.empty()); - } - - private static Supplier> register(String id, Optional> codec) { - return SBLConstants.SBL_LOADER.registerMemoryType(id, codec); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLSensors.java b/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLSensors.java deleted file mode 100644 index 25540bae6..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/registry/SBLSensors.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.registry; - -import net.minecraft.world.entity.ai.sensing.SensorType; -import mod.azure.azurelib.sblforked.SBLConstants; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.api.core.sensor.custom.*; -import mod.azure.azurelib.sblforked.api.core.sensor.vanilla.*; - -import java.util.function.Supplier; - -/** - * Registry class for {@link ExtendedSensor} implementations - */ -public final class SBLSensors { - public static void init() {} - - // Vanilla sensors - public static final Supplier>> NEAREST_ITEM = register("nearest_item", NearestItemSensor::new); - public static final Supplier>> NEARBY_LIVING_ENTITY = register("nearby_living_entity", NearbyLivingEntitySensor::new); - public static final Supplier>> NEARBY_PLAYERS = register("nearby_players", NearbyPlayersSensor::new); - public static final Supplier>> NEAREST_HOME = register("nearest_home", NearestHomeSensor::new); - public static final Supplier>> HURT_BY = register("hurt_by", HurtBySensor::new); - public static final Supplier>> NEARBY_HOSTILE = register("nearby_hostile", NearbyHostileSensor::new); - public static final Supplier>> NEARBY_BABY = register("nearby_baby", NearbyBabySensor::new); - public static final Supplier>> SECONDARY_POI = register("secondary_poi", SecondaryPoiSensor::new); - public static final Supplier>> NEARBY_GOLEM = register("nearby_golem", NearbyGolemSensor::new); - public static final Supplier>> NEARBY_ADULT = register("nearby_adult", NearbyAdultSensor::new); - public static final Supplier>> ITEM_TEMPTING = register("item_tempting", ItemTemptingSensor::new); - public static final Supplier>> IN_WATER = register("in_water", InWaterSensor::new); - - // Entity Specific - public static final Supplier>> FROG_SPECIFIC = register("frog_specific", FrogSpecificSensor::new); - public static final Supplier>> AXOLOTL_SPECIFIC = register("axolotl_specific", AxolotlSpecificSensor::new); - public static final Supplier>> PIGLIN_SPECIFIC = register("piglin_specific", PiglinSpecificSensor::new); - public static final Supplier>> PIGLIN_BRUTE_SPECIFIC = register("piglin_brute_specific", PiglinBruteSpecificSensor::new); - public static final Supplier>> HOGLIN_SPECIFIC = register("hoglin_specific", HoglinSpecificSensor::new); - public static final Supplier>> WARDEN_SPECIFIC = register("warden_specific", WardenSpecificSensor::new); - - // Custom - public static final Supplier>> INCOMING_PROJECTILES = register("incoming_projectiles", IncomingProjectilesSensor::new); - public static final Supplier>> GENERIC_ATTACK_TARGET = register("generic_attack_target", GenericAttackTargetSensor::new); - public static final Supplier>> UNREACHABLE_TARGET = register("unreachable_target", UnreachableTargetSensor::new); - public static final Supplier>> NEARBY_BLOCKS = register("nearby_blocks", NearbyBlocksSensor::new); - public static final Supplier>> NEARBY_ITEMS = register("nearby_items", NearbyItemsSensor::new); - - private static > Supplier> register(String id, Supplier sensor) { - return SBLConstants.SBL_LOADER.registerSensorType(id, sensor); - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/BrainUtils.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/BrainUtils.java deleted file mode 100644 index 268ab1ed9..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/BrainUtils.java +++ /dev/null @@ -1,558 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.util; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.ai.Brain; -import net.minecraft.world.entity.ai.behavior.Behavior; -import net.minecraft.world.entity.ai.behavior.BehaviorControl; -import net.minecraft.world.entity.ai.behavior.BehaviorUtils; -import net.minecraft.world.entity.ai.behavior.GateBehavior; -import net.minecraft.world.entity.ai.memory.ExpirableValue; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.Sensor; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.minecraft.world.entity.schedule.Activity; -import net.minecraft.world.entity.schedule.Schedule; -import net.minecraft.world.entity.schedule.Timeline; -import mod.azure.azurelib.sblforked.api.core.BrainActivityGroup; -import mod.azure.azurelib.sblforked.api.core.SmartBrain; -import mod.azure.azurelib.sblforked.api.core.behaviour.GroupBehaviour; -import mod.azure.azurelib.sblforked.api.core.schedule.SmartBrainSchedule; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.object.BrainBehaviourConsumer; -import mod.azure.azurelib.sblforked.object.BrainBehaviourPredicate; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.stream.Stream; - -/** - * Utility class for various brain functions. Try to utilise this where possible to ensure consistency and safety. - */ -public final class BrainUtils { - /** - * Get a memory value from an entity, with a fallback value if no memory is present - * - * @param entity The entity - * @param memory Memory type to get the value for - * @param fallback Fallback value if no memory value is present - * @return The stored memory, or fallback value if no memory was stored - * @param The type of object the memory uses - */ - public static T memoryOrDefault(LivingEntity entity, MemoryModuleType memory, Supplier fallback) { - return memoryOrDefault(entity.getBrain(), memory, fallback); - } - - /** - * Get a memory value from a brain, with a fallback value if no memory is present - * - * @param brain The brain - * @param memory Memory type to get the value for - * @param fallback Fallback value if no memory value is present - * @return The stored memory, or fallback value if no memory was stored - * @param The type of object the memory uses - */ - public static T memoryOrDefault(Brain brain, MemoryModuleType memory, Supplier fallback) { - return brain.getMemory(memory).orElseGet(fallback); - } - - /** - * Get a memory value from an entity, or null if no memory is present - * - * @param entity The entity - * @param memory Memory type to get the value for - * @return The stored memory, or null if no memory was stored - * @param The type of object the memory uses - */ - @Nullable - public static T getMemory(LivingEntity entity, MemoryModuleType memory) { - return getMemory(entity.getBrain(), memory); - } - - /** - * Get a memory value from a brain, or null if no memory is present - * - * @param brain The brain - * @param memory Memory type to get the value for - * @return The stored memory, or null if no memory was stored - * @param The type of object the memory uses - */ - @Nullable - public static T getMemory(Brain brain, MemoryModuleType memory) { - return memoryOrDefault(brain, memory, () -> null); - } - - /** - * Perform an operation on a given memory value, if present. If no memory value set, operation is not run - * - * @param entity The entity - * @param memory Memory type to get the value for - * @param consumer The operation to run if the memory is present - * @param The type of object the memory uses - */ - public static void withMemory(LivingEntity entity, MemoryModuleType memory, Consumer consumer) { - withMemory(entity.getBrain(), memory, consumer); - } - - /** - * Perform an operation on a given memory value, if present. If no memory value set, operation is not run - * - * @param brain The brain - * @param memory Memory type to get the value for - * @param consumer The operation to run if the memory is present - * @param The type of object the memory uses - */ - public static void withMemory(Brain brain, MemoryModuleType memory, Consumer consumer) { - brain.getMemory(memory).ifPresent(consumer); - } - - /** - * Check whether an entity has a memory value set. - * - * @param entity The entity - * @param memory Memory type to get the value for - * @return True if the memory value is present, or false if the memory value is absent or unregistered - */ - public static boolean hasMemory(LivingEntity entity, MemoryModuleType memory) { - return hasMemory(entity.getBrain(), memory); - } - /** - * Check whether a brain has a memory value set. - * - * @param brain The brain - * @param memory Memory type to get the value for - * @return True if the memory value is present, or false if the memory value is absent or unregistered - */ - public static boolean hasMemory(Brain brain, MemoryModuleType memory) { - return brain.hasMemoryValue(memory); - } - - /** - * Gets the ticks remaining until a memory expires. - * @param entity The entity - * @param memory Memory type to get the expiry time for - * @return The ticks until the memory expires, or 0 if the memory doesn't exist or doesn't expire - */ - public static long getTimeUntilMemoryExpires(LivingEntity entity, MemoryModuleType memory) { - return getTimeUntilMemoryExpires(entity.getBrain(), memory); - } - - /** - * Gets the ticks remaining until a memory expires. - * @param brain The brain - * @param memory Memory type to get the expiry time for - * @return The ticks until the memory expires, or 0 if the memory doesn't exist or doesn't expire - */ - public static long getTimeUntilMemoryExpires(Brain brain, MemoryModuleType memory) { - return brain.getTimeUntilExpiry(memory); - } - - /** - * Set an entity's memory value for the given memory type.
    - * Use {@link BrainUtils#clearMemory(LivingEntity, MemoryModuleType)} if intending to set a memory to nothing. - * - * @param entity The entity - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param The type of object the memory uses - */ - public static void setMemory(LivingEntity entity, MemoryModuleType memoryType, T memory) { - setMemory(entity.getBrain(), memoryType, memory); - } - - /** - * Set a brain's memory value for the given memory type.
    - * Use {@link BrainUtils#clearMemory(Brain, MemoryModuleType)} if intending to set a memory to nothing. - * - * @param brain The brain - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param The type of object the memory uses - */ - public static void setMemory(Brain brain, MemoryModuleType memoryType, T memory) { - brain.setMemory(memoryType, memory); - } - - /** - * Set a brain's memory value for the given memory type, with the memory expiring after a certain time.
    - * Use {@link BrainUtils#clearMemory(LivingEntity, MemoryModuleType)} if intending to set a memory to nothing. - * @param entity The entity - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param expirationTicks How many ticks until the memory expires - * @param The type of object the memory uses - */ - public static void setForgettableMemory(LivingEntity entity, MemoryModuleType memoryType, T memory, int expirationTicks) { - setForgettableMemory(entity.getBrain(), memoryType, memory, expirationTicks); - } - - /** - * Set an entity's memory value for the given memory type, with the memory expiring after a certain time.
    - * Use {@link BrainUtils#clearMemory(Brain, MemoryModuleType)} if intending to set a memory to nothing. - * @param brain The brain - * @param memoryType Memory type to set the value for - * @param memory The memory value to set - * @param expirationTicks How many ticks until the memory expires - * @param The type of object the memory uses - */ - public static void setForgettableMemory(Brain brain, MemoryModuleType memoryType, T memory, int expirationTicks) { - brain.setMemoryWithExpiry(memoryType, memory, expirationTicks); - } - - /** - * Wipe an entity's memory value for the given memory type. This safely unsets a memory, returning it to empty. - * - * @param entity The entity - * @param memory Memory type to erase the value for - */ - public static void clearMemory(LivingEntity entity, MemoryModuleType memory) { - clearMemory(entity.getBrain(), memory); - } - - /** - * Wipe a brain's memory value for the given memory type. This safely unsets a memory, returning it to empty. - * - * @param brain The brain - * @param memory Memory type to erase the value for - */ - public static void clearMemory(Brain brain, MemoryModuleType memory) { - brain.eraseMemory(memory); - } - - /** - * Wipe multiple memories for a given entity. This safely unsets each memory, returning them to empty. - * - * @param entity The entity - * @param memories The list of memory types to erase the values for - */ - public static void clearMemories(LivingEntity entity, MemoryModuleType... memories) { - clearMemories(entity.getBrain(), memories); - } - - /** - * Wipe multiple memories for a given brain. This safely unsets each memory, returning them to empty. - * - * @param brain The brain - * @param memories The list of memory types to erase the values for - */ - public static void clearMemories(Brain brain, MemoryModuleType... memories) { - for (MemoryModuleType memory : memories) { - brain.eraseMemory(memory); - } - } - - /** - * Gets the current attack target of an entity, if present. - * - * @param entity The entity - * @return The current attack target of the entity, or null if none present - */ - @Nullable - public static LivingEntity getTargetOfEntity(LivingEntity entity) { - return getTargetOfEntity(entity, null); - } - - /** - * Gets the current attack target of an entity, if present, or an optional fallback entity if none present - * - * @param entity The entity - * @param fallback Optional fallback entity to return if no attack target is set. - * @return The current attack target of the entity, the fallback entity if provided, or null otherwise - */ - @Nullable - public static LivingEntity getTargetOfEntity(LivingEntity entity, @Nullable LivingEntity fallback) { - return memoryOrDefault(entity.getBrain(), MemoryModuleType.ATTACK_TARGET, () -> fallback); - } - - /** - * Gets the last entity to attack the given entity, if present.
    - * Requires that the entity uses the {@link MemoryModuleType#HURT_BY_ENTITY} memory type, and a sensor that sets it - * - * @param entity The entity - * @return The last entity to attack the given entity, or null if none present - */ - @Nullable - public static LivingEntity getLastAttacker(LivingEntity entity) { - return memoryOrDefault(entity, MemoryModuleType.HURT_BY_ENTITY, () -> null); - } - - /** - * Sets the attack target of the given entity, and safely sets the non-brain attack target for compatibility purposes.
    - * Provided target can be null to effectively remove an entity's attack target. - * - * @param entity The entity - * @param target The entity to target - */ - public static void setTargetOfEntity(LivingEntity entity, @Nullable LivingEntity target) { - if (entity instanceof Mob mob) - mob.setTarget(target); - - if (target == null) { - clearMemory(entity, MemoryModuleType.ATTACK_TARGET); - } - else { - setMemory(entity, MemoryModuleType.ATTACK_TARGET, target); - } - } - - /** - * Replacement of {@link net.minecraft.world.entity.ai.behavior.BehaviorUtils#canSee}, falling back to a raytrace check in the event the target entity isn't in the {@link MemoryModuleType#NEAREST_VISIBLE_LIVING_ENTITIES} memory - * @param entity The entity to check the brain of - * @param target The target entity - * @return Whether the target entity is known to be visible or not - */ - public static boolean canSee(LivingEntity entity, LivingEntity target) { - Brain brain = entity.getBrain(); - - if (BehaviorUtils.entityIsVisible(brain, target)) - return true; - - return entity.hasLineOfSight(target); - } - - /** - * Sets a {@link SBLMemoryTypes#SPECIAL_ATTACK_COOLDOWN} value for a certain length of time.
    - * This can then be checked via {@link BrainUtils#isOnSpecialCooldown(LivingEntity)} as needed. - * @param entity The entity to check the brain of - * @param ticks The length of time (in ticks) the cooldown should apply for - */ - public static void setSpecialCooldown(LivingEntity entity, int ticks) { - setForgettableMemory(entity, SBLMemoryTypes.SPECIAL_ATTACK_COOLDOWN.get(), true, ticks); - } - - /** - * Checks whether the entity has had a {@link SBLMemoryTypes#SPECIAL_ATTACK_COOLDOWN} set, and it hasn't expired.
    - * This can be used for cross-behaviour cooldowns and interactions - * @param entity The entity to check the brain of - * @return Whether the entity has a cooldown currently active - */ - public static boolean isOnSpecialCooldown(LivingEntity entity) { - return hasMemory(entity, SBLMemoryTypes.SPECIAL_ATTACK_COOLDOWN.get()); - } - - /** - * Returns a stream of all {@link BehaviorControl Behaviours} registered to this brain - */ - public static Stream> getAllBehaviours(Brain brain) { - if (brain instanceof SmartBrain smartBrain) - return smartBrain.getBehaviours(); - - return brain.availableBehaviorsByPriority.values().stream() - .map(Map::values) - .flatMap(set -> set.stream().map(value -> value.stream().toList()).flatMap(List::stream)); - } - - /** - * Loops over all {@link BehaviorControl Behaviours} registered to this brain, calling the consumer for each - * @param brain The brain to scrape the behaviours of - * @param consumer The consumer called for each - */ - public static void forEachBehaviour(Brain brain, BrainBehaviourConsumer consumer) { - if (brain instanceof SmartBrain smartBrain) { - smartBrain.forEachBehaviour(consumer); - - return; - } - - Set>>>> behaviours = (Set)brain.availableBehaviorsByPriority.entrySet(); - - for (Map.Entry>>> priorityEntry : behaviours) { - Integer priority = priorityEntry.getKey(); - - for (Map.Entry>> activityEntry : priorityEntry.getValue().entrySet()) { - Activity activity = activityEntry.getKey(); - - for (BehaviorControl behaviour : activityEntry.getValue()) { - consumeBehaviour(priority, activity, behaviour, null, consumer); - } - } - } - } - - private static void consumeBehaviour(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parentBehaviour, BrainBehaviourConsumer consumer) { - consumer.consume(priority, activity, behaviour, parentBehaviour); - - if (behaviour instanceof GateBehavior groupBehaviour) { - groupBehaviour.behaviors.stream().forEach(childBehaviour -> consumeBehaviour(priority, activity, (BehaviorControl)childBehaviour, groupBehaviour, consumer)); - } - else if (behaviour instanceof GroupBehaviour groupBehaviour) { - groupBehaviour.getBehaviours().forEachRemaining(childBehaviour -> consumeBehaviour(priority, activity, (BehaviorControl)childBehaviour, groupBehaviour, consumer)); - } - } - - /** - * Removes any behaviours matching the given predicate from the provided brain.
    - * Removed behaviours are stopped prior to removal - * @param entity The owner of the brain - * @param predicate The predicate checked for each - */ - public static void removeBehaviour(E entity, BrainBehaviourPredicate predicate) { - if (entity.getBrain() instanceof SmartBrain smartBrain) { - smartBrain.removeBehaviour(entity, predicate); - - return; - } - - Set>>>> behaviours = (Set)entity.getBrain().availableBehaviorsByPriority.entrySet(); - - for (Map.Entry>>> priorityEntry : behaviours) { - Integer priority = priorityEntry.getKey(); - - for (Map.Entry>> activityEntry : priorityEntry.getValue().entrySet()) { - Activity activity = activityEntry.getKey(); - - for (Iterator> iterator = activityEntry.getValue().iterator(); iterator.hasNext();) { - BehaviorControl behaviour = iterator.next(); - - checkBehaviour(priority, activity, behaviour, null, predicate, () -> { - if (behaviour.getStatus() == Behavior.Status.RUNNING) - behaviour.doStop((ServerLevel)entity.level(), entity, entity.level().getGameTime()); - - iterator.remove(); - }); - } - } - } - } - - private static void checkBehaviour(int priority, Activity activity, BehaviorControl behaviour, @Nullable BehaviorControl parentBehaviour, BrainBehaviourPredicate predicate, Runnable callback) { - if (predicate.isBehaviour(priority, activity, behaviour, parentBehaviour)) { - callback.run(); - } - else if (behaviour instanceof GateBehavior groupBehaviour) { - for (Iterator> childBehaviourIterator = groupBehaviour.behaviors.iterator(); childBehaviourIterator.hasNext();) { - checkBehaviour(priority, activity, childBehaviourIterator.next(), groupBehaviour, predicate, childBehaviourIterator::remove); - } - - if (!groupBehaviour.behaviors.iterator().hasNext()) - callback.run(); - } - else if (behaviour instanceof GroupBehaviour groupBehaviour) { - for (Iterator> childBehaviourIterator = groupBehaviour.getBehaviours(); childBehaviourIterator.hasNext();) { - checkBehaviour(priority, activity, childBehaviourIterator.next(), groupBehaviour, predicate, childBehaviourIterator::remove); - } - - if (!groupBehaviour.getBehaviours().hasNext()) - callback.run(); - } - } - - /** - * Safely a new {@link BehaviorControl Behaviour} to the given {@link Brain} - * @param brain The brain to add the behaviour to - * @param priority The priority index the behaviour belongs to (lower runs earlier) - * @param activity The activity category the behaviour belongs to - * @param behaviourControl The behaviour to add - */ - public static void addBehaviour(Brain brain, int priority, Activity activity, BehaviorControl behaviourControl) { - if (brain instanceof SmartBrain smartBrain) { - smartBrain.addBehaviour(priority, activity, behaviourControl); - - return; - } - - brain.availableBehaviorsByPriority.computeIfAbsent(priority, priority2 -> Maps.newHashMap()).computeIfAbsent(activity, activity2 -> Sets.newLinkedHashSet()).add(behaviourControl); - - if (behaviourControl instanceof Behavior behavior) { - for (MemoryModuleType memoryType : behavior.entryCondition.keySet()) { - brain.memories.putIfAbsent(memoryType, Optional.empty()); - } - } - } - - /** - * Adds a full {@link BrainActivityGroup} to the brain, inclusive of activities and conditions - */ - public static void addActivity(Brain brain, BrainActivityGroup behaviourGroup) { - if (brain instanceof SmartBrain smartBrain) { - smartBrain.addActivity(behaviourGroup); - - return; - } - - brain.addActivityAndRemoveMemoriesWhenStopped(behaviourGroup.getActivity(), (ImmutableList)behaviourGroup.pairBehaviourPriorities(), behaviourGroup.getActivityStartMemoryConditions(), behaviourGroup.getWipedMemoriesOnFinish()); - } - - /** - * Adds a sensor to the given brain, additionally allowing for custom instantiation.
    - * Automatically adds detected memories to the brain, but because of the nature of the vanilla brain system, - * you may need to {@link BrainUtils#addMemories add additional memories manually} if Mojang didn't set something up properly - */ - public static > void addSensor(Brain brain, SensorType sensorType, S sensor) { - if (brain instanceof SmartBrain smartBrain) { - if (!(sensor instanceof ExtendedSensor extendedSensor)) - throw new IllegalArgumentException("Attempted to provide sensor to SmartBrain, only ExtendedSensor subclasses acceptable. Sensor: " + sensor.getClass()); - - smartBrain.addSensor(extendedSensor); - - return; - } - - brain.sensors.put((SensorType)sensorType, (Sensor)sensor); - addMemories(brain, sensor.requires().toArray(new MemoryModuleType[0])); - } - - /** - * Adds the given {@link MemoryModuleType} to the provided brain.
    - * Generally only required if modifying vanilla brains and additional memories are needed. - */ - public static void addMemories(Brain brain, MemoryModuleType... memories) { - if (brain instanceof SmartBrain smartBrain) { - for (MemoryModuleType memoryType : memories) { - smartBrain.getMemory(memoryType); - } - - return; - } - - for (MemoryModuleType memoryType : memories) { - brain.memories.computeIfAbsent(memoryType, key -> Optional.empty()).map(ExpirableValue::getValue); - } - } - - /** - * Adds the given scheduled activity transition to the provided brain's {@link net.minecraft.world.entity.schedule.Schedule schedule}, creating a new schedule if required. - * @param brain The brain the schedule belongs to - * @param activity The activity to transition to - * @param tickTime The tick-time the activity transition should happen - * @param tickType The type of tick tracking the schedule should use, if a new schedule has to be created. - */ - public static void addScheduledActivityTransition(Brain brain, Activity activity, int tickTime, SmartBrainSchedule.Type tickType) { - if (brain instanceof SmartBrain smartBrain) { - SmartBrainSchedule schedule; - - if ((schedule = smartBrain.getSchedule()) == null) - smartBrain.setSchedule((schedule = new SmartBrainSchedule(tickType))); - - schedule.activityAt(tickTime, activity); - } - else { - Schedule schedule; - - if ((schedule = brain.getSchedule()) == Schedule.EMPTY) - brain.setSchedule(new Schedule()); - - Timeline timeline = schedule.timelines.computeIfAbsent(activity, key -> new Timeline()); - - timeline.addKeyframe(tickTime, 1); - - for (Map.Entry entry : schedule.timelines.entrySet()) { - if (entry.getKey() != activity) - entry.getValue().addKeyframe(tickTime, 0); - } - } - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/EntityRetrievalUtil.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/EntityRetrievalUtil.java deleted file mode 100644 index fe544a025..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/EntityRetrievalUtil.java +++ /dev/null @@ -1,331 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.util; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.apache.commons.lang3.mutable.MutableDouble; -import org.apache.commons.lang3.mutable.MutableObject; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.Predicate; - -/** - * A helper class for retrieving entities from a given world. This removes a lot - * of the overhead of vanilla's type-checking and redundant stream-collection. - * Ultimately this leaves casting up to the end-user, and streamlines the actual - * retrieval functions to their most optimised form. - */ -public final class EntityRetrievalUtil { - /** - * Get the nearest entity from an existing list of entities. - * - * @param origin The center-point of the distance comparison - * @param entities The existing list of entities - * @return The closest entity to the origin point, or null if the input list was - * empty - * @param The entity type - */ - @Nullable - public static T getNearest(Vec3 origin, List entities) { - if (entities.isEmpty()) - return null; - - double dist = Double.MAX_VALUE; - T closest = null; - - for (T entity : entities) { - double entityDist = entity.distanceToSqr(origin); - - if (entityDist < dist) { - dist = entityDist; - closest = entity; - } - } - - return closest; - } - - /** - * Retrieve the nearest entity with a certain radius of a given origin point - * that meet a given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The predicate to filter entities by - * @return The closest entity found that meets the given criteria, or null if - * none found - * @param The output entity subtype - */ - @Nullable - public static T getNearestEntity(Entity origin, double radius, Predicate predicate) { - return getNearestEntity(origin, radius, radius, radius, predicate); - } - - /** - * Retrieve the nearest entity with a certain radius of a given origin point - * that meet a given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The predicate to filter entities by - * @return The closest entity found that meets the given criteria, or null if - * none found - * @param The output entity subtype - */ - @Nullable - public static T getNearestEntity(Entity origin, double radiusX, double radiusY, double radiusZ, Predicate predicate) { - return getNearestEntity(origin.level(), - new AABB(origin.getX() - radiusX, origin.getY() - radiusY, origin.getZ() - radiusZ, - origin.getX() + radiusX, origin.getY() + radiusY, origin.getZ() + radiusZ), - origin.position(), predicate); - } - - /** - * Retrieve the nearest entity with a certain radius of a given origin point - * that meet a given criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param level The level to search in - * @param area The region to search for entities in - * @param origin The center-point of the search - * @param predicate The predicate to filter entities by - * @return The closest entity found that meets the given criteria, or null if - * none found - * @param The output entity subtype - */ - @Nullable - public static T getNearestEntity(Level level, AABB area, Vec3 origin, Predicate predicate) { - final Predicate typeSafePredicate = (Predicate) predicate; - final MutableDouble dist = new MutableDouble(Double.MAX_VALUE); - final MutableObject closest = new MutableObject<>(null); - - level.getEntities().get(area, entity -> { - if (typeSafePredicate.test(entity)) { - double entityDist = entity.distanceToSqr(origin); - - if (entityDist < dist.getValue()) { - dist.setValue(entityDist); - closest.setValue(entity); - } - } - }); - - return (T) closest.getValue(); - } - - /** - * Retrieve the nearest player with a certain radius of a given origin point - * that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The predicate to filter players by - * @return The closest entity found that meets the given criteria, or null if - * none found - */ - @Nullable - public static Player getNearestPlayer(Entity origin, double radius, Predicate predicate) { - return getNearestPlayer(origin, radius, radius, radius, predicate); - } - - /** - * Retrieve the nearest player with a certain radius of a given origin point - * that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The predicate to filter players by - * @return The closest entity found that meets the given criteria, or null if - * none found - */ - @Nullable - public static Player getNearestPlayer(Entity origin, double radiusX, double radiusY, double radiusZ, Predicate predicate) { - return getNearestPlayer(origin.level(), - new AABB(origin.getX() - radiusX, origin.getY() - radiusY, origin.getZ() - radiusZ, - origin.getX() + radiusX, origin.getY() + radiusY, origin.getZ() + radiusZ), - origin.position(), predicate); - } - - /** - * Retrieve the nearest player with a certain radius of a given origin point - * that meet a given criteria. - * - * @param level The level to search in - * @param area The region to search for players in - * @param origin The center-point of the search - * @param predicate The predicate to filter players by - * @return The closest entity found that meets the given criteria, or null if - * none found - */ - @Nullable - public static Player getNearestPlayer(Level level, AABB area, Vec3 origin, Predicate predicate) { - double dist = Double.MAX_VALUE; - Player closest = null; - - for (Player player : level.players()) { - if (area.contains(player.position()) && predicate.test(player)) { - double playerDist = player.distanceToSqr(origin); - - if (playerDist < dist) { - dist = playerDist; - closest = player; - } - } - } - - return closest; - } - - /** - * Get all players within a given region. - * - * @param level The level in which to search - * @param area The region in which to find players - * @return A list of players that are within the given region - */ - public static List getPlayers(Level level, AABB area) { - return getPlayers(level, area, pl -> true); - } - - /** - * Get all players within a given region that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The criteria to meet for a player to be included in the - * returned list - * @return A list of players that are within the given region that meet the - * criteria in the predicate - */ - public static List getPlayers(Entity origin, double radius, Predicate predicate) { - return getPlayers(origin, radius, radius, radius, predicate); - } - - /** - * Get all players within a given region that meet a given criteria. - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The criteria to meet for a player to be included in the - * returned list - * @return A list of players that are within the given region that meet the - * criteria in the predicate - */ - public static List getPlayers(Entity origin, double radiusX, double radiusY, double radiusZ, Predicate predicate) { - return getPlayers(origin.level(), new AABB(origin.getX() - radiusX, origin.getY() - radiusY, - origin.getZ() - radiusZ, origin.getX() + radiusX, origin.getY() + radiusY, origin.getZ() + radiusZ), - predicate); - } - - /** - * Get all players within a given region that meet a given criteria. - * - * @param level The level in which to search - * @param area The region in which to find players - * @param predicate The criteria to meet for a player to be included in the - * returned list - * @return A list of players that are within the given region that meet the - * criteria in the predicate - */ - public static List getPlayers(Level level, AABB area, Predicate predicate) { - List players = new ObjectArrayList<>(); - - for (Player player : level.players()) { - if (area.contains(player.position()) && predicate.test(player)) - players.add(player); - } - - return players; - } - - /** - * Retrieve all nearby entities from the given area that meet the given - * criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radius The radius on the axis to search - * @param predicate The predicate to filter entities by - * @return A list of entities found in the provided region that meet the - * criteria of the predicate, or an empty list if none match - * @param The output entity subtype - */ - public static List getEntities(Entity origin, double radius, Predicate predicate) { - return getEntities(origin, radius, radius, radius, predicate); - } - - /** - * Retrieve all nearby entities from the given area that meet the given - * criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param origin The entity to act as the central point of the search radius - * @param radiusX The radius on the x-axis to search - * @param radiusY The radius on the y-axis to search - * @param radiusZ The radius on the z-axis to search - * @param predicate The predicate to filter entities by - * @return A list of entities found in the provided region that meet the - * criteria of the predicate, or an empty list if none match - * @param The output entity subtype - */ - public static List getEntities(Entity origin, double radiusX, double radiusY, double radiusZ, Predicate predicate) { - return getEntities(origin.level(), - new AABB(origin.getX() - radiusX, origin.getY() - radiusY, origin.getZ() - radiusZ, - origin.getX() + radiusX, origin.getY() + radiusY, origin.getZ() + radiusZ), - predicate.and(entity -> entity != origin)); - } - - /** - * Retrieve all nearby entities from the given area that meet the given - * criteria.
    - * Note that the output is blind-cast to your intended output type for ease of - * use. Make sure you check {@code instanceof} in your predicate if you intend - * to use any subclass of Entity - * - * @param level The level to search in - * @param area The region to search for entities in - * @param predicate The predicate to filter entities by - * @return A list of entities found in the provided region that meet the - * criteria of the predicate, or an empty list if none match - * @param The output entity subtype - */ - public static List getEntities(Level level, AABB area, Predicate predicate) { - Predicate typeSafePredicate = (Predicate) predicate; - List entities = new ObjectArrayList<>(); - - level.getEntities().get(area, entity -> { - if (typeSafePredicate.test(entity)) - entities.add((T) entity); - }); - - return entities; - } -} diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/RandomUtil.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/RandomUtil.java deleted file mode 100644 index e7f5d1f38..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/RandomUtil.java +++ /dev/null @@ -1,267 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.util; - -import net.minecraft.core.BlockPos; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.levelgen.PositionalRandomFactory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.BiPredicate; - -/** - * Utility class for easy and legible random functionality. - */ -public final class RandomUtil { - public static final EasyRandom RANDOM = new EasyRandom(RandomSource.createThreadSafe()); - - public static ThreadLocalRandom getRandomInstance() { - return ThreadLocalRandom.current(); - } - - public static boolean fiftyFifty() { - return RANDOM.fiftyFifty(); - } - - public static boolean oneInNChance(int n) { - return RANDOM.oneInNChance(n); - } - - public static boolean percentChance(double percentChance) { - return RANDOM.percentChance(percentChance); - } - - public static boolean percentChance(float percentChance) { - return RANDOM.percentChance(percentChance); - } - - public static int randomNumberUpTo(int upperBound) { - return RANDOM.randomNumberUpTo(upperBound); - } - - public static float randomValueUpTo(float upperBound) { - return RANDOM.randomValueUpTo(upperBound); - } - - public static double randomValueUpTo(double upperBound) { - return RANDOM.randomValueUpTo(upperBound); - } - - public static double randomGaussianValue() { - return RANDOM.randomGaussianValue(); - } - - public static double randomScaledGaussianValue(double scale) { - return RANDOM.randomScaledGaussianValue(scale); - } - - public static int randomNumberBetween(int min, int max) { - return RANDOM.randomNumberBetween(min, max); - } - - public static double randomValueBetween(double min, double max) { - return RANDOM.randomValueBetween(min, max); - } - - public static T getRandomSelection(@NotNull T... options) { - return RANDOM.getRandomSelection(options); - } - - public static T getRandomSelection(@NotNull List options) { - return RANDOM.getRandomSelection(options); - } - - @NotNull - public static BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius) { - return RANDOM.getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius); - } - - @NotNull - public static BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius, boolean safeSurfacePlacement, Level world) { - return RANDOM.getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, safeSurfacePlacement, world); - } - - @NotNull - public static BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius, int minSpreadX, int minSpreadY, int minSpreadZ, boolean safeSurfacePlacement, Level world, int tries, @Nullable BiPredicate statePredicate) { - return RANDOM.getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, minSpreadX, minSpreadY, minSpreadZ, safeSurfacePlacement, world, tries, statePredicate); - } - - public static final class EasyRandom implements RandomSource { - private final RandomSource random; - - public EasyRandom() { - this(RandomSource.create()); - } - - public EasyRandom(@NotNull RandomSource rand) { - this.random = rand; - } - - public RandomSource getSource() { - return RandomSource.create(); - } - - public boolean fiftyFifty() { - return random.nextBoolean(); - } - - public boolean oneInNChance(int n) { - if (n <= 0) - return false; - - return random.nextFloat() < 1 / (float)n; - } - - public boolean percentChance(double percentChance) { - if (percentChance <= 0) - return false; - - if (percentChance >= 1) - return true; - - return random.nextDouble() < percentChance; - } - - public boolean percentChance(float percentChance) { - if (percentChance <= 0) - return false; - - if (percentChance >= 1) - return true; - - return random.nextDouble() < percentChance; - } - - public int randomNumberUpTo(int upperBound) { - return random.nextInt(upperBound); - } - - public float randomValueUpTo(float upperBound) { - return random.nextFloat() * upperBound; - } - - public double randomValueUpTo(double upperBound) { - return random.nextDouble() * upperBound; - } - - public double randomGaussianValue() { - return random.nextGaussian(); - } - - public double randomScaledGaussianValue(double scale) { - return random.nextGaussian() * scale; - } - - public int randomNumberBetween(int min, int max) { - return min + (int)Math.floor(random.nextDouble() * (1 + max - min)); - } - - public double randomValueBetween(double min, double max) { - return min + random.nextDouble() * (max - min); - } - - public T getRandomSelection(@NotNull T... options) { - return options[random.nextInt(options.length)]; - } - - public T getRandomSelection(@NotNull List options) { - return options.get(random.nextInt(options.size())); - } - - @NotNull - public BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius) { - return getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, false, null); - } - - @NotNull - public BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius, boolean safeSurfacePlacement, Level world) { - return getRandomPositionWithinRange(centerPos, xRadius, yRadius, zRadius, 0, 0, 0, safeSurfacePlacement, world, 1, null); - } - - @NotNull - public BlockPos getRandomPositionWithinRange(BlockPos centerPos, int xRadius, int yRadius, int zRadius, int minSpreadX, int minSpreadY, int minSpreadZ, boolean safeSurfacePlacement, Level world, int tries, @Nullable BiPredicate statePredicate) { BlockPos.MutableBlockPos mutablePos = centerPos.mutable(); - xRadius = Math.max(xRadius - minSpreadX, 0); - yRadius = Math.max(yRadius - minSpreadY, 0); - zRadius = Math.max(zRadius - minSpreadZ, 0); - - for (int i = 0; i < tries; i++) { - double xAdjust = random.nextFloat() * xRadius * 2 - xRadius; - double yAdjust = random.nextFloat() * yRadius * 2 - yRadius; - double zAdjust = random.nextFloat() * zRadius * 2 - zRadius; - int newX = (int)Math.floor(centerPos.getX() + xAdjust + minSpreadX * Math.signum(xAdjust)); - int newY = (int)Math.floor(centerPos.getY() + yAdjust + minSpreadY * Math.signum(yAdjust)); - int newZ = (int)Math.floor(centerPos.getZ() + zAdjust + minSpreadZ * Math.signum(zAdjust)); - - mutablePos.set(newX, newY, newZ); - - if (safeSurfacePlacement && world != null) - mutablePos.set(world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, mutablePos)); - - if (statePredicate == null || statePredicate.test(world.getBlockState(mutablePos), mutablePos.immutable())) - return mutablePos.immutable(); - } - - return centerPos; - } - - @Override - public EasyRandom fork() { - return new EasyRandom(this.random.fork()); - } - - @Override - public PositionalRandomFactory forkPositional() { - return this.random.forkPositional(); - } - - @Override - public void setSeed(long seed) { - this.random.setSeed(seed); - } - - @Override - public int nextInt() { - return this.random.nextInt(); - } - - @Override - public int nextInt(int upperLimit) { - return this.random.nextInt(upperLimit); - } - - @Override - public long nextLong() { - return this.random.nextLong(); - } - - @Override - public boolean nextBoolean() { - return this.random.nextBoolean(); - } - - @Override - public float nextFloat() { - return this.random.nextFloat(); - } - - @Override - public double nextDouble() { - return this.random.nextDouble(); - } - - @Override - public double nextGaussian() { - return this.random.nextGaussian(); - } - } -} \ No newline at end of file diff --git a/common/src/main/java/mod/azure/azurelib/sblforked/util/SensoryUtils.java b/common/src/main/java/mod/azure/azurelib/sblforked/util/SensoryUtils.java deleted file mode 100644 index db4045799..000000000 --- a/common/src/main/java/mod/azure/azurelib/sblforked/util/SensoryUtils.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.sblforked.util; - -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Mob; -import mod.azure.azurelib.sblforked.object.ExtendedTargetingConditions; - -/** - * Helper class for sensory-related utility methods. - *

    Mostly this just replaces the poorly implemented methods in {@link net.minecraft.world.entity.ai.sensing.Sensor}

    - */ -public class SensoryUtils { - /** - * Check whether the given target is considered 'targetable' based on sensory and status conditions such as teams and line of sight - * @return Whether the target is considered targetable - */ - public static boolean isEntityTargetable(LivingEntity attacker, LivingEntity target) { - final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target ? - ExtendedTargetingConditions.forLookTarget().withFollowRange().skipInvisibilityCheck() : - ExtendedTargetingConditions.forLookTarget().withFollowRange(); - - return predicate.test(attacker, target); - } - - /** - * Check whether the given target is considered 'attackable' based on sensory and status conditions such as teams and line of sight - * @return Whether the target is considered attackable - */ - public static boolean isEntityAttackable(LivingEntity attacker, LivingEntity target) { - final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target ? - ExtendedTargetingConditions.forAttackTarget().withFollowRange().skipInvisibilityCheck() : - ExtendedTargetingConditions.forAttackTarget().withFollowRange(); - - return predicate.test(attacker, target); - } - - /** - * Check whether the given target is considered 'attackable' based on sensory and status conditions such as teams and difficulty, but specifically excluding a line of sight check - * @return Whether the target is considered attackable - */ - public static boolean isEntityAttackableIgnoringLineOfSight(LivingEntity attacker, LivingEntity target) { - final ExtendedTargetingConditions predicate = BrainUtils.getTargetOfEntity(attacker) == target ? - ExtendedTargetingConditions.forAttackTarget().ignoreLineOfSight().withFollowRange().skipInvisibilityCheck() : - ExtendedTargetingConditions.forAttackTarget().ignoreLineOfSight().withFollowRange(); - - return predicate.test(attacker, target); - } - - /** - * Check whether the given target is visible to the entity - * @return Whether the entity has line of sight to the target - */ - public static boolean hasLineOfSight(LivingEntity entity, Entity target) { - if (entity instanceof Mob mob) - return mob.getSensing().hasLineOfSight(target); - - return entity.hasLineOfSight(target); - } -} diff --git a/common/src/main/resources/assets/azurelib/animations/block/stargate.animation.json b/common/src/main/resources/assets/azurelib/animations/block/stargate.animation.json new file mode 100644 index 000000000..fac7d0e36 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/block/stargate.animation.json @@ -0,0 +1,249 @@ +{ + "format_version": "1.8.0", + "animations": { + "spinning": { + "loop": true, + "animation_length": 14.4, + "bones": { + "bone2": { + "position": { + "1.0": { + "vector": [0, 0, 0] + }, + "1.08": { + "vector": [0, "math.sin(query.anim_time * 360) * -3", 0] + }, + "1.12": { + "vector": [0, 0, 0] + }, + "1.56": { + "vector": [0, 0, 0] + }, + "2.64": { + "vector": [0, 0, 0] + }, + "2.72": { + "vector": [0, "math.cos(query.anim_time * 360) * -3", 0] + }, + "2.76": { + "vector": [0, 0, 0] + }, + "3.2": { + "vector": [0, 0, 0] + }, + "4.32": { + "vector": [0, 0, 0] + }, + "4.4": { + "vector": [0, "math.sin(query.anim_time * 360) * -2", 0] + }, + "4.44": { + "vector": [0, 0, 0] + }, + "4.88": { + "vector": [0, 0, 0] + }, + "6.0": { + "vector": [0, 0, 0] + }, + "6.08": { + "vector": [0, "math.sin(query.anim_time * 360) * -3", 0] + }, + "6.12": { + "vector": [0, 0, 0] + }, + "6.56": { + "vector": [0, 0, 0] + }, + "7.68": { + "vector": [0, 0, 0] + }, + "7.76": { + "vector": [0, "math.cos(query.anim_time * 360) * -3", 0] + }, + "7.8": { + "vector": [0, 0, 0] + }, + "8.24": { + "vector": [0, 0, 0] + }, + "9.36": { + "vector": [0, 0, 0] + }, + "9.44": { + "vector": [0, "math.sin(query.anim_time * 360) * -3", 0] + }, + "9.48": { + "vector": [0, 0, 0] + }, + "9.92": { + "vector": [0, 0, 0] + }, + "10.96": { + "vector": [0, 0, 0] + }, + "11.04": { + "vector": [0, "math.sin(query.anim_time * 360) * -3", 0] + }, + "11.08": { + "vector": [0, 0, 0] + }, + "11.52": { + "vector": [0, 0, 0] + } + } + }, + "inner_ring": { + "rotation": { + "0.0": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "1.04": { + "vector": [0, 0, 360] + }, + "1.48": { + "vector": [0, 0, 359] + }, + "1.52": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * -360"] + }, + "2.56": { + "vector": [0, 0, 1] + }, + "3.16": { + "vector": [0, 0, 1] + }, + "3.2": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "4.32": { + "vector": [0, 0, 1] + }, + "5.24": { + "vector": [0, 0, 1] + }, + "5.28": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "5.88": { + "vector": [0, 0, 1] + }, + "5.92": { + "vector": [0, 0, 0] + }, + "6.92": { + "vector": [0, 0, 0] + }, + "6.96": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "7.56": { + "vector": [0, 0, 1] + }, + "7.6": { + "vector": [0, 0, 0] + }, + "8.12": { + "vector": [0, 0, 0] + }, + "8.16": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "9.2": { + "vector": [0, 0, 1] + }, + "9.28": { + "vector": [0, 0, 0] + }, + "9.84": { + "vector": [0, 0, 0] + }, + "10.88": { + "vector": [0, 0, 359] + }, + "10.96": { + "vector": [0, 0, 360] + } + } + }, + "portal": { + "scale": { + "0.0": { + "vector": [0, 0, 0] + }, + "11.48": { + "vector": [0, 0, 0] + }, + "11.52": { + "vector": [1, 1, 1] + }, + "12.4": { + "vector": [1, 1, 1] + } + } + }, + "portal2": { + "rotation": { + "11.52": { + "vector": [0, 0, "math.cos(query.anim_time * 360) * 360"] + }, + "13.44": { + "vector": [0, 0, 359] + } + }, + "position": { + "11.52": { + "vector": [0, 0, 0] + }, + "12.4": { + "vector": [0, 0, "-30.83+math.sin(query.anim_time * 200) * 10"] + }, + "13.44": { + "vector": [0, 0, 0] + } + }, + "scale": { + "0.0": { + "vector": [0, 0, 0] + }, + "11.52": { + "vector": [0, 0, 0] + }, + "12.4": { + "vector": [0.5, 0.5, 37.3] + }, + "13.44": { + "vector": [0, 0, 0] + } + } + } + } + }, + "idle": { + "loop": true, + "bones": { + "portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "portal2": { + "scale": { + "vector": [0, 0, 0] + } + } + } + }, + "open": { + "loop": true, + "bones": { + "bone9": { + "scale": { + "vector": [1, 1, 1] + } + } + } + } + }, + "azurelib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/animations/entity/doomhunter.animation.json b/common/src/main/resources/assets/azurelib/animations/entity/doomhunter.animation.json new file mode 100644 index 000000000..69b6c2c9a --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/entity/doomhunter.animation.json @@ -0,0 +1,2917 @@ +{ + "format_version": "1.8.0", + "animations": { + "idle": { + "loop": true, + "animation_length": 1.76, + "bones": { + "body": { + "rotation": { + "0.0": { + "vector": [0, 0, 2.5] + }, + "0.72": { + "vector": [0, 0, -2.5] + }, + "1.04": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, 2.5] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [-0.38, 1, 0] + }, + "0.24": { + "vector": [-2.77, 2, 0] + }, + "0.36": { + "vector": [-4.88, 1, 0] + }, + "0.48": { + "vector": [-5, 0, 0] + }, + "0.6": { + "vector": [-3.88, -2.5, 0] + }, + "0.72": { + "vector": [-2.77, -3, 0] + }, + "0.88": { + "vector": [-0.77, -0.5, 0] + }, + "1.04": { + "vector": [3.23, 2, 0] + }, + "1.16": { + "vector": [4.11, 2, 0] + }, + "1.28": { + "vector": [5, 0, 0] + }, + "1.4": { + "vector": [4.89, -1.5, 0] + }, + "1.52": { + "vector": [2.77, -3, 0] + }, + "1.64": { + "vector": [1.39, -2.5, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "lowJaw": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.48": { + "vector": [12.5, 0, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0] + }, + "0.48": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, -0.25, 0] + } + } + }, + "rShoulder": { + "rotation": { + "0.0": { + "vector": [0, 10, 30] + }, + "0.52": { + "vector": [-2.18558, 9.76061, 17.31336] + }, + "1.4": { + "vector": [-0.19637, 9.94863, 28.85482] + }, + "1.76": { + "vector": [0, 10, 30] + } + } + }, + "lArm1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.48": { + "vector": [0, 0, -5] + }, + "1.28": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "propulsion1": { + "rotation": { + "0.0": { + "vector": [0, 0, -5] + }, + "0.24": { + "vector": [0, 0, -5] + }, + "0.72": { + "vector": [0, 0, 0] + }, + "1.04": { + "vector": [0, 0, 5] + }, + "1.52": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, -5] + } + } + }, + "propulsion2": { + "rotation": { + "0.0": { + "vector": [0, 0, -5] + }, + "0.24": { + "vector": [0, 0, -5] + }, + "0.72": { + "vector": [0, 0, 0] + }, + "1.04": { + "vector": [0, 0, 5] + }, + "1.52": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, -5] + } + } + }, + "propulsion3": { + "rotation": { + "0.0": { + "vector": [0, 0, -5] + }, + "0.24": { + "vector": [0, 0, -5] + }, + "0.72": { + "vector": [0, 0, -5] + }, + "1.04": { + "vector": [0, 0, 0] + }, + "1.52": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, -5] + } + } + }, + "propulsion4": { + "rotation": { + "0.0": { + "vector": [0, 0, -5] + }, + "0.24": { + "vector": [0, 0, -5] + }, + "0.72": { + "vector": [0, 0, -5] + }, + "1.04": { + "vector": [0, 0, 0] + }, + "1.52": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, -5] + } + } + }, + "chest": { + "rotation": { + "vector": [12.5, 0, 0] + }, + "position": { + "vector": [0, 0, -3] + } + }, + "head": { + "rotation": { + "0.0": { + "vector": [0, 0, 2.5] + }, + "0.48": { + "vector": [0, 0, -2.5] + }, + "1.28": { + "vector": [0, 0, 2.5] + } + } + }, + "rArm1": { + "rotation": { + "0.0": { + "vector": [0, 0, -7.5] + }, + "0.48": { + "vector": [0, 0, -7.5] + }, + "1.28": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, -7.5] + } + } + }, + "rArm2": { + "rotation": { + "0.0": { + "vector": [-25, 0, 0] + }, + "0.48": { + "vector": [-24.89078, -3.53329, -3.54002] + }, + "1.28": { + "vector": [-25, 0, 0] + }, + "1.76": { + "vector": [-25, 0, 0] + } + } + }, + "bone8": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.48": { + "vector": [1, 0, 0] + }, + "1.28": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [0, 0, -12.5] + }, + "0.72": { + "vector": [0, 0, 12.5] + }, + "1.04": { + "vector": [0, 0, 7.5] + }, + "1.76": { + "vector": [0, 0, -12.5] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [-0.38, 1, 0] + }, + "0.24": { + "vector": [-2.77, 2, 0] + }, + "0.36": { + "vector": [-4.88, 1, 0] + }, + "0.48": { + "vector": [-5, 0, 0] + }, + "0.6": { + "vector": [-3.88, -2.5, 0] + }, + "0.72": { + "vector": [-2.77, -3, 0] + }, + "0.88": { + "vector": [-0.77, -0.5, 0] + }, + "1.04": { + "vector": [3.23, 2, 0] + }, + "1.16": { + "vector": [4.11, 2, 0] + }, + "1.28": { + "vector": [5, 0, 0] + }, + "1.4": { + "vector": [4.89, -1.5, 0] + }, + "1.52": { + "vector": [2.77, -3, 0] + }, + "1.64": { + "vector": [1.39, -2.5, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "lGun": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.48": { + "vector": [0, -2.5, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "rGun2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.48": { + "vector": [0, 0, 0] + }, + "1.04": { + "vector": [0, 2.5, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "base": { + "position": { + "0.0": { + "vector": [-2, 0, 0] + }, + "0.84": { + "vector": [2, 0, 0] + }, + "1.76": { + "vector": [-2, 0, 0] + } + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25] + }, + "0.08": { + "vector": [-2, 0, 1.25] + }, + "0.12": { + "vector": [-0.5, 0, 1.25] + }, + "0.16": { + "vector": [0, 0, -0.75] + }, + "0.2": { + "vector": [0, 0, 1.25] + }, + "0.24": { + "vector": [-2, 0, 1.25] + }, + "0.28": { + "vector": [-0.5, 0, 1.25] + }, + "0.32": { + "vector": [0, 0, -0.75] + }, + "0.36": { + "vector": [0, 0, 1.25] + }, + "0.4": { + "vector": [-2, 0, 1.25] + }, + "0.44": { + "vector": [-0.5, 0, 1.25] + }, + "0.48": { + "vector": [0, 0, -0.75] + }, + "0.52": { + "vector": [0, 0, 1.25] + }, + "0.56": { + "vector": [-2, 0, 1.25] + }, + "0.6": { + "vector": [-0.5, 0, 1.25] + }, + "0.64": { + "vector": [0, 0, -0.75] + }, + "0.68": { + "vector": [0, 0, 1.25] + }, + "0.72": { + "vector": [-2, 0, 1.25] + }, + "0.76": { + "vector": [-0.5, 0, 1.25] + }, + "0.8": { + "vector": [0, 0, -0.75] + }, + "0.84": { + "vector": [0, 0, 1.25] + }, + "0.88": { + "vector": [-2, 0, 1.25] + }, + "0.92": { + "vector": [-0.5, 0, 1.25] + }, + "0.96": { + "vector": [0, 0, -0.75] + }, + "1.0": { + "vector": [0, 0, 1.25] + }, + "1.04": { + "vector": [-2, 0, 1.25] + }, + "1.08": { + "vector": [-0.5, 0, 1.25] + }, + "1.12": { + "vector": [0, 0, -0.75] + }, + "1.16": { + "vector": [0, 0, 1.25] + }, + "1.2": { + "vector": [-2, 0, 1.25] + }, + "1.24": { + "vector": [-0.5, 0, 1.25] + }, + "1.28": { + "vector": [0, 0, -0.75] + }, + "1.32": { + "vector": [0, 0, 1.25] + }, + "1.36": { + "vector": [-2, 0, 1.25] + }, + "1.4": { + "vector": [-0.5, 0, 1.25] + }, + "1.44": { + "vector": [0, 0, -0.75] + }, + "1.48": { + "vector": [0, 0, 1.25] + }, + "1.52": { + "vector": [-2, 0, 1.25] + }, + "1.56": { + "vector": [-0.5, 0, 1.25] + }, + "1.6": { + "vector": [0, 0, -0.75] + }, + "1.64": { + "vector": [0, 0, 1.25] + }, + "1.68": { + "vector": [-2, 0, 1.25] + }, + "1.72": { + "vector": [-0.5, 0, 1.25] + }, + "1.76": { + "vector": [0, 0, -0.75] + } + } + }, + "lShoulder": { + "rotation": { + "vector": [0, 0, 0] + } + } + } + }, + "walking": { + "loop": true, + "animation_length": 1.8, + "bones": { + "base": { + "rotation": { + "0.0": { + "vector": [5.00474, -2.49048, -0.21803] + }, + "0.44": { + "vector": [5.04292, -7.4713, -0.6574] + }, + "0.96": { + "vector": [5.00474, 2.49048, 0.21803] + }, + "1.48": { + "vector": [5.019, 4.98093, 0.43688] + }, + "1.8": { + "vector": [5.00474, -2.49048, -0.21803] + } + }, + "position": { + "0.0": { + "vector": [0, 4, 2.5] + }, + "0.08": { + "vector": [0, 5.41, 1.84] + }, + "0.2": { + "vector": [0, 6, 0] + }, + "0.32": { + "vector": [0, 5.16, -2.34] + }, + "0.44": { + "vector": [1, 4, -4] + }, + "0.56": { + "vector": [0, 2.91, -2.16] + }, + "0.68": { + "vector": [0, 2.25, 0] + }, + "0.8": { + "vector": [0, 2.84, 1.84] + }, + "0.92": { + "vector": [0, 4, 2.5] + }, + "1.0": { + "vector": [0, 5.41, 1.84] + }, + "1.12": { + "vector": [0, 6, 0] + }, + "1.24": { + "vector": [0, 5.16, -2.34] + }, + "1.36": { + "vector": [0, 4, -4] + }, + "1.48": { + "vector": [-1, 2.91, -2.16] + }, + "1.6": { + "vector": [0, 2.25, 0] + }, + "1.72": { + "vector": [0, 2.84, 1.84] + }, + "1.8": { + "vector": [0, 4, 2.5] + } + } + }, + "body": { + "rotation": { + "vector": [20, 0, 0] + }, + "position": { + "vector": [0, -1, 3] + } + }, + "lowJaw": { + "rotation": { + "0.0": { + "vector": [12.5, 0, 0] + }, + "0.88": { + "vector": [0, 0, 0] + }, + "1.8": { + "vector": [12.5, 0, 0] + } + } + }, + "rShoulder": { + "rotation": { + "0.0": { + "vector": [35, 0, 27.5] + }, + "0.28": { + "vector": [27.5, 0, 27.5] + }, + "0.64": { + "vector": [2.48637, 0.64686, 25.08508] + }, + "1.0": { + "vector": [20, 0, 27.5] + }, + "1.32": { + "vector": [32.5, 0, 27.5] + }, + "1.8": { + "vector": [35, 0, 27.5] + } + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25] + }, + "0.08": { + "vector": [-2, 0, 1.25] + }, + "0.12": { + "vector": [-0.5, 0, 1.25] + }, + "0.16": { + "vector": [0, 0, -0.75] + }, + "0.2": { + "vector": [0, 0, 1.25] + }, + "0.24": { + "vector": [-2, 0, 1.25] + }, + "0.28": { + "vector": [-0.5, 0, 1.25] + }, + "0.32": { + "vector": [0, 0, -0.75] + }, + "0.36": { + "vector": [0, 0, 1.25] + }, + "0.4": { + "vector": [-2, 0, 1.25] + }, + "0.44": { + "vector": [-0.5, 0, 1.25] + }, + "0.48": { + "vector": [0, 0, -0.75] + }, + "0.52": { + "vector": [0, 0, 1.25] + }, + "0.56": { + "vector": [-2, 0, 1.25] + }, + "0.6": { + "vector": [-0.5, 0, 1.25] + }, + "0.64": { + "vector": [0, 0, -0.75] + }, + "0.68": { + "vector": [0, 0, 1.25] + }, + "0.72": { + "vector": [-2, 0, 1.25] + }, + "0.76": { + "vector": [-0.5, 0, 1.25] + }, + "0.8": { + "vector": [0, 0, -0.75] + }, + "0.84": { + "vector": [0, 0, 1.25] + }, + "0.88": { + "vector": [-2, 0, 1.25] + }, + "0.92": { + "vector": [-0.5, 0, 1.25] + }, + "0.96": { + "vector": [0, 0, -0.75] + }, + "1.0": { + "vector": [0, 0, 1.25] + }, + "1.04": { + "vector": [-2, 0, 1.25] + }, + "1.08": { + "vector": [-0.5, 0, 1.25] + }, + "1.12": { + "vector": [0, 0, -0.75] + }, + "1.16": { + "vector": [0, 0, 1.25] + }, + "1.2": { + "vector": [-2, 0, 1.25] + }, + "1.24": { + "vector": [-0.5, 0, 1.25] + }, + "1.28": { + "vector": [0, 0, -0.75] + }, + "1.32": { + "vector": [0, 0, 1.25] + }, + "1.36": { + "vector": [-2, 0, 1.25] + }, + "1.4": { + "vector": [-0.5, 0, 1.25] + }, + "1.44": { + "vector": [0, 0, -0.75] + }, + "1.48": { + "vector": [0, 0, 1.25] + }, + "1.52": { + "vector": [-2, 0, 1.25] + }, + "1.56": { + "vector": [-0.5, 0, 1.25] + }, + "1.6": { + "vector": [0, 0, -0.75] + }, + "1.64": { + "vector": [0, 0, 1.25] + }, + "1.68": { + "vector": [-2, 0, 1.25] + }, + "1.72": { + "vector": [-0.5, 0, 1.25] + }, + "1.76": { + "vector": [0, 0, -0.75] + } + } + }, + "lArm1": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "propulsion1": { + "rotation": { + "0.0": { + "vector": [15, 0, 0] + }, + "0.28": { + "vector": [10, 0, 0] + }, + "0.56": { + "vector": [-2.5, 0, 0] + }, + "0.88": { + "vector": [15, 0, 0] + }, + "1.24": { + "vector": [10, 0, 0] + }, + "1.52": { + "vector": [-2.5, 0, 0] + }, + "1.8": { + "vector": [15, 0, 0] + } + } + }, + "propulsion2": { + "rotation": { + "0.0": { + "vector": [15, 0, 0] + }, + "0.28": { + "vector": [15, 0, 0] + }, + "0.56": { + "vector": [-5, 0, 0] + }, + "0.88": { + "vector": [15, 0, 0] + }, + "1.24": { + "vector": [15, 0, 0] + }, + "1.52": { + "vector": [-5, 0, 0] + }, + "1.8": { + "vector": [15, 0, 0] + } + } + }, + "propulsion3": { + "rotation": { + "0.0": { + "vector": [20, 0, 0] + }, + "0.28": { + "vector": [19.75778, 4.81281, -5.7589] + }, + "0.56": { + "vector": [19.97314, 1.60667, -1.91561] + }, + "0.88": { + "vector": [20, 0, 0] + }, + "1.24": { + "vector": [19.89247, -3.21154, 3.83424] + }, + "1.52": { + "vector": [19.97314, -1.60667, 1.91561] + }, + "1.8": { + "vector": [20, 0, 0] + } + } + }, + "propulsion4": { + "rotation": { + "0.0": { + "vector": [20, 0, 0] + }, + "0.28": { + "vector": [19.89247, 3.21154, -3.83424] + }, + "0.56": { + "vector": [19.97314, 1.60667, -1.91561] + }, + "0.88": { + "vector": [20, 0, 0] + }, + "1.24": { + "vector": [19.75778, -4.81281, 5.7589] + }, + "1.52": { + "vector": [19.97314, -1.60667, 1.91561] + }, + "1.8": { + "vector": [20, 0, 0] + } + } + }, + "chest": { + "rotation": { + "0.0": { + "vector": [-15, 0, 0] + }, + "0.56": { + "vector": [-15.34721, -12.06754, 3.28396] + }, + "1.52": { + "vector": [-15.22074, 9.65594, -2.61298] + }, + "1.8": { + "vector": [-15, 0, 0] + } + }, + "position": { + "vector": [0, -1, 1] + } + }, + "neck": { + "rotation": { + "vector": [-2.5, 0, 0] + } + }, + "head": { + "rotation": { + "0.0": { + "vector": [-2.50238, -2.49762, 0.10912] + }, + "0.56": { + "vector": [-2.5, 0, 0] + }, + "1.04": { + "vector": [-2.50238, -2.49762, 0.10912] + }, + "1.52": { + "vector": [-2.50954, -4.99523, 0.21865] + }, + "1.8": { + "vector": [-2.50238, -2.49762, 0.10912] + } + } + }, + "bone8": { + "rotation": { + "0.0": { + "vector": [0.5, 0, 0] + }, + "0.28": { + "vector": [0, 0, 0] + }, + "0.56": { + "vector": [0.5, 0, 0] + }, + "0.88": { + "vector": [0, 0, 0] + }, + "1.56": { + "vector": [0, 0, 0] + }, + "1.8": { + "vector": [0.5, 0, 0] + } + } + }, + "lShoulder": { + "rotation": { + "0.0": { + "vector": [25.01229, 7.69749, -4.68915] + }, + "0.44": { + "vector": [24.81197, 3.1622, -6.80423] + }, + "1.0": { + "vector": [25.01229, 7.69749, -4.68915] + }, + "1.48": { + "vector": [24.81197, 3.1622, -6.80423] + }, + "1.8": { + "vector": [25.01229, 7.69749, -4.68915] + } + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [15, 0, 0] + }, + "0.56": { + "vector": [20.01754, 2.34914, 0.85553] + }, + "0.92": { + "vector": [15.04507, -1.3275, -0.48507] + }, + "1.48": { + "vector": [20.07031, -4.69776, -1.71394] + }, + "1.8": { + "vector": [15, 0, 0] + } + } + } + } + }, + "flamethrower": { + "loop": true, + "animation_length": 1.76, + "bones": { + "rShoulder": { + "rotation": { + "0.0": { + "vector": [-10.32304, 44.70786, 22.04742] + }, + "0.88": { + "vector": [-31.90332, 23.29728, -10.1545] + }, + "1.76": { + "vector": [-10.32304, 44.70786, 22.04742] + } + } + }, + "base": { + "rotation": { + "vector": [0, -7.5, 0] + }, + "position": { + "0.0": { + "vector": [0, 0, 2] + }, + "0.04": { + "vector": [0, 0.05, 2.3] + }, + "0.24": { + "vector": [0, 0.47, 2.46] + }, + "0.52": { + "vector": [0, 1, 1] + }, + "1.04": { + "vector": [0, 0.67, -2] + }, + "1.76": { + "vector": [0, 0, 2] + } + } + }, + "chest": { + "rotation": { + "0.0": { + "vector": [0, -17.5, 0] + }, + "0.52": { + "vector": [0, -30, 0] + }, + "1.08": { + "vector": [0, -20, 0] + }, + "1.56": { + "vector": [0, -15, 0] + }, + "1.76": { + "vector": [0, -17.5, 0] + } + }, + "position": { + "vector": [-3, 0, -3.25] + } + }, + "head": { + "rotation": { + "vector": [0, 20, 0] + }, + "position": { + "vector": [1, 0, 0] + } + }, + "lShoulder": { + "rotation": { + "vector": [25, -5, 0] + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25] + }, + "0.08": { + "vector": [-2, 0, 1.25] + }, + "0.12": { + "vector": [-0.5, 0, 1.25] + }, + "0.16": { + "vector": [0, 0, -0.75] + }, + "0.2": { + "vector": [0, 0, 1.25] + }, + "0.24": { + "vector": [-2, 0, 1.25] + }, + "0.28": { + "vector": [-0.5, 0, 1.25] + }, + "0.32": { + "vector": [0, 0, -0.75] + }, + "0.36": { + "vector": [0, 0, 1.25] + }, + "0.4": { + "vector": [-2, 0, 1.25] + }, + "0.44": { + "vector": [-0.5, 0, 1.25] + }, + "0.48": { + "vector": [0, 0, -0.75] + }, + "0.52": { + "vector": [0, 0, 1.25] + }, + "0.56": { + "vector": [-2, 0, 1.25] + }, + "0.6": { + "vector": [-0.5, 0, 1.25] + }, + "0.64": { + "vector": [0, 0, -0.75] + }, + "0.68": { + "vector": [0, 0, 1.25] + }, + "0.72": { + "vector": [-2, 0, 1.25] + }, + "0.76": { + "vector": [-0.5, 0, 1.25] + }, + "0.8": { + "vector": [0, 0, -0.75] + }, + "0.84": { + "vector": [0, 0, 1.25] + }, + "0.88": { + "vector": [-2, 0, 1.25] + }, + "0.92": { + "vector": [-0.5, 0, 1.25] + }, + "0.96": { + "vector": [0, 0, -0.75] + }, + "1.0": { + "vector": [0, 0, 1.25] + }, + "1.04": { + "vector": [-2, 0, 1.25] + }, + "1.08": { + "vector": [-0.5, 0, 1.25] + }, + "1.12": { + "vector": [0, 0, -0.75] + }, + "1.16": { + "vector": [0, 0, 1.25] + }, + "1.2": { + "vector": [-2, 0, 1.25] + }, + "1.24": { + "vector": [-0.5, 0, 1.25] + }, + "1.28": { + "vector": [0, 0, -0.75] + }, + "1.32": { + "vector": [0, 0, 1.25] + }, + "1.36": { + "vector": [-2, 0, 1.25] + }, + "1.4": { + "vector": [-0.5, 0, 1.25] + }, + "1.44": { + "vector": [0, 0, -0.75] + }, + "1.48": { + "vector": [0, 0, 1.25] + }, + "1.52": { + "vector": [-2, 0, 1.25] + }, + "1.56": { + "vector": [-0.5, 0, 1.25] + }, + "1.6": { + "vector": [0, 0, -0.75] + }, + "1.64": { + "vector": [0, 0, 1.25] + }, + "1.68": { + "vector": [-2, 0, 1.25] + }, + "1.72": { + "vector": [-0.5, 0, 1.25] + }, + "1.76": { + "vector": [0, 0, -0.75] + } + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [-12.48848, 0.54094, 9.94081] + }, + "1.04": { + "vector": [-23.63948, 2.83053, 8.93777] + }, + "1.76": { + "vector": [-12.48848, 0.54094, 9.94081] + } + }, + "position": { + "vector": [0, 1, 0] + } + }, + "lowJaw": { + "position": { + "vector": [0, -2, 0] + } + }, + "rArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, 5] + }, + "0.4": { + "vector": [0, 0, 0] + }, + "0.84": { + "vector": [4.81096, -6.97913, -7.21254] + }, + "1.32": { + "vector": [5.02885, -7.50642, -9.51579] + }, + "1.6": { + "vector": [0, 0, 0] + }, + "1.76": { + "vector": [0, 0, 5] + } + } + }, + "trigger": { + "rotation": { + "0.0": { + "vector": [-10, 0, 0] + }, + "0.56": { + "vector": [-13.5, 0, 0] + }, + "0.76": { + "vector": [-14.82, 0, 0] + }, + "0.88": { + "vector": [-15.57, 0, 0] + }, + "1.12": { + "vector": [-16.75, 0, 0] + }, + "1.28": { + "vector": [-17.75, 0, 0] + }, + "1.76": { + "vector": [-9.75, 0, 0] + } + } + }, + "bone7": { + "rotation": { + "0.0": { + "vector": [-5, 0, 0] + }, + "0.36": { + "vector": [-6.12, 0, 0] + }, + "0.8": { + "vector": [-7.5, 0, 0] + }, + "1.28": { + "vector": [-8.75, 0, 0] + }, + "1.76": { + "vector": [-5, 0, 0] + } + } + }, + "bigGun": { + "rotation": { + "0.0": { + "vector": [0, 0, 0.5] + }, + "0.04": { + "vector": [0, 0, -0.25] + }, + "0.08": { + "vector": [-0.75, 0, -0.25] + }, + "0.12": { + "vector": [0, 0, -0.25] + }, + "0.16": { + "vector": [0, 0, 0.5] + }, + "0.2": { + "vector": [0, 0, -0.25] + }, + "0.24": { + "vector": [-0.75, 0, -0.25] + }, + "0.28": { + "vector": [0, 0, -0.25] + }, + "0.32": { + "vector": [0, 0, 0.5] + }, + "0.36": { + "vector": [0, 0, -0.25] + }, + "0.4": { + "vector": [-0.75, 0, -0.25] + }, + "0.44": { + "vector": [0, 0, -0.25] + }, + "0.48": { + "vector": [0, 0, 0.5] + }, + "0.52": { + "vector": [0, 0, -0.25] + }, + "0.56": { + "vector": [-0.75, 0, -0.25] + }, + "0.6": { + "vector": [0, 0, -0.25] + }, + "0.64": { + "vector": [0, 0, 0.5] + }, + "0.68": { + "vector": [0, 0, -0.25] + }, + "0.72": { + "vector": [-0.75, 0, -0.25] + }, + "0.76": { + "vector": [0, 0, -0.25] + }, + "0.8": { + "vector": [0, 0, 0.5] + }, + "0.84": { + "vector": [0, 0, -0.25] + }, + "0.88": { + "vector": [-0.75, 0, -0.25] + }, + "0.92": { + "vector": [0, 0, -0.25] + }, + "0.96": { + "vector": [0, 0, 0.5] + }, + "1.0": { + "vector": [0, 0, -0.25] + }, + "1.04": { + "vector": [-0.75, 0, -0.25] + }, + "1.08": { + "vector": [0, 0, -0.25] + }, + "1.12": { + "vector": [0, 0, 0.5] + }, + "1.16": { + "vector": [0, 0, -0.25] + }, + "1.2": { + "vector": [-0.75, 0, -0.25] + }, + "1.24": { + "vector": [0, 0, -0.25] + }, + "1.28": { + "vector": [0, 0, 0.5] + }, + "1.32": { + "vector": [0, 0, -0.25] + }, + "1.36": { + "vector": [-0.75, 0, -0.25] + }, + "1.4": { + "vector": [0, 0, -0.25] + }, + "1.44": { + "vector": [0, 0, 0.5] + }, + "1.48": { + "vector": [0, 0, -0.25] + }, + "1.52": { + "vector": [-0.75, 0, -0.25] + }, + "1.56": { + "vector": [0, 0, -0.25] + }, + "1.6": { + "vector": [0, 0, 0.5] + }, + "1.64": { + "vector": [0, 0, -0.25] + }, + "1.68": { + "vector": [-0.75, 0, -0.25] + }, + "1.72": { + "vector": [0, 0, -0.25] + } + } + }, + "propulsion1": { + "rotation": { + "0.0": { + "vector": [60, 0, 0] + }, + "0.6": { + "vector": [17.5, 0, 0] + }, + "0.88": { + "vector": [18.83, 0, 0] + }, + "1.16": { + "vector": [33.75, 0, 0] + }, + "1.48": { + "vector": [51.33, 0, 0] + }, + "1.76": { + "vector": [60, 0, 0] + } + }, + "position": { + "vector": [0, 7, 0] + } + }, + "propulsion2": { + "rotation": { + "0.0": { + "vector": [55, 0, 0] + }, + "0.6": { + "vector": [17.5, 0, 0] + }, + "1.16": { + "vector": [33.75, 0, 0] + }, + "1.76": { + "vector": [55, 0, 0] + } + }, + "position": { + "vector": [0, 7, 0] + } + }, + "propulsion3": { + "rotation": { + "vector": [12.5, 0, 0] + } + }, + "propulsion4": { + "rotation": { + "vector": [15, 0, 0] + } + } + } + }, + "chainsaw": { + "loop": true, + "animation_length": 1.76, + "bones": { + "bone": { + "scale": { + "vector": [0, 0, 0] + } + }, + "base": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.24": { + "vector": [0, -2.5, 0] + }, + "1.76": { + "vector": [0, -22.5, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 5] + }, + "0.24": { + "vector": [0, 2, -9] + }, + "0.8": { + "vector": [0, -3.18, -4.79] + }, + "1.08": { + "vector": [0, -4.27, -1.94] + }, + "1.32": { + "vector": [0, -4.46, 0.51] + }, + "1.52": { + "vector": [0, -2.93, 3.3] + }, + "1.76": { + "vector": [0, 0, 5] + } + } + }, + "body": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.36": { + "vector": [0, 5, 0] + }, + "1.36": { + "vector": [0, -10, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "chest": { + "rotation": { + "0.0": { + "vector": [10, 0, 0] + }, + "0.32": { + "vector": [11.24314, 27.0478, 5.16524] + }, + "1.76": { + "vector": [10, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, -2] + }, + "0.32": { + "vector": [0, 0, -3] + }, + "1.76": { + "vector": [0, 0, -2] + } + } + }, + "head": { + "rotation": { + "0.0": { + "vector": [-5.1972, 17.46065, -360.90906] + }, + "0.32": { + "vector": [-6.23682, -37.30758, -355.55617] + }, + "1.12": { + "vector": [-4.97617, 5.00946, -359.78134] + }, + "1.76": { + "vector": [-5.1972, 17.46065, -360.90906] + } + }, + "position": { + "0.0": { + "vector": [0, 0, -2] + }, + "0.32": { + "vector": [-2, 0, -2] + }, + "1.12": { + "vector": [-1, 0, -2] + }, + "1.76": { + "vector": [0, 0, -2] + } + } + }, + "lowJaw": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.24": { + "vector": [10, 0, 0] + }, + "1.76": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.24": { + "vector": [0, -1, 0] + }, + "1.76": { + "vector": [0, 0, 0] + } + } + }, + "rShoulder": { + "rotation": { + "0.0": { + "vector": [-15, 0, 17.5] + }, + "0.24": { + "vector": [36.54514, -9.06524, 29.5012] + }, + "1.76": { + "vector": [-15, 0, 17.5] + } + } + }, + "rArm2": { + "rotation": { + "vector": [2.5, -15, 0] + }, + "position": { + "vector": [-1, 0, 0] + } + }, + "lShoulder": { + "rotation": { + "0.0": { + "vector": [49.8924, -3.82821, 3.21873] + }, + "0.28": { + "vector": [-40.1076, -3.82821, 3.21873] + }, + "0.68": { + "vector": [-55.6431, 7.13136, -10.29284] + }, + "1.12": { + "vector": [-10.1076, -3.82821, 3.21873] + }, + "1.48": { + "vector": [4.8924, -3.82821, 3.21873] + }, + "1.76": { + "vector": [49.8924, -3.82821, 3.21873] + } + }, + "position": { + "0.28": { + "vector": [0, -2, 1] + }, + "0.68": { + "vector": [0, -4, -2] + }, + "1.12": { + "vector": [0, -2, 1] + }, + "1.48": { + "vector": [0, -2, 1] + } + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.08": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.12": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.16": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "0.2": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.24": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.28": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.32": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "0.36": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.4": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.44": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.48": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "0.52": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.56": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.6": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.64": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "0.68": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.72": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.76": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.8": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "0.84": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "0.88": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "0.92": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "0.96": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "1.0": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "1.04": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "1.08": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "1.12": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "1.16": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "1.2": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "1.24": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "1.28": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "1.32": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "1.36": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "1.4": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "1.44": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "1.48": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "1.52": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "1.56": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "1.6": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + }, + "1.64": { + "vector": [0, 0, 1.25], + "easing": "easeInElastic" + }, + "1.68": { + "vector": [-2, 0, 1.25], + "easing": "easeInElastic" + }, + "1.72": { + "vector": [-0.5, 0, 1.25], + "easing": "easeInElastic" + }, + "1.76": { + "vector": [0, 0, -0.75], + "easing": "easeInElastic" + } + } + }, + "lArm3": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [-20.39807, 11.91276, -3.81397] + }, + "0.16": { + "vector": [28.58219, 14.34511, -8.30016] + }, + "0.88": { + "vector": [-15.19432, 13.43122, -2.91042] + }, + "1.0": { + "vector": [-16.15392, 13.22416, -3.03363] + }, + "1.28": { + "vector": [-10.05966, 12.74101, -3.32112] + }, + "1.36": { + "vector": [-9.28273, 12.60297, -3.40327] + }, + "1.76": { + "vector": [-20.39807, 11.91276, -3.81397] + } + } + }, + "propulsion1": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.16": { + "vector": [-32.5, 0, 0] + }, + "0.88": { + "vector": [32.5, 0, 0] + }, + "1.28": { + "vector": [-5, 0, 0] + }, + "1.76": { + "vector": [22.5, 0, 0] + } + } + }, + "propulsion2": { + "rotation": { + "0.0": { + "vector": [22.5, 0, 0] + }, + "0.16": { + "vector": [-32.5, 0, 0] + }, + "0.88": { + "vector": [32.5, 0, 0] + }, + "1.28": { + "vector": [-5, 0, 0] + }, + "1.76": { + "vector": [22.5, 0, 0] + } + } + }, + "propulsion3": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.28": { + "vector": [22.5, 0, 0] + }, + "0.84": { + "vector": [-32.5, 0, 0] + }, + "1.36": { + "vector": [-35, 0, 0] + }, + "1.76": { + "vector": [-22.5, 0, 0] + } + } + }, + "propulsion4": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.28": { + "vector": [17.5, 0, 0] + }, + "0.84": { + "vector": [-27.5, 0, 0] + }, + "1.36": { + "vector": [-35, 0, 0] + }, + "1.76": { + "vector": [-22.5, 0, 0] + } + } + } + } + }, + "rockets": { + "loop": true, + "animation_length": 1.44, + "bones": { + "base": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [0, -7, 12] + }, + "0.56": { + "vector": [0, -9, 5.75] + }, + "0.92": { + "vector": [0, -8.5, -0.5] + }, + "1.28": { + "vector": [0, -4.36, -2.55] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [15, 0, 0] + }, + "0.32": { + "vector": [20.5, 0, 0] + }, + "0.56": { + "vector": [14.32, 0, 0] + }, + "1.08": { + "vector": [-10.34, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.2": { + "vector": [0, 0, -5] + }, + "1.36": { + "vector": [0, 0, -2.09] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "lMissleLaunch": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.16": { + "vector": [-15, 0, 0] + }, + "0.6": { + "vector": [-3, 0, 0] + }, + "0.72": { + "vector": [0, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 2, -2] + }, + "0.16": { + "vector": [0, -3, 3] + }, + "0.24": { + "vector": [0, -3, 3] + }, + "0.6": { + "vector": [0, 4, -4] + }, + "0.72": { + "vector": [0, 2, -2] + }, + "1.44": { + "vector": [0, 2, -2] + } + } + }, + "rMissleLaunch2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.16": { + "vector": [-15, 0, 0] + }, + "0.6": { + "vector": [-5.5, 0, 0] + }, + "0.72": { + "vector": [0, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 2, -2] + }, + "0.16": { + "vector": [0, -3, 3] + }, + "0.24": { + "vector": [0, -3, 3] + }, + "0.6": { + "vector": [0, 4, -4] + }, + "0.72": { + "vector": [0, 2, -2] + }, + "1.44": { + "vector": [0, 2, -2] + } + } + }, + "neck": { + "rotation": { + "vector": [-12.5, 0, 0] + }, + "position": { + "0.0": { + "vector": [0, -2, 0] + }, + "0.2": { + "vector": [0, -2, 0] + }, + "1.44": { + "vector": [0, -2, 0] + } + } + }, + "head": { + "rotation": { + "0.0": { + "vector": [27.5, 0, 0] + }, + "0.2": { + "vector": [5.7, 0, 0] + }, + "1.2": { + "vector": [30, 0, 0] + }, + "1.44": { + "vector": [27.5, 0, 0] + } + }, + "position": { + "0.2": { + "vector": [0, 1, -2] + }, + "1.2": { + "vector": [0, 1, -2.25] + } + } + }, + "lowJaw": { + "rotation": { + "vector": [10, 0, 0] + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.68": { + "vector": [0, -1, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "rArm2": { + "rotation": { + "vector": [0, 0, -2.5] + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25] + }, + "0.08": { + "vector": [-2, 0, 1.25] + }, + "0.12": { + "vector": [-0.5, 0, 1.25] + }, + "0.16": { + "vector": [0, 0, -0.75] + }, + "0.2": { + "vector": [0, 0, 1.25] + }, + "0.24": { + "vector": [-2, 0, 1.25] + }, + "0.28": { + "vector": [-0.5, 0, 1.25] + }, + "0.32": { + "vector": [0, 0, -0.75] + }, + "0.36": { + "vector": [0, 0, 1.25] + }, + "0.4": { + "vector": [-2, 0, 1.25] + }, + "0.44": { + "vector": [-0.5, 0, 1.25] + }, + "0.48": { + "vector": [0, 0, -0.75] + }, + "0.52": { + "vector": [0, 0, 1.25] + }, + "0.56": { + "vector": [-2, 0, 1.25] + }, + "0.6": { + "vector": [-0.5, 0, 1.25] + }, + "0.64": { + "vector": [0, 0, -0.75] + }, + "0.68": { + "vector": [0, 0, 1.25] + }, + "0.72": { + "vector": [-2, 0, 1.25] + }, + "0.76": { + "vector": [-0.5, 0, 1.25] + }, + "0.8": { + "vector": [0, 0, -0.75] + }, + "0.84": { + "vector": [0, 0, 1.25] + }, + "0.88": { + "vector": [-2, 0, 1.25] + }, + "0.92": { + "vector": [-0.5, 0, 1.25] + }, + "0.96": { + "vector": [0, 0, -0.75] + }, + "1.0": { + "vector": [0, 0, 1.25] + }, + "1.04": { + "vector": [-2, 0, 1.25] + }, + "1.08": { + "vector": [-0.5, 0, 1.25] + }, + "1.12": { + "vector": [0, 0, -0.75] + }, + "1.16": { + "vector": [0, 0, 1.25] + }, + "1.2": { + "vector": [-2, 0, 1.25] + }, + "1.24": { + "vector": [-0.5, 0, 1.25] + }, + "1.28": { + "vector": [0, 0, -0.75] + }, + "1.32": { + "vector": [0, 0, 1.25] + }, + "1.36": { + "vector": [-2, 0, 1.25] + }, + "1.4": { + "vector": [-0.5, 0, 1.25] + }, + "1.44": { + "vector": [0, 0, -0.75] + } + } + }, + "propulsion1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [-20, 0, 0] + }, + "0.4": { + "vector": [-25, 0, 0] + }, + "1.16": { + "vector": [10, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "propulsion2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [-20, 0, 0] + }, + "0.36": { + "vector": [-23.62, 0, 0] + }, + "1.16": { + "vector": [10, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "propulsion3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.24": { + "vector": [-20, 0, 0] + }, + "0.44": { + "vector": [-20, 0, 0] + }, + "0.84": { + "vector": [7.5, 0, 0] + }, + "1.2": { + "vector": [-17.5, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "propulsion4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.24": { + "vector": [-20, 0, 0] + }, + "0.44": { + "vector": [-20, 0, 0] + }, + "0.84": { + "vector": [7.5, 0, 0] + }, + "1.2": { + "vector": [-17.5, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "body": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.2": { + "vector": [0, 0, -5] + }, + "1.36": { + "vector": [0, 0, -2.09] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "chest": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.24": { + "vector": [20, 0, 0] + }, + "0.48": { + "vector": [-20.31, 0, 0] + }, + "1.44": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.24": { + "vector": [0, 0, -5] + }, + "0.48": { + "vector": [0, -4, 0.63] + }, + "1.44": { + "vector": [0, 0, 0] + } + } + }, + "rShoulder": { + "rotation": { + "0.0": { + "vector": [20, 0, 25] + }, + "0.24": { + "vector": [-12.33756, -10.68806, 28.14783] + }, + "0.52": { + "vector": [24.25098, 26.17588, 16.14687] + }, + "1.44": { + "vector": [20, 0, 25] + } + } + }, + "lShoulder": { + "rotation": { + "0.0": { + "vector": [15, 0, 0] + }, + "0.24": { + "vector": [-35.6484, 10.21235, -7.24677] + }, + "0.52": { + "vector": [5.50884, -14.30659, -1.44989] + }, + "1.44": { + "vector": [15, 0, 0] + } + } + } + } + }, + "death": { + "animation_length": 2.2, + "bones": { + "lowJaw": { + "rotation": { + "vector": [12.5, 0, 0] + }, + "position": { + "vector": [0, -0.9, 0.32] + } + }, + "body": { + "rotation": { + "1.12": { + "vector": [0, 0, 0] + }, + "1.44": { + "vector": [14.78, 0, 0] + }, + "1.56": { + "vector": [38.02, 0, 0] + }, + "1.6": { + "vector": [64.79, 0, 0] + }, + "1.64": { + "vector": [82.5, 0, 0] + } + }, + "position": { + "0.08": { + "vector": [0, -6.08, -9.31] + }, + "0.2": { + "vector": [0, -3.96, -11.5] + }, + "0.96": { + "vector": [0, 15.7, -17.08] + }, + "1.12": { + "vector": [0, -15.24, -21.15] + }, + "1.44": { + "vector": [0, -15.24, -21.15] + }, + "2.0": { + "vector": [0, -20, -46] + }, + "2.2": { + "vector": [0, -20, -46] + } + }, + "scale": { + "1.12": { + "vector": [1, 1, 1] + }, + "2.0": { + "vector": [1, 1, 1] + }, + "2.2": { + "vector": [0, 0.1, 0] + } + } + }, + "chest": { + "rotation": { + "0.36": { + "vector": [-7.5, 0, 0] + }, + "1.36": { + "vector": [-19.38, 0, 0] + }, + "1.64": { + "vector": [-10, 0, 0] + } + }, + "position": { + "0.36": { + "vector": [0, 0, 1] + }, + "1.36": { + "vector": [0, -3, 2.75] + }, + "1.64": { + "vector": [0, 0, 1] + } + } + }, + "head": { + "rotation": { + "0.96": { + "vector": [-25, 0, 0] + }, + "1.28": { + "vector": [-20.00075, 38.2555, -12.70047] + }, + "1.36": { + "vector": [-29.39567, 39.06543, -13.38968] + }, + "1.72": { + "vector": [-25.01852, 44.68059, -18.16791] + }, + "1.84": { + "vector": [16.38795, 47.80879, 37.05489] + } + }, + "position": { + "vector": [0, -3, -1] + } + }, + "rShoulder": { + "rotation": { + "0.48": { + "vector": [0, 32.5, 0] + }, + "0.96": { + "vector": [0, 32.5, 0] + }, + "1.32": { + "vector": [-4.375, 20, 0] + }, + "1.64": { + "vector": [40.30522, 0.78366, 14.98913] + }, + "1.72": { + "vector": [19.44478, -1.35296, 14.23226] + } + } + }, + "rArm1": { + "rotation": { + "vector": [20, 0, 0] + } + }, + "rArm2": { + "rotation": { + "0.24": { + "vector": [30, 0, 0] + }, + "0.72": { + "vector": [-5, 0, 0] + }, + "0.96": { + "vector": [-5, 0, 0] + }, + "1.16": { + "vector": [10, 0, 0] + } + } + }, + "lShoulder": { + "rotation": { + "0.32": { + "vector": [-87.5, 0, 0] + }, + "0.96": { + "vector": [-87.5, 0, 0] + }, + "1.32": { + "vector": [2.5, 0, 0] + }, + "1.64": { + "vector": [67.5, 0, 0] + }, + "1.72": { + "vector": [50, 0, 0] + } + }, + "position": { + "0.32": { + "vector": [0, -8, 3] + }, + "0.96": { + "vector": [0, -8, 3] + }, + "1.32": { + "vector": [0, -1, -2] + } + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [-2, 0, 1.25] + }, + "0.04": { + "vector": [-0.5, 0, 1.25] + }, + "0.08": { + "vector": [0, 0, -0.75] + }, + "0.12": { + "vector": [0, 0, 1.25] + }, + "0.16": { + "vector": [-2, 0, 1.25] + }, + "0.2": { + "vector": [-0.5, 0, 1.25] + }, + "0.24": { + "vector": [0, 0, -0.75] + }, + "0.28": { + "vector": [0, 0, 1.25] + }, + "0.32": { + "vector": [-2, 0, 1.25] + }, + "0.36": { + "vector": [-0.5, 0, 1.25] + }, + "0.4": { + "vector": [0, 0, -0.75] + }, + "0.44": { + "vector": [0, 0, 1.25] + }, + "0.48": { + "vector": [-2, 0, 1.25] + }, + "0.52": { + "vector": [-0.5, 0, 1.25] + }, + "0.56": { + "vector": [0, 0, -0.75] + }, + "0.6": { + "vector": [0, 0, 1.25] + }, + "0.64": { + "vector": [-2, 0, 1.25] + }, + "0.68": { + "vector": [-0.5, 0, 1.25] + }, + "0.72": { + "vector": [0, 0, -0.75] + }, + "0.76": { + "vector": [0, 0, 1.25] + }, + "0.8": { + "vector": [-2, 0, 1.25] + }, + "0.84": { + "vector": [-0.5, 0, 1.25] + }, + "0.88": { + "vector": [0, 0, -0.75] + } + } + }, + "sled": { + "rotation": { + "vector": [180, 0, 0] + }, + "position": { + "vector": [0, 0, 52] + }, + "scale": { + "vector": [0, 0, 1] + } + } + } + }, + "sled_death": { + "animation_length": 0.52, + "bones": { + "lowJaw": { + "rotation": { + "vector": [0, 0, 0] + }, + "position": { + "vector": [0, 0.1, 0.325] + } + }, + "body": { + "rotation": { + "vector": [0, 0, 0] + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.12": { + "vector": [0, 16, -0.19] + }, + "0.24": { + "vector": [0, 12.69, -2.49] + }, + "0.32": { + "vector": [0, 5.86, -5.09] + }, + "0.52": { + "vector": [0, -3.85, -6.93] + } + }, + "scale": { + "vector": [1, 1, 1] + } + }, + "chest": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.32": { + "vector": [12.5, 0, 0] + } + }, + "position": { + "vector": [0, 0, -3] + } + }, + "head": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.4": { + "vector": [17.5, 0, 0] + } + }, + "position": { + "vector": [0, 0, -1] + } + }, + "rShoulder": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "rArm1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.28": { + "vector": [7.5, 0, 0] + } + } + }, + "rArm2": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "lShoulder": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.32": { + "vector": [15, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -1, 3] + }, + "0.32": { + "vector": [0, -1.55, 3] + } + } + }, + "lArm2": { + "rotation": { + "0.0": { + "vector": [0, 0, -0.75] + }, + "0.04": { + "vector": [0, 0, 1.25] + }, + "0.08": { + "vector": [-2, 0, 1.25] + }, + "0.12": { + "vector": [-0.5, 0, 1.25] + }, + "0.16": { + "vector": [0, 0, -0.75] + }, + "0.2": { + "vector": [0, 0, 1.25] + }, + "0.24": { + "vector": [-2, 0, 1.25] + }, + "0.28": { + "vector": [-0.5, 0, 1.25] + }, + "0.32": { + "vector": [0, 0, -0.75] + }, + "0.36": { + "vector": [0, 0, 1.25] + }, + "0.4": { + "vector": [-2, 0, 1.25] + }, + "0.44": { + "vector": [-0.5, 0, 1.25] + }, + "0.48": { + "vector": [0, 0, -0.75] + }, + "0.52": { + "vector": [0, 0, 1.25] + } + } + }, + "sled": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.16": { + "vector": [45, 0, 0] + }, + "0.28": { + "vector": [90, 0, 0] + }, + "0.48": { + "vector": [135, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.16": { + "vector": [0, 5.86, 9.77] + }, + "0.28": { + "vector": [0, 10, 26] + }, + "0.48": { + "vector": [0, 6.26, 40.01] + } + }, + "scale": { + "0.0": { + "vector": [1, 1, 1] + }, + "0.28": { + "vector": [1, 1, 1] + } + } + } + } + } + }, + "azurelib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/animations/entity/marauder.animation.json b/common/src/main/resources/assets/azurelib/animations/entity/marauder.animation.json new file mode 100644 index 000000000..94ee538c4 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/entity/marauder.animation.json @@ -0,0 +1,6262 @@ +{ + "format_version": "1.8.0", + "animations": { + "idle": { + "loop": true, + "animation_length": 2, + "bones": { + "torso": { + "rotation": { + "vector": [0, 22.5, 0] + } + }, + "right_arm": { + "rotation": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0.5, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.2": { + "vector": [-2.83, 0, 0] + }, + "0.8": { + "vector": [-7.17, 0, 0] + }, + "1.0": { + "vector": [-7.5, 0, 0] + }, + "1.2": { + "vector": [-7.17, 0, 0] + }, + "1.8": { + "vector": [-2.83, 0, 0] + }, + "2.0": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, -1.5] + }, + "0.2": { + "vector": [0, -0.25, -1.5] + }, + "0.8": { + "vector": [0, -0.25, -1.5] + }, + "1.0": { + "vector": [0, -0.25, -1.5] + }, + "1.2": { + "vector": [0, -0.25, -1.5] + }, + "1.8": { + "vector": [0, -0.25, -1.5] + }, + "2.0": { + "vector": [0, -0.25, -1.5] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.2": { + "vector": [5.67, 0, 0] + }, + "0.8": { + "vector": [14.33, 0, 0] + }, + "1.0": { + "vector": [15, 0, 0] + }, + "1.2": { + "vector": [14.33, 0, 0] + }, + "1.8": { + "vector": [5.67, 0, 0] + }, + "2.0": { + "vector": [5, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.2": { + "vector": [-2.83, 0, 0] + }, + "0.8": { + "vector": [-7.17, 0, 0] + }, + "1.0": { + "vector": [-7.5, 0, 0] + }, + "1.2": { + "vector": [-7.17, 0, 0] + }, + "1.8": { + "vector": [-2.83, 0, 0] + }, + "2.0": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0.5] + }, + "0.2": { + "vector": [0, -0.25, 0.5] + }, + "0.8": { + "vector": [0, -0.25, 0.5] + }, + "1.0": { + "vector": [0, -0.25, 0.5] + }, + "1.2": { + "vector": [0, -0.25, 0.5] + }, + "1.8": { + "vector": [0, -0.25, 0.5] + }, + "2.0": { + "vector": [0, -0.25, 0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.2": { + "vector": [5.67, 0, 0] + }, + "0.8": { + "vector": [14.33, 0, 0] + }, + "1.0": { + "vector": [15, 0, 0] + }, + "1.2": { + "vector": [14.33, 0, 0] + }, + "1.8": { + "vector": [5.67, 0, 0] + }, + "2.0": { + "vector": [5, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "vector": [0, -22.5, 0] + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0.25, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, -0.5, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_attack": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [1, 1, 1] + } + } + } + }, + "walk": { + "loop": true, + "animation_length": 2, + "bones": { + "torso": { + "rotation": { + "vector": [0, 22.5, 0] + }, + "position": { + "0.0": { + "vector": [-0.25, 0, 0] + }, + "0.3": { + "vector": [-0.33, 0, 0] + }, + "1.0": { + "vector": [0.25, 0, 0] + }, + "1.3": { + "vector": [0.33, 0, 0] + }, + "2.0": { + "vector": [-0.25, 0, 0] + } + } + }, + "upper_torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 1] + }, + "0.3": { + "vector": [0, 0, 1.5] + }, + "1.0": { + "vector": [0, 0, -1] + }, + "1.3": { + "vector": [0, 0, -1.5] + }, + "2.0": { + "vector": [0, 0, 1] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, -0.17, 0] + }, + "0.2": { + "vector": [0, -0.83, 0] + }, + "0.3": { + "vector": [0, -1, 0] + }, + "0.45": { + "vector": [0, -0.93, 0] + }, + "0.85": { + "vector": [0, -0.07, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.1": { + "vector": [0, -0.17, 0] + }, + "1.2": { + "vector": [0, -0.83, 0] + }, + "1.3": { + "vector": [0, -1, 0] + }, + "1.45": { + "vector": [0, -0.93, 0] + }, + "1.85": { + "vector": [0, -0.07, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.3": { + "vector": [37.94, 29.52, 9.71] + }, + "1.0": { + "vector": [37.1047, 28.17926, 12.12078] + }, + "1.3": { + "vector": [36.1047, 28.17926, 12.12078] + }, + "2.0": { + "vector": [36.94319, 29.52361, 9.71415] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, 0.17, 0] + }, + "0.2": { + "vector": [0, 0.83, 0] + }, + "0.3": { + "vector": [0, 1, 0] + }, + "0.45": { + "vector": [0, 0.93, 0] + }, + "0.85": { + "vector": [0, 0.07, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.1": { + "vector": [0, 0.17, 0] + }, + "1.2": { + "vector": [0, 0.83, 0] + }, + "1.3": { + "vector": [0, 1, 0] + }, + "1.45": { + "vector": [0, 0.93, 0] + }, + "1.85": { + "vector": [0, 0.07, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [12.5, 0, 0] + }, + "0.55": { + "vector": [-10, 0, 0] + }, + "1.0": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "2.0": { + "vector": [12.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.5, -1] + }, + "0.15": { + "vector": [0, 1, -2] + }, + "0.55": { + "vector": [0, 1, -2] + }, + "1.0": { + "vector": [0, -1, -2.5] + }, + "2.0": { + "vector": [0, -0.5, -1] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [32.5, 0, 0] + }, + "1.0": { + "vector": [5, 0, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "1.0": { + "vector": [12.5, 0, 0] + }, + "1.55": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "2.0": { + "vector": [-9.96271, -0.86717, -4.92442] + } + }, + "position": { + "0.0": { + "vector": [0, -1, -0.5] + }, + "1.0": { + "vector": [0, -0.5, 1] + }, + "1.15": { + "vector": [0, 1, 0] + }, + "1.55": { + "vector": [0, 1, 0] + }, + "2.0": { + "vector": [0, -1, -0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + }, + "1.3": { + "vector": [32.5, 0, 0] + }, + "2.0": { + "vector": [5, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, -22.5, -1] + }, + "0.3": { + "vector": [0, -22.5, -1.5] + }, + "1.0": { + "vector": [0, -22.5, 1] + }, + "1.3": { + "vector": [0, -22.5, 1.5] + }, + "2.0": { + "vector": [0, -22.5, -1] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_attack": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.95": { + "effect": "walk" + }, + "1.95": { + "effect": "walk" + } + } + }, + "run": { + "loop": true, + "animation_length": 0.5, + "bones": { + "torso": { + "rotation": { + "vector": [25, 0, 0] + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [-47.41709, -12.48859, 0.54146] + }, + "0.1": { + "vector": [-16.79911, -16.90142, 4.98561] + }, + "0.25": { + "vector": [39.3969, -19.7052, 3.8848] + }, + "0.5": { + "vector": [-47.41709, -12.48859, 0.54146] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [-27.5, 0, 0] + }, + "0.5": { + "vector": [-27.5, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [39.3969, 19.7052, -3.8848] + }, + "0.25": { + "vector": [-47.41709, 12.4886, -0.5415] + }, + "0.35": { + "vector": [-16.79911, 16.9014, -4.9856] + }, + "0.5": { + "vector": [39.3969, 19.7052, -3.8848] + } + } + }, + "right_elbow": { + "rotation": { + "0.0": { + "vector": [-27.5, 0, 0] + }, + "0.5": { + "vector": [-27.5, 0, 0] + } + } + }, + "axe": { + "rotation": { + "vector": [-45, -45, 0] + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [48.84318, 11.0235, -2.4076] + }, + "0.25": { + "vector": [-47.31623, 14.328, 1.6962] + }, + "0.35": { + "vector": [-16.25675, 7.3218, 2.8407] + }, + "0.5": { + "vector": [48.84318, 11.0235, -2.4076] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, -1, -2] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [41.96457, 0, 0] + }, + "0.1": { + "vector": [22.01779, 0, 0] + }, + "0.25": { + "vector": [10.44841, 0, 0] + }, + "0.5": { + "vector": [41.96457, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-47.31623, -14.32798, -1.69619] + }, + "0.1": { + "vector": [-16.25675, -7.32179, -2.84073] + }, + "0.25": { + "vector": [48.84318, -11.02346, 2.40756] + }, + "0.5": { + "vector": [-47.31623, -14.32798, -1.69619] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, -1, -2] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [10.44841, 0, 0] + }, + "0.25": { + "vector": [41.96457, 0, 0] + }, + "0.35": { + "vector": [22.01779, 0, 0] + }, + "0.5": { + "vector": [10.44841, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "vector": [-15, 0, 0] + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, -2, 0] + }, + "0.2": { + "vector": [0, 1.5, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, -2, 0] + }, + "0.45": { + "vector": [0, 1.5, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_attack": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.05": { + "effect": "walk" + }, + "0.15": { + "effect": "walk" + }, + "0.3": { + "effect": "walk" + }, + "0.4": { + "effect": "walk" + } + } + }, + "energy_slash": { + "animation_length": 1, + "bones": { + "torso": { + "rotation": { + "0.0": { + "vector": [0, 22.5, 0] + }, + "0.25": { + "vector": [-22.45376, 4.88119, 1.08482], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [20.15711, -30.42471, 3.15289], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [0, 22.5, 0], + "easing": "easeInOutQuad" + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2": { + "vector": [0, 0.05, 0] + }, + "0.25": { + "vector": [0, 0.8, 0] + }, + "0.4": { + "vector": [0, 0.95, 0] + }, + "0.5": { + "vector": [0, 0.95, 0] + }, + "0.65": { + "vector": [0, 0.8, 0] + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-42.73421, -15.69986, -38.82495], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [-25.00772, 13.4395, -26.99582], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-45, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [-22.5, 0, 0], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.25": { + "vector": [-170.91589, -12.68945, -29.87236], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [-50.77424, 27.00637, -42.94328], + "easing": "easeInOutQuad" + }, + "0.5": { + "vector": [-21.42177, 17.7925, -31.36258], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [36.94319, 29.52361, 9.71415], + "easing": "easeInOutQuad" + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "axe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-45, -45, 15], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [22.5, -45, 15], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.25": { + "vector": [-56.86218, 2.34352, -12.28179] + }, + "0.4": { + "vector": [-32.5, 0, 0] + }, + "0.5": { + "vector": [-32.5, 0, 0] + }, + "1.0": { + "vector": [-2.5, 0, 0], + "easing": "easeInOutQuad" + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, -1.5] + }, + "1.0": { + "vector": [0, -0.25, -1.5], + "easing": "easeInOutQuad" + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.25": { + "vector": [45, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [45, 0, 0], + "easing": "easeInOutQuad" + }, + "0.5": { + "vector": [45, 0, 0], + "easing": "easeInOutQuad" + }, + "1.0": { + "vector": [5, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.25": { + "vector": [10.4943, -0.822, -2.71827] + }, + "0.4": { + "vector": [37.5, 0, 0] + }, + "0.5": { + "vector": [37.5, 0, 0] + }, + "1.0": { + "vector": [-2.5, 0, 0], + "easing": "easeInOutQuad" + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0.5] + }, + "1.0": { + "vector": [0, -0.25, 0.5], + "easing": "easeInOutQuad" + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "1.0": { + "vector": [5, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "h_slash": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 4, -8] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + }, + "scale": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.35": { + "vector": [1, 1, 1], + "easing": "easeInOutQuad" + } + } + }, + "h_slash2": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash3": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash4": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash5": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash6": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash7": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash8": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash9": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_slash10": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + }, + "0.4": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, -47], + "easing": "easeInOutQuad" + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.25": { + "vector": [33.77048, -5.99032, 2.66499] + }, + "0.4": { + "vector": [-5.12161, 25.82329, -2.83601] + }, + "0.5": { + "vector": [-5.12161, 25.82329, -2.83601] + }, + "0.75": { + "vector": [-0.75543, 4.97912, -2.45465] + }, + "1.0": { + "vector": [0, -22.5, 0], + "easing": "easeInOutQuad" + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.15": { + "vector": [0, -1, 2] + }, + "0.3": { + "vector": [0, -1, 2] + }, + "0.4": { + "vector": [0, -4, -8] + }, + "1.0": { + "vector": [0, 0, 0], + "easing": "easeInOutQuad" + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.35": { + "effect": "slash" + } + } + }, + "hook": { + "animation_length": 1, + "bones": { + "torso": { + "rotation": { + "0.0": { + "vector": [0, 22.5, 0] + }, + "0.35": { + "vector": [0, -45, 0] + }, + "0.5": { + "vector": [30, 45, 0] + }, + "0.6": { + "vector": [63.10819, 71.24264, 36.51548] + }, + "1.0": { + "vector": [0, 22.5, 0] + } + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.4": { + "vector": [62.65725, 6.55676, -77.51703] + }, + "0.5": { + "vector": [-67.34275, 6.55676, -77.51703] + }, + "0.6": { + "vector": [-104.84275, 6.55676, -77.51703] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-60, 0, 0] + }, + "0.4": { + "vector": [-91.5, 0, 0] + }, + "0.5": { + "vector": [-37.5, 0, 0] + }, + "0.6": { + "vector": [-30.5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.35": { + "vector": [42.52426, 19.88275, 12.4118] + }, + "0.4": { + "vector": [42.52426, 19.88275, 12.4118] + }, + "0.45": { + "vector": [10.82416, 8.65125, 9.70546] + }, + "0.5": { + "vector": [-5.0275, -2.11363, 18.00718] + }, + "0.6": { + "vector": [-14.10919, -0.72303, 17.14132] + }, + "1.0": { + "vector": [36.94319, 29.52361, 9.71415] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [1, 0, 1] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "right_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [22.5, 0, 0] + }, + "0.35": { + "vector": [22.5, 0, 0] + }, + "0.4": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [7.5, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.4": { + "vector": [-7.5, 0, 0] + }, + "0.5": { + "vector": [-2.5, 0, 0] + }, + "1.0": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, -1.5] + }, + "0.5": { + "vector": [0, -0.25, -1.5] + }, + "1.0": { + "vector": [0, -0.25, -1.5] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.4": { + "vector": [12.5, 0, 0] + }, + "0.5": { + "vector": [5, 0, 0] + }, + "1.0": { + "vector": [5, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.4": { + "vector": [-7.5, 0, 0] + }, + "0.5": { + "vector": [-2.5, 0, 0] + }, + "1.0": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0.5] + }, + "0.5": { + "vector": [0, -0.25, -1.5] + }, + "1.0": { + "vector": [0, -0.25, 0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.4": { + "vector": [12.5, 0, 0] + }, + "0.5": { + "vector": [5, 0, 0] + }, + "1.0": { + "vector": [5, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.25": { + "vector": [18.81517, 32.16683, 2.79164] + }, + "0.3": { + "vector": [17.23042, 35.45167, 3.72115] + }, + "0.35": { + "vector": [15.61275, 38.78143, 4.50441] + }, + "0.4": { + "vector": [1.82829, 15.09442, -2.58693] + }, + "0.5": { + "vector": [-3.83528, -41.13981, 7.84775] + }, + "0.6": { + "vector": [-20.07884, -63.15509, 26.26946] + }, + "0.8": { + "vector": [-0.62387, -43.76225, -0.56045] + }, + "1.0": { + "vector": [0, -22.5, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.45": { + "effect": "axe_hit" + } + } + }, + "shoot": { + "animation_length": 1.25, + "bones": { + "torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, 3.75, 0] + }, + "0.2": { + "vector": [0, 18.75, 0] + }, + "0.3": { + "vector": [0, 22.5, 0] + }, + "0.55": { + "vector": [0, 22.5, 0] + }, + "0.75": { + "vector": [0, 22.5, 0] + }, + "0.85": { + "vector": [0, 20.89, 0] + }, + "1.15": { + "vector": [0, 1.61, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "upper_torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, 3.75, 0] + }, + "0.2": { + "vector": [0, 18.75, 0] + }, + "0.3": { + "vector": [0, 22.5, 0] + }, + "0.55": { + "vector": [0, 22.5, 0] + }, + "0.65": { + "vector": [-3.53092, 22.36846, -2.70099] + }, + "0.75": { + "vector": [-3.53, 22.37, -2.7] + }, + "0.85": { + "vector": [-3.28, 20.77, -2.51] + }, + "1.15": { + "vector": [-0.25, 1.6, -0.19] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.65": { + "vector": [0, 0, 1] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.85": { + "vector": [0, 0, 0] + }, + "1.15": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [-10.25, -7.3, 2.45] + }, + "0.2": { + "vector": [-51.27, -36.49, 12.26] + }, + "0.3": { + "vector": [-61.52003, -43.79162, 14.71526] + }, + "0.55": { + "vector": [-61.52003, -43.79162, 14.71526] + }, + "0.65": { + "vector": [-106.52003, -43.79162, 14.71526] + }, + "0.75": { + "vector": [-106.52, -43.79, 14.72] + }, + "0.85": { + "vector": [-98.91, -40.66, 13.67] + }, + "1.15": { + "vector": [-7.61, -3.13, 1.05] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.55": { + "vector": [0, 0, 0] + }, + "0.65": { + "vector": [0, 0, 1] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "0.85": { + "vector": [0, 0, 0] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.65": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [-22.5, 0, 0] + }, + "0.85": { + "vector": [-20.89, 0, 0] + }, + "1.15": { + "vector": [-1.61, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.1": { + "vector": [32.45, 24.6, 8.1] + }, + "0.2": { + "vector": [14.49, 4.92, 1.62] + }, + "0.3": { + "vector": [10, 0, 0] + }, + "0.75": { + "vector": [10, 0, 0] + }, + "0.85": { + "vector": [11.68, 1.85, 0.61] + }, + "1.15": { + "vector": [35.26, 27.68, 9.11] + }, + "1.25": { + "vector": [36.94319, 29.52361, 9.71415] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0.83, -7.5, 0] + }, + "0.2": { + "vector": [4.17, -37.5, 0] + }, + "0.3": { + "vector": [5, -45, 0] + }, + "0.4": { + "vector": [5, -45, 0] + }, + "0.75": { + "vector": [5, -45, 0] + }, + "0.85": { + "vector": [4.64, -41.79, 0] + }, + "1.15": { + "vector": [0.2, -1.77, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.65": { + "vector": [-2.5, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.65": { + "vector": [0, 0, 0.7] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.45": { + "effect": "attack" + } + } + }, + "axe_attack": { + "animation_length": 1.25, + "override_previous_animation": true, + "bones": { + "torso": { + "rotation": { + "0.0": { + "vector": [0, 22.5, 0] + }, + "0.3": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [0, 19.42, 0] + }, + "0.8": { + "vector": [0, -15.24, 0] + }, + "1.25": { + "vector": [0, 22.5, 0] + } + } + }, + "upper_torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [0, 45, 0] + }, + "0.5": { + "vector": [0, 45, 0] + }, + "0.55": { + "vector": [0, -7.5, 0] + }, + "0.6": { + "vector": [0, 16.15, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [-15.50853, 9.3733, -19.69937] + }, + "0.5": { + "vector": [-15.50853, 9.3733, -19.69937] + }, + "0.6": { + "vector": [20.14197, 18.45386, -44.18719] + }, + "0.9": { + "vector": [21.31475, -5.36143, -32.73013] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [-67.5, 0, 0] + }, + "0.5": { + "vector": [-67.5, 0, 0] + }, + "0.6": { + "vector": [-17.31, 0, 0] + }, + "0.9": { + "vector": [-17.31, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.3": { + "vector": [-109.70372, -34.12145, 43.97409] + }, + "0.5": { + "vector": [-121.22829, -24.29511, 67.25777] + }, + "0.55": { + "vector": [-102.45958, -14.42399, 77.57976] + }, + "0.6": { + "vector": [-29.07197, -13.47349, 60.63172] + }, + "0.7": { + "vector": [37.73643, -0.99934, 60.90401] + }, + "0.8": { + "vector": [52.73643, -0.99934, 60.90401] + }, + "1.25": { + "vector": [36.94319, 29.52361, 9.71415] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [2, -1, -1] + }, + "0.5": { + "vector": [2, -1, -1] + }, + "0.6": { + "vector": [2, 0, 0] + }, + "0.7": { + "vector": [2, 0, 0] + }, + "0.8": { + "vector": [2, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "right_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "axe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [27.44634, -46.77638, 1.64566] + }, + "0.2": { + "vector": [12.8954, -72.37008, -0.60389] + }, + "0.3": { + "vector": [-1.09992, -78.07078, 2.27213] + }, + "0.5": { + "vector": [-19.66347, -69.27795, 32.98256] + }, + "0.55": { + "vector": [-26.9171, -41.80641, 26.33413] + }, + "0.6": { + "vector": [-26.9171, -41.80641, 26.33413] + }, + "0.7": { + "vector": [-4.4171, -41.80641, 26.33413] + }, + "0.75": { + "vector": [18.0829, -41.80641, 26.33413] + }, + "0.8": { + "vector": [40.32194, -42.2031, 21.34306] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.15": { + "vector": [0.8, -0.8, -2] + }, + "0.3": { + "vector": [0, 0, -1] + }, + "0.5": { + "vector": [0, 0, -1] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + }, + "0.7": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.3": { + "vector": [-2.5, 0, 0] + }, + "0.5": { + "vector": [-2.5, 0, 0] + }, + "0.55": { + "vector": [-2.5, 0, 0] + }, + "0.6": { + "vector": [-18.7289, 36.8678, 1.46479] + }, + "0.65": { + "vector": [-39.75355, 33.51618, 1.33163] + }, + "1.25": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, -1.5] + }, + "0.3": { + "vector": [0, -0.25, -1.5] + }, + "0.5": { + "vector": [0, -0.25, -1.5] + }, + "0.55": { + "vector": [0, -0.25, -1.5] + }, + "1.25": { + "vector": [0, -0.25, -1.5] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.3": { + "vector": [5, 0, 0] + }, + "0.45": { + "vector": [5, 0, 0] + }, + "0.55": { + "vector": [5, 0, 0] + }, + "0.6": { + "vector": [27.5, 0, 0] + }, + "0.65": { + "vector": [47.95, 0, 0] + }, + "1.25": { + "vector": [5, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.3": { + "vector": [-2.5, 0, 0] + }, + "0.45": { + "vector": [-21.38885, 10.86362, 32.59688] + }, + "0.55": { + "vector": [-20.35186, 1.51634, 36.30248] + }, + "0.6": { + "vector": [27.22998, 57.15097, 37.99251] + }, + "1.25": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0.5] + }, + "0.3": { + "vector": [0, -0.25, 0.5] + }, + "0.45": { + "vector": [0, -0.25, 0.5] + }, + "0.55": { + "vector": [0, -0.25, 0.5] + }, + "1.25": { + "vector": [0, -0.25, 0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.3": { + "vector": [5, 0, 0] + }, + "0.45": { + "vector": [72.5, 0, 0] + }, + "0.55": { + "vector": [72.5, 0, 0] + }, + "0.6": { + "vector": [27.5, 0, 0] + }, + "1.25": { + "vector": [5, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.3": { + "vector": [0, 72.5, 0] + }, + "0.5": { + "vector": [0, 72.5, 0] + }, + "0.55": { + "vector": [0, 45, 0] + }, + "0.6": { + "vector": [0, 22.5, 0] + }, + "0.65": { + "vector": [0, 22.92, 0] + }, + "1.25": { + "vector": [0, -22.5, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.15": { + "vector": [0, 75, 0] + }, + "0.3": { + "vector": [0, 100, 0] + }, + "0.5": { + "vector": [0, 220.04517, 0] + }, + "0.6": { + "vector": [0, 310.04517, 0] + }, + "0.65": { + "vector": [0, 310.04517, 0] + }, + "0.85": { + "vector": [0, 360, 0] + }, + "1.25": { + "vector": [0, 360, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [1, -1, 4] + }, + "0.4": { + "vector": [4.5, -1, 1] + }, + "0.45": { + "vector": [4.25, -1, -2.5] + }, + "0.5": { + "vector": [3, -1, -4] + }, + "0.55": { + "vector": [0, 0, -4] + }, + "0.65": { + "vector": [0, -4, -8] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.25": { + "effect": "axe_hit" + } + } + }, + "axe_cut": { + "animation_length": 1.35, + "bones": { + "torso": { + "rotation": { + "0.0": { + "vector": [0, 22.5, 0] + }, + "0.3": { + "vector": [-12.5, 0, 0] + }, + "0.5": { + "vector": [0, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [56.82632, 6.94314, -0.0723] + }, + "0.75": { + "vector": [56.82632, 6.94314, -0.0723] + }, + "1.25": { + "vector": [0, 22.5, 0] + } + } + }, + "upper_torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [0, 55, 0] + }, + "0.5": { + "vector": [0, 45, 0] + }, + "0.55": { + "vector": [0, 42, 0] + }, + "0.6": { + "vector": [0, -21, 0] + }, + "0.75": { + "vector": [0, -21, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "vector": [0, 0, 0] + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0, 0, 0] + }, + "0.2": { + "vector": [-36.54219, -33.28982, -69.7671] + }, + "0.4": { + "vector": [-15.2553, -34.46461, -98.06686] + }, + "0.5": { + "vector": [-33.95742, -37.02514, -80.39611] + }, + "0.55": { + "vector": [-40.69539, -21.98867, -73.87325] + }, + "0.6": { + "vector": [-97.19705, 30.96904, -59.43905] + }, + "0.75": { + "vector": [-97.19705, 30.96904, -59.43905] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.3": { + "vector": [-45, 0, 0] + }, + "0.5": { + "vector": [-45, 0, 0] + }, + "0.6": { + "vector": [-34.81, 0, 0] + }, + "0.75": { + "vector": [-34.81, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "0.2": { + "vector": [-145.20556, -13.66588, 31.66413] + }, + "0.35": { + "vector": [-145.20556, -13.66588, 31.66413] + }, + "0.5": { + "vector": [-143.03203, -20.66768, 33.50612] + }, + "0.55": { + "vector": [-134.1591, -38.7886, 10.07665] + }, + "0.6": { + "vector": [-84.25071, -6.85667, -9.50735] + }, + "0.75": { + "vector": [-84.25071, -6.85667, -9.50735] + }, + "1.25": { + "vector": [36.94319, 29.52361, 9.71415] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2": { + "vector": [1, 3, -1] + }, + "0.5": { + "vector": [2, 3, -2] + }, + "0.6": { + "vector": [2, 0, 0] + }, + "0.7": { + "vector": [2, 0, 0] + }, + "0.8": { + "vector": [2, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "right_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.2": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [-12.5, 0, 0] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.75": { + "vector": [0, 0, 0] + }, + "1.2": { + "vector": [0, 0, 0] + } + } + }, + "axe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.05": { + "vector": [-17.55366, -46.77638, 1.64566] + }, + "0.15": { + "vector": [-31.37378, -33.42989, -4.98105] + }, + "0.2": { + "vector": [-44.19581, -3.0647, 48.97981] + }, + "0.35": { + "vector": [-44.12388, 1.93476, 49.08245] + }, + "0.5": { + "vector": [-46.88452, -10.32122, 51.03982] + }, + "0.55": { + "vector": [-57.65366, -23.33192, 27.23873] + }, + "0.6": { + "vector": [16.98134, -43.05147, 42.21258] + }, + "1.25": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.1": { + "vector": [0.8, -0.8, -2] + }, + "0.2": { + "vector": [0, 0, -1] + }, + "0.5": { + "vector": [0, 0, -1] + }, + "0.55": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.3": { + "vector": [-2.5, 0, 0] + }, + "0.55": { + "vector": [12.5, 0, 0] + }, + "0.6": { + "vector": [12.5, 0, 0] + }, + "0.65": { + "vector": [12.5, 0, 0] + }, + "0.7": { + "vector": [12.5, 0, 0] + }, + "0.75": { + "vector": [12.5, 0, 0] + }, + "1.25": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, -1.5] + }, + "0.3": { + "vector": [0, -0.25, -1.5] + }, + "0.6": { + "vector": [0, -0.25, -1.5] + }, + "0.65": { + "vector": [0, -0.25, -1.5] + }, + "1.25": { + "vector": [0, -0.25, -1.5] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.3": { + "vector": [5, 0, 0] + }, + "0.55": { + "vector": [15, 0, 0] + }, + "0.65": { + "vector": [15, 0, 0] + }, + "0.7": { + "vector": [15, 0, 0] + }, + "0.75": { + "vector": [15, 0, 0] + }, + "1.25": { + "vector": [5, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [-2.5, 0, 0] + }, + "0.15": { + "vector": [-47.5, 0, 0] + }, + "0.4": { + "vector": [-47.5, 0, 0] + }, + "0.5": { + "vector": [-27.06, 0, 0] + }, + "1.25": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, -0.25, 0.5] + }, + "0.15": { + "vector": [0, -0.25, 0.5] + }, + "0.4": { + "vector": [0, -0.25, 0.5] + }, + "1.25": { + "vector": [0, -0.25, 0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [5, 0, 0] + }, + "0.15": { + "vector": [27.5, 0, 0] + }, + "0.4": { + "vector": [27.5, 0, 0] + }, + "0.5": { + "vector": [17.5, 0, 0] + }, + "0.65": { + "vector": [31.03, 0, 0] + }, + "1.25": { + "vector": [5, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, -22.5, 0] + }, + "0.3": { + "vector": [5.24771, -55.29505, 5.70142] + }, + "0.5": { + "vector": [4.24777, -45.32881, 6.99588] + }, + "0.55": { + "vector": [2.01385, -45.16677, 0.61212] + }, + "0.6": { + "vector": [-31.34904, 12.54752, 4.35778] + }, + "0.75": { + "vector": [-37.83777, 14.32159, 7.88953] + }, + "1.25": { + "vector": [0, -22.5, 0] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash10": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.4": { + "vector": [0, 0, -1] + }, + "0.5": { + "vector": [0, -2, -7] + }, + "0.55": { + "vector": [0, -2, -9.5] + }, + "0.6": { + "vector": [0, -2, -10] + }, + "0.65": { + "vector": [0, -2, -11] + }, + "0.75": { + "vector": [0, -2, -11] + }, + "1.25": { + "vector": [0, 0, 0] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_normal": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.6": { + "effect": "axe_hit" + } + } + }, + "death": { + "animation_length": 10, + "bones": { + "right_heel": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-12.5, 0, 0] + }, + "0.35": { + "vector": [17.5, 0, 0] + } + } + }, + "right_foot": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-33.13773, 0.2136, -1.9553] + }, + "0.35": { + "vector": [27.10718, 0.299, -2.7374] + }, + "0.6": { + "vector": [72.10718, 0.299, -2.7374] + } + } + }, + "left_heel": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-12.5, 0, 0] + }, + "0.35": { + "vector": [17.5, 0, 0] + } + } + }, + "left_foot": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-33.13773, -0.21358, 1.95528] + }, + "0.35": { + "vector": [27.10718, -0.29901, 2.73739] + }, + "0.6": { + "vector": [72.10718, -0.29901, 2.73739] + } + } + }, + "torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-35, 0, 0] + }, + "0.35": { + "vector": [-45, 0, 0] + }, + "0.45": { + "vector": [-45, 0, 0] + }, + "0.6": { + "vector": [22.5, 0, 0] + } + } + }, + "left_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [-99.28275, -76.00637, 13.97749] + }, + "0.5": { + "vector": [-99.28275, -76.00637, 13.97749] + }, + "0.7": { + "vector": [-99.28275, -76.00637, 13.97749] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0] + } + } + }, + "left_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-2.5, 0, 0] + }, + "0.35": { + "vector": [12.5, 0, 0] + }, + "0.5": { + "vector": [17.5, 0, 0] + }, + "0.6": { + "vector": [17.5, 0, 0] + }, + "0.7": { + "vector": [17.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [-0.75, 0, 0] + }, + "0.5": { + "vector": [-0.75, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [-166.3778, 49.43206, -84.18841] + }, + "0.5": { + "vector": [-166.3778, 49.43206, -84.18841] + }, + "0.7": { + "vector": [-166.3778, 49.43206, -84.18841] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 0, 0] + } + } + }, + "right_elbow": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-2.5, 0, 0] + }, + "0.35": { + "vector": [12.5, 0, 0] + }, + "0.5": { + "vector": [17.5, 0, 0] + }, + "0.6": { + "vector": [17.5, 0, 0] + }, + "0.7": { + "vector": [17.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0.75, 0, 0] + }, + "0.5": { + "vector": [0.75, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + } + } + }, + "axe": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.6": { + "vector": [-112.2725, 1.95838, -155.96286] + }, + "0.7": { + "vector": [-111.16188, -2.34128, -158.55673] + } + }, + "position": { + "0.6": { + "vector": [0, 0, 0] + }, + "0.7": { + "vector": [2.75, -16, -4.25] + }, + "0.75": { + "vector": [4.75, -18, -6.25] + } + } + }, + "left_leg": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, 7.5, 0] + }, + "0.6": { + "vector": [25, 7.5, 0] + } + } + }, + "left_knee": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [72.86, 0, 0] + }, + "0.35": { + "vector": [42.5, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [0, -7.5, 0] + }, + "0.6": { + "vector": [25, -7.5, 0] + } + } + }, + "right_knee": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [72.86, 0, 0] + }, + "0.35": { + "vector": [42.5, 0, 0] + }, + "0.6": { + "vector": [0, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 0, 0] + }, + "0.4": { + "vector": [-22.5, 0, 0] + }, + "0.6": { + "vector": [-37.5, 0, 0] + }, + "0.75": { + "vector": [-12.5, 0, 0] + } + } + }, + "inactive_axe": { + "scale": { + "vector": [0, 0, 0] + } + }, + "leg_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [-7.5, 0, 0] + }, + "0.35": { + "vector": [27.5, 0, 0] + }, + "0.45": { + "vector": [65, 0, 0] + }, + "0.7": { + "vector": [65, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -8.5, -6] + }, + "0.35": { + "vector": [0, -10, -10] + }, + "0.45": { + "vector": [0, -19, -14] + } + } + }, + "dreadnought_portal": { + "scale": { + "vector": [0, 0, 0] + } + }, + "eyes_attack": { + "scale": { + "vector": [0, 0, 0] + } + } + } + }, + "spawn": { + "animation_length": 14.35, + "override_previous_animation": true, + "bones": { + "dreadnought": { + "position": { + "0.0": { + "vector": [0, 0, 90] + }, + "0.3": { + "vector": [0, 0, 90] + }, + "0.35": { + "vector": [0, 0, 80] + }, + "2.35": { + "vector": [0, 0, 64] + }, + "10.35": { + "vector": [0, 0, 32] + }, + "14.35": { + "vector": [0, 0, 0] + } + }, + "scale": { + "0.3": { + "vector": [0, 0, 0] + }, + "0.35": { + "vector": [1, 1, 1] + } + } + }, + "torso": { + "rotation": { + "0.35": { + "vector": [0, 0, 0] + }, + "9.35": { + "vector": [0, 0, 0] + }, + "10.35": { + "vector": [0, 22.5, 0] + }, + "12.35": { + "vector": [0, 22.5, 0] + }, + "14.35": { + "vector": [0, 22.5, 0] + } + }, + "position": { + "0.35": { + "vector": [-0.25, 0, 0] + }, + "0.8": { + "vector": [-0.33, 0, 0] + }, + "1.6": { + "vector": [0.25, 0, 0] + }, + "2.05": { + "vector": [0.33, 0, 0] + }, + "2.85": { + "vector": [-0.25, 0, 0] + }, + "3.3": { + "vector": [-0.33, 0, 0] + }, + "4.1": { + "vector": [0.25, 0, 0] + }, + "4.55": { + "vector": [0.33, 0, 0] + }, + "5.35": { + "vector": [-0.25, 0, 0] + }, + "5.8": { + "vector": [-0.33, 0, 0] + }, + "6.6": { + "vector": [0.25, 0, 0] + }, + "7.05": { + "vector": [0.33, 0, 0] + }, + "7.85": { + "vector": [-0.25, 0, 0] + }, + "8.3": { + "vector": [-0.33, 0, 0] + }, + "9.1": { + "vector": [0.25, 0, 0] + }, + "9.55": { + "vector": [0.33, 0, 0] + }, + "10.35": { + "vector": [-0.25, 0, 0] + }, + "10.65": { + "vector": [-0.33, 0, 0] + }, + "11.35": { + "vector": [0.25, 0, 0] + }, + "11.65": { + "vector": [0.33, 0, 0] + }, + "12.35": { + "vector": [-0.25, 0, 0] + }, + "12.65": { + "vector": [-0.33, 0, 0] + }, + "13.35": { + "vector": [0.25, 0, 0] + }, + "13.65": { + "vector": [0.33, 0, 0] + }, + "14.35": { + "vector": [0, 0, 0] + } + } + }, + "upper_torso": { + "rotation": { + "0.35": { + "vector": [0, 0, 1] + }, + "0.8": { + "vector": [0, 0, 2.5] + }, + "1.6": { + "vector": [0, 0, -1] + }, + "2.05": { + "vector": [0, 0, -2.5] + }, + "2.85": { + "vector": [0, 0, 1] + }, + "3.3": { + "vector": [0, 0, 2.5] + }, + "4.1": { + "vector": [0, 0, -1] + }, + "4.55": { + "vector": [0, 0, -2.5] + }, + "5.35": { + "vector": [0, 0, 1] + }, + "5.8": { + "vector": [0, 0, 2.5] + }, + "6.6": { + "vector": [0, 0, -1] + }, + "7.05": { + "vector": [0, 0, -2.5] + }, + "7.85": { + "vector": [0, 0, 1] + }, + "8.3": { + "vector": [0, 0, 2.5] + }, + "9.1": { + "vector": [0, 0, -1] + }, + "9.55": { + "vector": [0, 0, -2.5] + }, + "10.35": { + "vector": [0, 0, 1] + }, + "10.65": { + "vector": [0, 0, 2.5] + }, + "11.35": { + "vector": [0, 0, -1] + }, + "11.65": { + "vector": [0, 0, -2.5] + }, + "12.35": { + "vector": [0, 0, 1] + }, + "12.65": { + "vector": [0, 0, 2.5] + }, + "13.35": { + "vector": [0, 0, -1] + }, + "13.65": { + "vector": [0, 0, -2.5] + }, + "14.35": { + "vector": [0, 0, 0] + } + }, + "position": { + "0.35": { + "vector": [0, 0, 0] + }, + "0.5": { + "vector": [0, -0.17, 0] + }, + "0.65": { + "vector": [0, -0.83, 0] + }, + "0.8": { + "vector": [0, -1, 0] + }, + "0.95": { + "vector": [0, -0.93, 0] + }, + "1.4": { + "vector": [0, -0.07, 0] + }, + "1.6": { + "vector": [0, 0, 0] + }, + "1.75": { + "vector": [0, -0.17, 0] + }, + "1.9": { + "vector": [0, -0.83, 0] + }, + "2.05": { + "vector": [0, -1, 0] + }, + "2.2": { + "vector": [0, -0.93, 0] + }, + "2.7": { + "vector": [0, -0.07, 0] + }, + "2.85": { + "vector": [0, 0, 0] + }, + "3.0": { + "vector": [0, -0.17, 0] + }, + "3.15": { + "vector": [0, -0.83, 0] + }, + "3.3": { + "vector": [0, -1, 0] + }, + "3.45": { + "vector": [0, -0.93, 0] + }, + "3.9": { + "vector": [0, -0.07, 0] + }, + "4.1": { + "vector": [0, 0, 0] + }, + "4.25": { + "vector": [0, -0.17, 0] + }, + "4.4": { + "vector": [0, -0.83, 0] + }, + "4.55": { + "vector": [0, -1, 0] + }, + "4.7": { + "vector": [0, -0.93, 0] + }, + "5.2": { + "vector": [0, -0.07, 0] + }, + "5.35": { + "vector": [0, 0, 0] + }, + "5.5": { + "vector": [0, -0.17, 0] + }, + "5.65": { + "vector": [0, -0.83, 0] + }, + "5.8": { + "vector": [0, -1, 0] + }, + "5.95": { + "vector": [0, -0.93, 0] + }, + "6.4": { + "vector": [0, -0.07, 0] + }, + "6.6": { + "vector": [0, 0, 0] + }, + "6.75": { + "vector": [0, -0.17, 0] + }, + "6.9": { + "vector": [0, -0.83, 0] + }, + "7.05": { + "vector": [0, -1, 0] + }, + "7.2": { + "vector": [0, -0.93, 0] + }, + "7.7": { + "vector": [0, -0.07, 0] + }, + "7.85": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -0.17, 0] + }, + "8.15": { + "vector": [0, -0.83, 0] + }, + "8.3": { + "vector": [0, -1, 0] + }, + "8.45": { + "vector": [0, -0.93, 0] + }, + "8.9": { + "vector": [0, -0.07, 0] + }, + "9.1": { + "vector": [0, 0, 0] + }, + "9.25": { + "vector": [0, -0.17, 0] + }, + "9.4": { + "vector": [0, -0.83, 0] + }, + "9.55": { + "vector": [0, -1, 0] + }, + "9.7": { + "vector": [0, -0.93, 0] + }, + "10.2": { + "vector": [0, -0.07, 0] + }, + "10.35": { + "vector": [0, 0, 0] + }, + "10.45": { + "vector": [0, -0.17, 0] + }, + "10.55": { + "vector": [0, -0.83, 0] + }, + "10.65": { + "vector": [0, -1, 0] + }, + "10.8": { + "vector": [0, -0.93, 0] + }, + "11.2": { + "vector": [0, -0.07, 0] + }, + "11.35": { + "vector": [0, 0, 0] + }, + "11.45": { + "vector": [0, -0.17, 0] + }, + "11.55": { + "vector": [0, -0.83, 0] + }, + "11.65": { + "vector": [0, -1, 0] + }, + "11.8": { + "vector": [0, -0.93, 0] + }, + "12.2": { + "vector": [0, -0.07, 0] + }, + "12.35": { + "vector": [0, 0, 0] + }, + "12.45": { + "vector": [0, -0.17, 0] + }, + "12.55": { + "vector": [0, -0.83, 0] + }, + "12.65": { + "vector": [0, -1, 0] + }, + "12.8": { + "vector": [0, -0.93, 0] + }, + "13.2": { + "vector": [0, -0.07, 0] + }, + "13.35": { + "vector": [0, 0, 0] + }, + "13.45": { + "vector": [0, -0.17, 0] + }, + "13.55": { + "vector": [0, -0.83, 0] + }, + "13.65": { + "vector": [0, -1, 0] + }, + "13.8": { + "vector": [0, -0.93, 0] + }, + "14.2": { + "vector": [0, -0.07, 0] + }, + "14.35": { + "vector": [0, 0, 0] + } + } + }, + "left_arm": { + "rotation": { + "0.35": { + "vector": [-65.3438, 2.97085, -54.00316] + }, + "1.35": { + "vector": [-65.3438, 2.97085, -54.00316] + }, + "2.1": { + "vector": [-19.29063, 7.22373, -42.19927] + }, + "2.6": { + "vector": [13.14, 0.83582, -11.7567] + }, + "3.45": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "5.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "6.6": { + "vector": [12.5, 0, 0] + }, + "7.4": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "7.85": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "9.1": { + "vector": [12.5, 0, 0] + }, + "9.9": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "10.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "14.35": { + "vector": [0, 0, 0] + } + } + }, + "right_arm": { + "rotation": { + "0.35": { + "vector": [12.68664, -9.76061, -2.18558] + }, + "2.85": { + "vector": [12.68664, -9.76061, -2.18558] + }, + "3.55": { + "vector": [-10.15108, -9.84655, 1.75378] + }, + "4.1": { + "vector": [-10.08648, -8.98092, 6.66735] + }, + "5.35": { + "vector": [12.68664, -9.76061, -2.18558] + }, + "6.05": { + "vector": [-10.15108, -9.84655, 1.75378] + }, + "6.6": { + "vector": [-10.08648, -8.98092, 6.66735] + }, + "7.85": { + "vector": [12.68664, -9.76061, -2.18558] + }, + "8.2": { + "vector": [37.68664, -9.76061, -2.18558] + }, + "8.35": { + "vector": [20.18664, -9.76061, -2.18558] + }, + "9.35": { + "vector": [25.0691, 18.40276, 1.7084] + }, + "10.35": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "10.65": { + "vector": [37.94, 29.52, 9.71] + }, + "11.35": { + "vector": [37.1047, 28.17926, 12.12078] + }, + "11.65": { + "vector": [36.1047, 28.17926, 12.12078] + }, + "12.35": { + "vector": [36.94319, 29.52361, 9.71415] + }, + "12.65": { + "vector": [37.94, 29.52, 9.71] + }, + "13.35": { + "vector": [37.1047, 28.17926, 12.12078] + }, + "13.65": { + "vector": [36.1047, 28.17926, 12.12078] + }, + "14.35": { + "vector": [36.94319, 29.52361, 9.71415] + } + }, + "position": { + "7.85": { + "vector": [0, 0, 0] + }, + "8.2": { + "vector": [0, 1, 1] + }, + "8.35": { + "vector": [-1, -1, -1] + }, + "9.35": { + "vector": [0, 0, 0] + }, + "10.35": { + "vector": [0, 0, 0] + }, + "10.45": { + "vector": [0, 0.17, 0] + }, + "10.55": { + "vector": [0, 0.83, 0] + }, + "10.65": { + "vector": [0, 1, 0] + }, + "10.8": { + "vector": [0, 0.93, 0] + }, + "11.2": { + "vector": [0, 0.07, 0] + }, + "11.35": { + "vector": [0, 0, 0] + }, + "11.45": { + "vector": [0, 0.17, 0] + }, + "11.55": { + "vector": [0, 0.83, 0] + }, + "11.65": { + "vector": [0, 1, 0] + }, + "11.8": { + "vector": [0, 0.93, 0] + }, + "12.2": { + "vector": [0, 0.07, 0] + }, + "12.35": { + "vector": [0, 0, 0] + }, + "12.45": { + "vector": [0, 0.17, 0] + }, + "12.55": { + "vector": [0, 0.83, 0] + }, + "12.65": { + "vector": [0, 1, 0] + }, + "12.8": { + "vector": [0, 0.93, 0] + }, + "13.2": { + "vector": [0, 0.07, 0] + }, + "13.35": { + "vector": [0, 0, 0] + }, + "13.45": { + "vector": [0, 0.17, 0] + }, + "13.55": { + "vector": [0, 0.83, 0] + }, + "13.65": { + "vector": [0, 1, 0] + }, + "13.8": { + "vector": [0, 0.93, 0] + }, + "14.2": { + "vector": [0, 0.07, 0] + }, + "14.35": { + "vector": [0, 0, 0] + } + } + }, + "right_elbow": { + "rotation": { + "0.35": { + "vector": [22.5, 0, 0] + }, + "2.85": { + "vector": [22.5, 0, 0] + }, + "5.35": { + "vector": [22.5, 0, 0] + }, + "7.85": { + "vector": [22.5, 0, 0] + }, + "8.1": { + "vector": [-2.5, 0, 0] + }, + "8.25": { + "vector": [-2.5, 0, 0] + }, + "8.4": { + "vector": [2.5, 0, 0] + }, + "9.35": { + "vector": [22.5, 0, 0] + }, + "10.35": { + "vector": [0, 0, 0] + } + } + }, + "axe": { + "rotation": { + "8.4": { + "vector": [-17.76543, -17.59014, -11.04134] + }, + "8.45": { + "vector": [-17.76543, -17.59014, -11.04134] + }, + "8.85": { + "vector": [-17.76543, -17.59014, -11.04134] + }, + "9.35": { + "vector": [-26.84362, -11.72676, -7.36089] + }, + "10.35": { + "vector": [0, 0, 0] + } + }, + "position": { + "8.35": { + "vector": [0.75, 3, 3] + }, + "8.4": { + "vector": [0.75, 3, 3] + }, + "8.45": { + "vector": [0.75, 3, 3] + }, + "8.85": { + "vector": [0.75, 3, 3] + }, + "10.35": { + "vector": [0, 0, 0] + } + }, + "scale": { + "8.35": { + "vector": [0, 0, 0] + }, + "8.4": { + "vector": [1, 1, 1] + } + } + }, + "left_leg": { + "rotation": { + "0.35": { + "vector": [5, 0, 0] + }, + "1.05": { + "vector": [-10, 0, 0] + }, + "1.6": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "2.85": { + "vector": [5, 0, 0] + }, + "3.55": { + "vector": [-10, 0, 0] + }, + "4.1": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "5.35": { + "vector": [5, 0, 0] + }, + "6.05": { + "vector": [-10, 0, 0] + }, + "6.6": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "7.85": { + "vector": [5, 0, 0] + }, + "8.55": { + "vector": [-10, 0, 0] + }, + "9.1": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "10.35": { + "vector": [12.5, 0, 0] + }, + "10.9": { + "vector": [-10, 0, 0] + }, + "11.35": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "12.35": { + "vector": [12.5, 0, 0] + }, + "12.9": { + "vector": [-10, 0, 0] + }, + "13.35": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "14.35": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.35": { + "vector": [0, -0.5, -1] + }, + "1.05": { + "vector": [0, 0, -2] + }, + "1.6": { + "vector": [0, -1, -2.5] + }, + "2.85": { + "vector": [0, -0.5, -1] + }, + "3.55": { + "vector": [0, 0, -2] + }, + "4.1": { + "vector": [0, -1, -2.5] + }, + "5.35": { + "vector": [0, -0.5, -1] + }, + "6.05": { + "vector": [0, 0, -2] + }, + "6.6": { + "vector": [0, -1, -2.5] + }, + "7.85": { + "vector": [0, -0.5, -1] + }, + "8.55": { + "vector": [0, 0, -2] + }, + "9.1": { + "vector": [0, -1, -2.5] + }, + "10.35": { + "vector": [0, -0.5, -1] + }, + "10.5": { + "vector": [0, 1, -2] + }, + "10.9": { + "vector": [0, 1, -2] + }, + "11.35": { + "vector": [0, -1, -2.5] + }, + "12.35": { + "vector": [0, -0.5, -1] + }, + "12.5": { + "vector": [0, 1, -2] + }, + "12.9": { + "vector": [0, 1, -2] + }, + "13.35": { + "vector": [0, -1, -2.5] + }, + "14.35": { + "vector": [0, -0.25, -1.5] + } + } + }, + "left_knee": { + "rotation": { + "0.35": { + "vector": [0, 0, 0] + }, + "0.8": { + "vector": [32.5, 0, 0] + }, + "1.6": { + "vector": [5, 0, 0] + }, + "2.85": { + "vector": [0, 0, 0] + }, + "3.3": { + "vector": [32.5, 0, 0] + }, + "4.1": { + "vector": [5, 0, 0] + }, + "5.35": { + "vector": [0, 0, 0] + }, + "5.8": { + "vector": [32.5, 0, 0] + }, + "6.6": { + "vector": [5, 0, 0] + }, + "7.85": { + "vector": [0, 0, 0] + }, + "8.3": { + "vector": [32.5, 0, 0] + }, + "9.1": { + "vector": [5, 0, 0] + }, + "10.35": { + "vector": [0, 0, 0] + }, + "10.65": { + "vector": [32.5, 0, 0] + }, + "11.35": { + "vector": [5, 0, 0] + }, + "12.35": { + "vector": [0, 0, 0] + }, + "12.65": { + "vector": [32.5, 0, 0] + }, + "13.35": { + "vector": [5, 0, 0] + }, + "14.35": { + "vector": [5, 0, 0] + } + } + }, + "right_leg": { + "rotation": { + "0.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "1.6": { + "vector": [5, 0, 0] + }, + "2.4": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "2.85": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "4.1": { + "vector": [5, 0, 0] + }, + "4.9": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "5.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "6.6": { + "vector": [5, 0, 0] + }, + "7.4": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "7.85": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "9.1": { + "vector": [5, 0, 0] + }, + "9.9": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "10.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "11.35": { + "vector": [12.5, 0, 0] + }, + "11.9": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "12.35": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "13.35": { + "vector": [12.5, 0, 0] + }, + "13.9": { + "vector": [-9.96271, -0.86717, -4.92442] + }, + "14.35": { + "vector": [-2.5, 0, 0] + } + }, + "position": { + "0.35": { + "vector": [0, -1, -0.5] + }, + "1.6": { + "vector": [0, -0.5, 1] + }, + "2.4": { + "vector": [0, 0, 0] + }, + "2.85": { + "vector": [0, -1, -0.5] + }, + "4.1": { + "vector": [0, -0.5, 1] + }, + "4.9": { + "vector": [0, 0, 0] + }, + "5.35": { + "vector": [0, -1, -0.5] + }, + "6.6": { + "vector": [0, -0.5, 1] + }, + "7.4": { + "vector": [0, 0, 0] + }, + "7.85": { + "vector": [0, -1, -0.5] + }, + "9.1": { + "vector": [0, -0.5, 1] + }, + "9.9": { + "vector": [0, 0, 0] + }, + "10.35": { + "vector": [0, -1, -0.5] + }, + "11.35": { + "vector": [0, -0.5, 1] + }, + "11.5": { + "vector": [0, 1, 0] + }, + "11.9": { + "vector": [0, 1, 0] + }, + "12.35": { + "vector": [0, -1, -0.5] + }, + "13.35": { + "vector": [0, -0.5, 1] + }, + "13.5": { + "vector": [0, 1, 0] + }, + "13.9": { + "vector": [0, 1, 0] + }, + "14.35": { + "vector": [0, -0.25, 0.5] + } + } + }, + "right_knee": { + "rotation": { + "0.35": { + "vector": [5, 0, 0] + }, + "1.6": { + "vector": [0, 0, 0] + }, + "2.05": { + "vector": [32.5, 0, 0] + }, + "2.85": { + "vector": [5, 0, 0] + }, + "4.1": { + "vector": [0, 0, 0] + }, + "4.55": { + "vector": [32.5, 0, 0] + }, + "5.35": { + "vector": [5, 0, 0] + }, + "6.6": { + "vector": [0, 0, 0] + }, + "7.05": { + "vector": [32.5, 0, 0] + }, + "7.85": { + "vector": [5, 0, 0] + }, + "9.1": { + "vector": [0, 0, 0] + }, + "9.55": { + "vector": [32.5, 0, 0] + }, + "10.35": { + "vector": [5, 0, 0] + }, + "11.35": { + "vector": [0, 0, 0] + }, + "11.65": { + "vector": [32.5, 0, 0] + }, + "12.35": { + "vector": [5, 0, 0] + }, + "13.35": { + "vector": [0, 0, 0] + }, + "13.65": { + "vector": [32.5, 0, 0] + }, + "14.35": { + "vector": [5, 0, 0] + } + } + }, + "inactive_axe": { + "rotation": { + "0.35": { + "vector": [2.51565, -47.38422, -0.7522] + }, + "2.85": { + "vector": [-32.48435, -47.38422, -0.7522] + }, + "3.55": { + "vector": [-17.48435, -47.38422, -0.7522] + }, + "4.1": { + "vector": [-19.98435, -47.38422, -0.7522] + }, + "5.35": { + "vector": [-32.48435, -47.38422, -0.7522] + }, + "6.05": { + "vector": [-17.48435, -47.38422, -0.7522] + }, + "6.6": { + "vector": [-19.98435, -47.38422, -0.7522] + }, + "7.85": { + "vector": [-17.76543, -17.59014, -11.04134] + }, + "8.15": { + "vector": [-17.76543, -17.59014, -11.04134] + }, + "8.35": { + "vector": [-17.76543, -17.59014, -11.04134] + } + }, + "position": { + "0.35": { + "vector": [0, 7, 7] + }, + "2.85": { + "vector": [0, 1, 4] + }, + "3.55": { + "vector": [0, 2, 4] + }, + "4.1": { + "vector": [0, 1, 4] + }, + "5.35": { + "vector": [0, 1, 4] + }, + "6.05": { + "vector": [-1, 2.75, 4] + }, + "6.6": { + "vector": [-1, 2, 4] + }, + "7.85": { + "vector": [0.75, 3, 3] + }, + "8.15": { + "vector": [0.75, 3, 3] + }, + "8.35": { + "vector": [0.75, 3, 3] + }, + "8.4": { + "vector": [0, -3200, 4] + } + }, + "scale": { + "0.0": { + "vector": [1, 1, 1] + }, + "8.35": { + "vector": [1, 1, 1] + }, + "8.45": { + "vector": [0, 0, 0] + } + } + }, + "h_head_furious": { + "rotation": { + "0.35": { + "vector": [0, 0, -1] + }, + "0.8": { + "vector": [15, 0, 1] + }, + "1.6": { + "vector": [15, 0, 1] + }, + "2.85": { + "vector": [0, 0, -1] + }, + "3.3": { + "vector": [0, 0, -2.5] + }, + "4.1": { + "vector": [0, 0, 1] + }, + "4.55": { + "vector": [0, 0, 2.5] + }, + "5.35": { + "vector": [0, 0, -1] + }, + "5.8": { + "vector": [0, 0, -2.5] + }, + "6.6": { + "vector": [0, 0, 1] + }, + "7.05": { + "vector": [0, 0, 2.5] + }, + "7.85": { + "vector": [0, 0, -1] + }, + "8.3": { + "vector": [0, 0, -2.5] + }, + "9.1": { + "vector": [0, 0, 1] + }, + "9.55": { + "vector": [0, 0, 2.5] + }, + "10.35": { + "vector": [0, -22.5, -1] + }, + "10.65": { + "vector": [0, -22.5, -2.5] + }, + "11.35": { + "vector": [0, -22.5, 1] + }, + "11.65": { + "vector": [0, -22.5, 2.5] + }, + "12.35": { + "vector": [0, -22.5, -1] + }, + "12.65": { + "vector": [0, -22.5, -2.5] + }, + "13.35": { + "vector": [0, -22.5, 1] + }, + "13.65": { + "vector": [0, -22.5, 2.5] + }, + "14.35": { + "vector": [0, -22.5, 0] + } + }, + "position": { + "0.35": { + "vector": [0, 0, 0] + }, + "1.35": { + "vector": [0, 0, -2] + }, + "1.75": { + "vector": [0, 0, -2] + }, + "2.05": { + "vector": [0, 0, 0] + }, + "14.35": { + "vector": [0, 0, 0] + } + } + }, + "hand_boomstick": { + "scale": { + "vector": [0, 0, 0] + } + }, + "h_slash": { + "scale": { + "vector": [0, 0, 0] + } + }, + "body2": { + "position": { + "vector": [0, 0, 0] + } + }, + "dreadnought_portal": { + "position": { + "0.0": { + "vector": [0, 0, 69] + }, + "7.85": { + "vector": [0, 0, 69] + }, + "8.0": { + "vector": [0, 25, 69] + } + }, + "scale": { + "7.85": { + "vector": [1, 1, 1] + }, + "8.1": { + "vector": [0, 0, 0] + } + } + }, + "black": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cluster1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud5": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud6": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud7": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud8": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud9": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud10": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud11": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud12": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud13": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud14": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud15": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud16": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud17": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud18": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster5": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud19": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud20": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud21": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud22": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster6": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud23": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud24": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud25": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud26": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud27": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster7": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud28": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud29": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud30": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud31": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster8": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud32": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud33": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud34": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud35": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud36": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster9": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud37": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud38": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud39": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud40": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster10": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud41": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud42": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud43": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud44": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud45": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster11": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud46": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud47": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud48": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud49": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster12": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud50": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud51": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud52": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud53": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud54": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster13": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud55": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud56": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud57": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud58": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster14": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud59": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud60": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud61": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud62": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud63": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster15": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud64": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud65": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud66": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud67": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster16": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud68": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud69": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud70": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud71": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud72": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster17": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud73": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud74": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud75": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud76": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster18": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud77": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud78": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud79": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud80": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud81": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster19": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud82": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud83": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud84": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud85": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster20": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud86": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud87": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud88": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud89": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud90": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster21": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud91": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud92": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud93": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud94": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster22": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud95": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud96": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud97": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud98": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud99": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster23": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud100": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud101": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud102": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud103": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster24": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud104": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud105": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud106": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud107": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud108": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster25": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud109": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud110": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud111": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud112": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster26": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud113": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud114": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud115": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud116": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud117": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster27": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud118": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud119": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud120": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud121": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster28": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud122": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud123": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud124": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud125": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud126": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster29": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud127": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud128": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud129": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud130": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster30": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud131": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud132": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud133": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud134": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud135": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cluster31": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud136": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 360, 0] + } + } + }, + "cloud137": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud138": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 960, 0] + } + } + }, + "cloud139": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 2880, 0] + } + } + }, + "cluster32": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 0, -360] + } + } + }, + "cloud140": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -2880, 0] + } + } + }, + "cloud141": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud142": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, 1440, 0] + } + } + }, + "cloud143": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "cloud144": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "8.0": { + "vector": [0, -1440, 0] + } + } + }, + "eyes_attack": { + "scale": { + "vector": [0, 0, 0] + } + } + }, + "sound_effects": { + "0.0": { + "effect": "portal" + }, + "0.35": { + "effect": "walk" + }, + "1.7": { + "effect": "walk" + }, + "2.85": { + "effect": "walk" + }, + "4.05": { + "effect": "walk" + }, + "4.3": { + "effect": "portal" + }, + "5.25": { + "effect": "walk" + }, + "6.5": { + "effect": "walk" + }, + "7.85": { + "effect": "walk" + }, + "8.35": { + "effect": "axe" + }, + "9.05": { + "effect": "walk" + }, + "10.3": { + "effect": "walk" + }, + "11.2": { + "effect": "walk" + }, + "12.25": { + "effect": "walk" + }, + "13.25": { + "effect": "walk" + }, + "14.0": { + "effect": "walk" + } + } + } + }, + "azurelib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/animations/entity/ovamorph.animation.json b/common/src/main/resources/assets/azurelib/animations/entity/ovamorph.animation.json new file mode 100644 index 000000000..e150f120c --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/entity/ovamorph.animation.json @@ -0,0 +1,136 @@ +{ + "format_version": "1.8.0", + "animations": { + "animation.eggopen": { + "loop": "hold_on_last_frame", + "animation_length": 1, + "bones": { + "gPetal1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [-35, 0, 0] + } + } + }, + "gPetalTop1": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [-107.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -0.09, -0.2] + }, + "1.0": { + "vector": [0, -0.36672, -0.3911] + } + } + }, + "gPetal2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [-35, 0, 0] + } + } + }, + "gPetalTop2": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [-107.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -0.09, -0.2] + }, + "1.0": { + "vector": [0, -0.36672, -0.3911] + } + } + }, + "gPetal3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [-35, 0, 0] + } + } + }, + "gPetalTop3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [-107.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -0.09, -0.2] + }, + "1.0": { + "vector": [0, -0.36672, -0.3911] + } + } + }, + "gPetal4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [-35, 0, 0] + } + } + }, + "gPetalTop4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [-107.5, 0, 0] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -0.09, -0.2] + }, + "1.0": { + "vector": [0, -0.36672, -0.3911] + } + } + } + } + } + }, + "azurelib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/animations/item/doomicorn.animation.json b/common/src/main/resources/assets/azurelib/animations/item/doomicorn.animation.json new file mode 100644 index 000000000..c7d87a8e1 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/item/doomicorn.animation.json @@ -0,0 +1,741 @@ +{ + "format_version": "1.8.0", + "animations": { + "equipping": { + "loop": true, + "animation_length": 1.84, + "bones": { + "bipedHead": { + "rotation": { + "0.0": { + "vector": [ + -90, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + -78.65, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + 0, + 10, + 15.03 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + }, + "bipedBody": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + 0, + 359, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + 0, + 10, + 15.03 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + }, + "bipedRightArm": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + 0, + 359, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + -15, + 10, + -1.97 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + }, + "bipedLeftArm": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + 0, + 359, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + 15, + 10, + -1.97 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + }, + "bipedRightLeg": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + 0, + 359, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + 11, + -31, + 15.03 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + }, + "bipedLeftLeg": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.76": { + "vector": [ + 0, + 359, + 0 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 2 + ] + }, + "0.76": { + "vector": [ + -11, + -31, + 15.03 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "scale": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutSine" + } + } + } + } + }, + "idle": { + "loop": true, + "animation_length": 4.6, + "bones": { + "group": { + "rotation": { + "0.0": { + "vector": [ + 0, + -20, + 0 + ] + }, + "0.8": { + "vector": [ + 0, + -15, + 15 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + }, + "2.32": { + "vector": [ + 0, + -15, + 15 + ], + "easing": "easeInOutSine" + }, + "3.08": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + }, + "3.84": { + "vector": [ + 0, + -15, + 15 + ], + "easing": "easeInOutSine" + }, + "4.6": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + } + } + }, + "group2": { + "rotation": { + "0.0": { + "vector": [ + 0, + -20, + 0 + ] + }, + "0.8": { + "vector": [ + 0, + -15, + -15 + ], + "easing": "easeInOutSine" + }, + "1.56": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + }, + "2.32": { + "vector": [ + 0, + -15, + -15 + ], + "easing": "easeInOutSine" + }, + "3.08": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + }, + "3.84": { + "vector": [ + 0, + -15, + -15 + ], + "easing": "easeInOutSine" + }, + "4.6": { + "vector": [ + 0, + -20, + 0 + ], + "easing": "easeInOutSine" + } + } + }, + "launcher": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.52": { + "vector": [ + 25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "4.04": { + "vector": [ + 25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "4.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + } + }, + "bone4": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.52": { + "vector": [ + -25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "1.0": { + "vector": [ + -25, + -17.5, + 0 + ], + "easing": "easeInOutSine" + }, + "1.52": { + "vector": [ + -25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "2.0": { + "vector": [ + -25, + 13, + 0 + ], + "easing": "easeInOutSine" + }, + "2.52": { + "vector": [ + -25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "3.04": { + "vector": [ + -25, + -17.5, + 0 + ], + "easing": "easeInOutSine" + }, + "3.52": { + "vector": [ + -25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "4.08": { + "vector": [ + -25, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "4.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + } + } + } + }, + "attacking": { + "animation_length": 2.08, + "bones": { + "blade": { + "position": { + "0.0": { + "vector": [ + 5, + 0, + 0 + ] + }, + "0.52": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutCirc" + }, + "1.56": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutCirc" + }, + "2.08": { + "vector": [ + 5, + 0, + 0 + ], + "easing": "easeInOutCirc" + } + }, + "scale": { + "0.0": { + "vector": [ + 0.7, + 0.7, + 0.7 + ] + }, + "0.52": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutCirc" + }, + "1.56": { + "vector": [ + 1, + 1, + 1 + ], + "easing": "easeInOutCirc" + }, + "2.08": { + "vector": [ + 0.7, + 0.7, + 0.7 + ], + "easing": "easeInOutCirc" + } + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/animations/item/pistol.animation.json b/common/src/main/resources/assets/azurelib/animations/item/pistol.animation.json new file mode 100644 index 000000000..dba595e89 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/animations/item/pistol.animation.json @@ -0,0 +1,80 @@ +{ + "format_version": "1.8.0", + "animations": { + "firing": { + "loop": true, + "animation_length": 0.16, + "bones": { + "group": { + "rotation": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.08": { + "vector": [ + -7.5, + 0, + 0 + ], + "easing": "easeInOutSine" + }, + "0.16": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + }, + "position": { + "0.0": { + "vector": [ + 0, + 0, + 0 + ] + }, + "0.08": { + "vector": [ + 0, + 0, + 2 + ], + "easing": "easeInOutSine" + }, + "0.16": { + "vector": [ + 0, + 0, + 0 + ], + "easing": "easeInOutSine" + } + } + }, + "bone": { + "position": { + "vector": [ + 0, + 0, + -0.3 + ] + }, + "scale": { + "vector": [ + 7, + 7, + 7 + ] + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/blockstates/stargate.json b/common/src/main/resources/assets/azurelib/blockstates/stargate.json new file mode 100644 index 000000000..1d8c9ec54 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/blockstates/stargate.json @@ -0,0 +1,5 @@ +{ + "variants": { + "model": "azurelib:block/stargate" + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/block/stargate.geo.json b/common/src/main/resources/assets/azurelib/geo/block/stargate.geo.json new file mode 100644 index 000000000..8da51fbc9 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/block/stargate.geo.json @@ -0,0 +1,877 @@ +{ + "format_version": "1.21.20", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 256, + "texture_height": 256, + "visible_bounds_width": 7, + "visible_bounds_height": 6.5, + "visible_bounds_offset": [0, 2.75, 0] + }, + "bones": [ + { + "name": "bone9", + "pivot": [0, 12, -0.6] + }, + { + "name": "outter_ring", + "parent": "bone9", + "pivot": [0, 40, 0], + "cubes": [ + { + "origin": [-7.95649, 0, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [160, 24], "uv_size": [16, 4]}, + "east": {"uv": [42, 140], "uv_size": [6, 4]}, + "south": {"uv": [160, 28], "uv_size": [16, 4]}, + "west": {"uv": [122, 161], "uv_size": [6, 4]}, + "up": {"uv": [26, 132], "uv_size": [16, 6]}, + "down": {"uv": [26, 144], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 0, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [160, 32], "uv_size": [16, 4]}, + "east": {"uv": [198, 151], "uv_size": [6, 4]}, + "south": {"uv": [160, 36], "uv_size": [16, 4]}, + "west": {"uv": [199, 50], "uv_size": [6, 4]}, + "up": {"uv": [143, 143], "uv_size": [16, 6]}, + "down": {"uv": [144, 6], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 0, -3], + "size": [15.91299, 4, 6], + "uv": { + "north": {"uv": [160, 40], "uv_size": [16, 4]}, + "east": {"uv": [199, 54], "uv_size": [6, 4]}, + "south": {"uv": [160, 44], "uv_size": [16, 4]}, + "west": {"uv": [155, 200], "uv_size": [6, 4]}, + "up": {"uv": [144, 6], "uv_size": [16, 6]}, + "down": {"uv": [144, 18], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 0, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [160, 48], "uv_size": [16, 4]}, + "east": {"uv": [161, 200], "uv_size": [6, 4]}, + "south": {"uv": [160, 52], "uv_size": [16, 4]}, + "west": {"uv": [167, 200], "uv_size": [6, 4]}, + "up": {"uv": [144, 18], "uv_size": [16, 6]}, + "down": {"uv": [144, 30], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 0, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [160, 56], "uv_size": [16, 4]}, + "east": {"uv": [173, 200], "uv_size": [6, 4]}, + "south": {"uv": [143, 160], "uv_size": [16, 4]}, + "west": {"uv": [179, 200], "uv_size": [6, 4]}, + "up": {"uv": [26, 144], "uv_size": [16, 6]}, + "down": {"uv": [144, 36], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 76, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [159, 160], "uv_size": [16, 4]}, + "east": {"uv": [82, 201], "uv_size": [6, 4]}, + "south": {"uv": [143, 164], "uv_size": [16, 4]}, + "west": {"uv": [201, 166], "uv_size": [6, 4]}, + "up": {"uv": [144, 36], "uv_size": [16, 6]}, + "down": {"uv": [144, 48], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 76, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [159, 164], "uv_size": [16, 4]}, + "east": {"uv": [201, 170], "uv_size": [6, 4]}, + "south": {"uv": [26, 167], "uv_size": [16, 4]}, + "west": {"uv": [201, 174], "uv_size": [6, 4]}, + "up": {"uv": [144, 48], "uv_size": [16, 6]}, + "down": {"uv": [144, 60], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 76, -3], + "size": [15.91299, 4, 6], + "uv": { + "north": {"uv": [42, 167], "uv_size": [16, 4]}, + "east": {"uv": [201, 178], "uv_size": [6, 4]}, + "south": {"uv": [58, 167], "uv_size": [16, 4]}, + "west": {"uv": [202, 0], "uv_size": [6, 4]}, + "up": {"uv": [42, 145], "uv_size": [16, 6]}, + "down": {"uv": [58, 151], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 76, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [74, 167], "uv_size": [16, 4]}, + "east": {"uv": [202, 4], "uv_size": [6, 4]}, + "south": {"uv": [110, 167], "uv_size": [16, 4]}, + "west": {"uv": [24, 202], "uv_size": [6, 4]}, + "up": {"uv": [74, 145], "uv_size": [16, 6]}, + "down": {"uv": [90, 151], "uv_size": [16, -6]} + } + }, + { + "origin": [-7.95649, 76, -3], + "size": [15.91299, 4, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [167, 145], "uv_size": [16, 4]}, + "east": {"uv": [30, 202], "uv_size": [6, 4]}, + "south": {"uv": [167, 149], "uv_size": [16, 4]}, + "west": {"uv": [36, 202], "uv_size": [6, 4]}, + "up": {"uv": [106, 145], "uv_size": [16, 6]}, + "down": {"uv": [143, 155], "uv_size": [16, -6]} + } + }, + { + "origin": [36, 32.04351, -3], + "size": [4, 15.91299, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [118, 151], "uv_size": [4, 16]}, + "east": {"uv": [122, 145], "uv_size": [6, 16]}, + "south": {"uv": [168, 0], "uv_size": [4, 16]}, + "west": {"uv": [26, 150], "uv_size": [6, 16]}, + "up": {"uv": [126, 65], "uv_size": [4, 6]}, + "down": {"uv": [126, 77], "uv_size": [4, -6]} + } + }, + { + "origin": [36, 32.04351, -3], + "size": [4, 15.91299, 6], + "uv": { + "north": {"uv": [143, 168], "uv_size": [4, 16]}, + "east": {"uv": [32, 150], "uv_size": [6, 16]}, + "south": {"uv": [147, 168], "uv_size": [4, 16]}, + "west": {"uv": [38, 151], "uv_size": [6, 16]}, + "up": {"uv": [138, 197], "uv_size": [4, 6]}, + "down": {"uv": [88, 207], "uv_size": [4, -6]} + } + }, + { + "origin": [36, 32.04351, -3], + "size": [4, 15.91299, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [151, 168], "uv_size": [4, 16]}, + "east": {"uv": [44, 151], "uv_size": [6, 16]}, + "south": {"uv": [155, 168], "uv_size": [4, 16]}, + "west": {"uv": [50, 151], "uv_size": [6, 16]}, + "up": {"uv": [42, 202], "uv_size": [4, 6]}, + "down": {"uv": [46, 208], "uv_size": [4, -6]} + } + }, + { + "origin": [-40, 32.04351, -3], + "size": [4, 15.91299, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [159, 168], "uv_size": [4, 16]}, + "east": {"uv": [56, 151], "uv_size": [6, 16]}, + "south": {"uv": [163, 168], "uv_size": [4, 16]}, + "west": {"uv": [62, 151], "uv_size": [6, 16]}, + "up": {"uv": [50, 202], "uv_size": [4, 6]}, + "down": {"uv": [54, 208], "uv_size": [4, -6]} + } + }, + { + "origin": [-40, 32.04351, -3], + "size": [4, 15.91299, 6], + "uv": { + "north": {"uv": [167, 168], "uv_size": [4, 16]}, + "east": {"uv": [68, 151], "uv_size": [6, 16]}, + "south": {"uv": [26, 171], "uv_size": [4, 16]}, + "west": {"uv": [74, 151], "uv_size": [6, 16]}, + "up": {"uv": [58, 202], "uv_size": [4, 6]}, + "down": {"uv": [62, 208], "uv_size": [4, -6]} + } + }, + { + "origin": [-40, 32.04351, -3], + "size": [4, 15.91299, 6], + "pivot": [0, 40, -1], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [30, 171], "uv_size": [4, 16]}, + "east": {"uv": [80, 151], "uv_size": [6, 16]}, + "south": {"uv": [34, 171], "uv_size": [4, 16]}, + "west": {"uv": [86, 151], "uv_size": [6, 16]}, + "up": {"uv": [66, 202], "uv_size": [4, 6]}, + "down": {"uv": [70, 208], "uv_size": [4, -6]} + } + } + ] + }, + { + "name": "bone", + "parent": "outter_ring", + "pivot": [0, 27, 0], + "cubes": [ + { + "origin": [10.4, 3.2, -3.8], + "size": [8, 6, 7.5], + "pivot": [18.4, 5.7, -3.8], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [191, 51], "uv_size": [8, 6]}, + "east": {"uv": [155, 194], "uv_size": [8, 6]}, + "south": {"uv": [163, 194], "uv_size": [8, 6]}, + "west": {"uv": [171, 194], "uv_size": [8, 6]}, + "up": {"uv": [160, 8], "uv_size": [8, 8]}, + "down": {"uv": [160, 24], "uv_size": [8, -8]} + } + }, + { + "origin": [-18.4, 3.2, -3.8], + "size": [8, 6, 7.5], + "pivot": [-18.4, 5.7, -3.8], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [199, 14], "uv_size": [8, 6]}, + "east": {"uv": [199, 20], "uv_size": [8, 6]}, + "south": {"uv": [199, 26], "uv_size": [8, 6]}, + "west": {"uv": [199, 32], "uv_size": [8, 6]}, + "up": {"uv": [78, 171], "uv_size": [8, 8]}, + "down": {"uv": [110, 179], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone2", + "parent": "bone", + "pivot": [-0.5, 76.8, -3.8], + "cubes": [ + { + "origin": [-4.5, 74.6, -3.8], + "size": [8, 6, 7.5], + "uv": { + "north": {"uv": [118, 73], "uv_size": [8, 6]}, + "east": {"uv": [199, 38], "uv_size": [7, 6]}, + "south": {"uv": [155, 188], "uv_size": [8, 6]}, + "west": {"uv": [199, 44], "uv_size": [7, 6]}, + "up": {"uv": [118, 171], "uv_size": [8, 7]}, + "down": {"uv": [187, 15], "uv_size": [8, -7]} + } + } + ] + }, + { + "name": "bone3", + "parent": "bone", + "pivot": [7.5, 47, -2.1], + "cubes": [ + { + "origin": [19.44583, 63.56781, -3.8], + "size": [8, 6, 7.5], + "pivot": [26.5, 64.6, -3.9], + "rotation": [0, 0, 42.5], + "uv": { + "north": {"uv": [163, 188], "uv_size": [8, 6]}, + "east": {"uv": [171, 188], "uv_size": [8, 6]}, + "south": {"uv": [179, 188], "uv_size": [8, 6]}, + "west": {"uv": [188, 184], "uv_size": [8, 6]}, + "up": {"uv": [118, 65], "uv_size": [8, 8]}, + "down": {"uv": [42, 140], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone4", + "parent": "bone", + "pivot": [10.8, 42.2, -2.1], + "cubes": [ + { + "origin": [27, 46.7, -3.8], + "size": [8, 6, 7.5], + "pivot": [35, 46.7, -3.8], + "rotation": [0, 0, 70], + "uv": { + "north": {"uv": [190, 160], "uv_size": [8, 6]}, + "east": {"uv": [187, 190], "uv_size": [8, 6]}, + "south": {"uv": [191, 15], "uv_size": [8, 6]}, + "west": {"uv": [191, 21], "uv_size": [8, 6]}, + "up": {"uv": [110, 151], "uv_size": [8, 8]}, + "down": {"uv": [110, 167], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone5", + "parent": "bone", + "pivot": [35.2, 22.1, -2.1], + "cubes": [ + { + "origin": [26.4, 20.7, -3.8], + "size": [8, 6, 7.5], + "pivot": [34.4, 23.2, -3.8], + "rotation": [0, 0, -60], + "uv": { + "north": {"uv": [191, 27], "uv_size": [8, 6]}, + "east": {"uv": [191, 33], "uv_size": [8, 6]}, + "south": {"uv": [191, 39], "uv_size": [8, 6]}, + "west": {"uv": [191, 45], "uv_size": [8, 6]}, + "up": {"uv": [159, 145], "uv_size": [8, 8]}, + "down": {"uv": [160, 8], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone6", + "parent": "bone", + "pivot": [-29.9, 22.8, -2.1], + "cubes": [ + { + "origin": [-34.4, 20.7, -3.8], + "size": [8, 6, 7.5], + "pivot": [-34.4, 23.2, -3.8], + "rotation": [0, 0, 60], + "uv": { + "north": {"uv": [8, 198], "uv_size": [8, 6]}, + "east": {"uv": [16, 198], "uv_size": [8, 6]}, + "south": {"uv": [198, 145], "uv_size": [8, 6]}, + "west": {"uv": [198, 160], "uv_size": [8, 6]}, + "up": {"uv": [62, 171], "uv_size": [8, 8]}, + "down": {"uv": [70, 179], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone7", + "parent": "bone", + "pivot": [-34.6, 48.8, -2.1], + "cubes": [ + { + "origin": [-35, 46.7, -3.8], + "size": [8, 6, 7.5], + "pivot": [-35, 46.7, -3.8], + "rotation": [0, 0, -70], + "uv": { + "north": {"uv": [187, 196], "uv_size": [8, 6]}, + "east": {"uv": [195, 196], "uv_size": [8, 6]}, + "south": {"uv": [130, 197], "uv_size": [8, 6]}, + "west": {"uv": [0, 198], "uv_size": [8, 6]}, + "up": {"uv": [46, 171], "uv_size": [8, 8]}, + "down": {"uv": [54, 179], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone8", + "parent": "bone", + "pivot": [-23.5, 67.1, -2.1], + "cubes": [ + { + "origin": [-28.44583, 66.56781, -3.8], + "size": [8, 6, 7.5], + "pivot": [-23.5, 67.6, -3.9], + "rotation": [0, 0, -42.5], + "uv": { + "north": {"uv": [179, 194], "uv_size": [8, 6]}, + "east": {"uv": [195, 8], "uv_size": [8, 6]}, + "south": {"uv": [195, 190], "uv_size": [8, 6]}, + "west": {"uv": [196, 184], "uv_size": [8, 6]}, + "up": {"uv": [168, 16], "uv_size": [8, 8]}, + "down": {"uv": [38, 179], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "inner_ring", + "parent": "bone9", + "pivot": [0, 40, 0], + "cubes": [ + { + "origin": [-7.35976, 3, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [171, 168], "uv_size": [15, 4]}, + "east": {"uv": [48, 140], "uv_size": [4, 4]}, + "south": {"uv": [172, 0], "uv_size": [15, 4]}, + "west": {"uv": [74, 202], "uv_size": [4, 4]}, + "up": {"uv": [172, 4], "uv_size": [15, 4]}, + "down": {"uv": [172, 12], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 3, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [172, 12], "uv_size": [15, 4]}, + "east": {"uv": [78, 202], "uv_size": [4, 4]}, + "south": {"uv": [171, 172], "uv_size": [15, 4]}, + "west": {"uv": [110, 202], "uv_size": [4, 4]}, + "up": {"uv": [175, 160], "uv_size": [15, 4]}, + "down": {"uv": [175, 168], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 3, -2], + "size": [14.71952, 4, 4], + "uv": { + "north": {"uv": [176, 16], "uv_size": [15, 4]}, + "east": {"uv": [114, 202], "uv_size": [4, 4]}, + "south": {"uv": [176, 20], "uv_size": [15, 4]}, + "west": {"uv": [118, 202], "uv_size": [4, 4]}, + "up": {"uv": [176, 24], "uv_size": [15, 4]}, + "down": {"uv": [176, 32], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 3, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [176, 32], "uv_size": [15, 4]}, + "east": {"uv": [122, 202], "uv_size": [4, 4]}, + "south": {"uv": [176, 36], "uv_size": [15, 4]}, + "west": {"uv": [185, 202], "uv_size": [4, 4]}, + "up": {"uv": [176, 40], "uv_size": [15, 4]}, + "down": {"uv": [176, 48], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 3, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [176, 48], "uv_size": [15, 4]}, + "east": {"uv": [189, 202], "uv_size": [4, 4]}, + "south": {"uv": [176, 52], "uv_size": [15, 4]}, + "west": {"uv": [193, 202], "uv_size": [4, 4]}, + "up": {"uv": [176, 56], "uv_size": [15, 4]}, + "down": {"uv": [171, 180], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 73, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [38, 179], "uv_size": [15, 4]}, + "east": {"uv": [197, 202], "uv_size": [4, 4]}, + "south": {"uv": [53, 179], "uv_size": [15, 4]}, + "west": {"uv": [201, 202], "uv_size": [4, 4]}, + "up": {"uv": [68, 179], "uv_size": [15, 4]}, + "down": {"uv": [110, 183], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 73, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [171, 180], "uv_size": [15, 4]}, + "east": {"uv": [203, 8], "uv_size": [4, 4]}, + "south": {"uv": [38, 183], "uv_size": [15, 4]}, + "west": {"uv": [130, 203], "uv_size": [4, 4]}, + "up": {"uv": [53, 183], "uv_size": [15, 4]}, + "down": {"uv": [68, 187], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 73, -2], + "size": [14.71952, 4, 4], + "uv": { + "north": {"uv": [110, 183], "uv_size": [15, 4]}, + "east": {"uv": [134, 203], "uv_size": [4, 4]}, + "south": {"uv": [183, 145], "uv_size": [15, 4]}, + "west": {"uv": [138, 203], "uv_size": [4, 4]}, + "up": {"uv": [183, 149], "uv_size": [15, 4]}, + "down": {"uv": [143, 188], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 73, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [158, 184], "uv_size": [15, 4]}, + "east": {"uv": [142, 203], "uv_size": [4, 4]}, + "south": {"uv": [173, 184], "uv_size": [15, 4]}, + "west": {"uv": [146, 203], "uv_size": [4, 4]}, + "up": {"uv": [186, 168], "uv_size": [15, 4]}, + "down": {"uv": [186, 176], "uv_size": [15, -4]} + } + }, + { + "origin": [-7.35976, 73, -2], + "size": [14.71952, 4, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [186, 176], "uv_size": [15, 4]}, + "east": {"uv": [150, 203], "uv_size": [4, 4]}, + "south": {"uv": [186, 180], "uv_size": [15, 4]}, + "west": {"uv": [203, 190], "uv_size": [4, 4]}, + "up": {"uv": [187, 0], "uv_size": [15, 4]}, + "down": {"uv": [187, 8], "uv_size": [15, -4]} + } + }, + { + "origin": [33, 32.64024, -2], + "size": [4, 14.71952, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [86, 171], "uv_size": [4, 15]}, + "east": {"uv": [83, 186], "uv_size": [4, 15]}, + "south": {"uv": [87, 186], "uv_size": [4, 15]}, + "west": {"uv": [26, 187], "uv_size": [4, 15]}, + "up": {"uv": [203, 194], "uv_size": [4, 4]}, + "down": {"uv": [203, 202], "uv_size": [4, -4]} + } + }, + { + "origin": [33, 32.64024, -2], + "size": [4, 14.71952, 4], + "uv": { + "north": {"uv": [30, 187], "uv_size": [4, 15]}, + "east": {"uv": [34, 187], "uv_size": [4, 15]}, + "south": {"uv": [38, 187], "uv_size": [4, 15]}, + "west": {"uv": [42, 187], "uv_size": [4, 15]}, + "up": {"uv": [0, 204], "uv_size": [4, 4]}, + "down": {"uv": [4, 208], "uv_size": [4, -4]} + } + }, + { + "origin": [33, 32.64024, -2], + "size": [4, 14.71952, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [46, 187], "uv_size": [4, 15]}, + "east": {"uv": [50, 187], "uv_size": [4, 15]}, + "south": {"uv": [54, 187], "uv_size": [4, 15]}, + "west": {"uv": [58, 187], "uv_size": [4, 15]}, + "up": {"uv": [8, 204], "uv_size": [4, 4]}, + "down": {"uv": [12, 208], "uv_size": [4, -4]} + } + }, + { + "origin": [-37, 32.64024, -2], + "size": [4, 14.71952, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [62, 187], "uv_size": [4, 15]}, + "east": {"uv": [66, 187], "uv_size": [4, 15]}, + "south": {"uv": [70, 187], "uv_size": [4, 15]}, + "west": {"uv": [74, 187], "uv_size": [4, 15]}, + "up": {"uv": [16, 204], "uv_size": [4, 4]}, + "down": {"uv": [20, 208], "uv_size": [4, -4]} + } + }, + { + "origin": [-37, 32.64024, -2], + "size": [4, 14.71952, 4], + "uv": { + "north": {"uv": [78, 187], "uv_size": [4, 15]}, + "east": {"uv": [110, 187], "uv_size": [4, 15]}, + "south": {"uv": [114, 187], "uv_size": [4, 15]}, + "west": {"uv": [118, 187], "uv_size": [4, 15]}, + "up": {"uv": [204, 151], "uv_size": [4, 4]}, + "down": {"uv": [154, 208], "uv_size": [4, -4]} + } + }, + { + "origin": [-37, 32.64024, -2], + "size": [4, 14.71952, 4], + "pivot": [0, 40, 0], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [122, 187], "uv_size": [4, 15]}, + "east": {"uv": [143, 188], "uv_size": [4, 15]}, + "south": {"uv": [147, 188], "uv_size": [4, 15]}, + "west": {"uv": [151, 188], "uv_size": [4, 15]}, + "up": {"uv": [158, 204], "uv_size": [4, 4]}, + "down": {"uv": [162, 208], "uv_size": [4, -4]} + } + } + ] + }, + { + "name": "portal", + "parent": "bone9", + "pivot": [0, 40, -0.7], + "cubes": [ + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [52, 79], "uv_size": [13, 66]}, + "east": {"uv": [100, 151], "uv_size": [1, 66]}, + "south": {"uv": [65, 79], "uv_size": [13, 66]}, + "west": {"uv": [101, 151], "uv_size": [1, 66]}, + "up": {"uv": [191, 59], "uv_size": [13, 1]}, + "down": {"uv": [201, 183], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [78, 79], "uv_size": [13, 66]}, + "east": {"uv": [102, 151], "uv_size": [1, 66]}, + "south": {"uv": [91, 79], "uv_size": [13, 66]}, + "west": {"uv": [103, 151], "uv_size": [1, 66]}, + "up": {"uv": [201, 183], "uv_size": [13, 1]}, + "down": {"uv": [203, 13], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "uv": { + "north": {"uv": [104, 79], "uv_size": [13, 66]}, + "east": {"uv": [104, 151], "uv_size": [1, 66]}, + "south": {"uv": [117, 79], "uv_size": [13, 66]}, + "west": {"uv": [105, 151], "uv_size": [1, 66]}, + "up": {"uv": [203, 13], "uv_size": [13, 1]}, + "down": {"uv": [204, 59], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [130, 65], "uv_size": [13, 66]}, + "east": {"uv": [106, 151], "uv_size": [1, 66]}, + "south": {"uv": [130, 131], "uv_size": [13, 66]}, + "west": {"uv": [107, 151], "uv_size": [1, 66]}, + "up": {"uv": [204, 59], "uv_size": [13, 1]}, + "down": {"uv": [166, 205], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [0, 132], "uv_size": [13, 66]}, + "east": {"uv": [108, 151], "uv_size": [1, 66]}, + "south": {"uv": [13, 132], "uv_size": [13, 66]}, + "west": {"uv": [109, 151], "uv_size": [1, 66]}, + "up": {"uv": [204, 184], "uv_size": [13, 1]}, + "down": {"uv": [204, 186], "uv_size": [13, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [143, 65], "uv_size": [66, 13]}, + "east": {"uv": [91, 180], "uv_size": [1, 13]}, + "south": {"uv": [143, 78], "uv_size": [66, 13]}, + "west": {"uv": [82, 187], "uv_size": [1, 13]}, + "up": {"uv": [143, 156], "uv_size": [66, 1]}, + "down": {"uv": [143, 158], "uv_size": [66, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "uv": { + "north": {"uv": [143, 91], "uv_size": [66, 13]}, + "east": {"uv": [126, 191], "uv_size": [1, 13]}, + "south": {"uv": [143, 104], "uv_size": [66, 13]}, + "west": {"uv": [127, 191], "uv_size": [1, 13]}, + "up": {"uv": [143, 158], "uv_size": [66, 1]}, + "down": {"uv": [143, 160], "uv_size": [66, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [143, 117], "uv_size": [66, 13]}, + "east": {"uv": [126, 204], "uv_size": [1, 13]}, + "south": {"uv": [143, 130], "uv_size": [66, 13]}, + "west": {"uv": [127, 204], "uv_size": [1, 13]}, + "up": {"uv": [159, 143], "uv_size": [66, 1]}, + "down": {"uv": [159, 145], "uv_size": [66, -1]} + } + } + ] + }, + { + "name": "portal2", + "parent": "bone9", + "pivot": [0, 40, -0.7], + "cubes": [ + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [0, 0], "uv_size": [13, 66]}, + "east": {"uv": [128, 145], "uv_size": [1, 66]}, + "south": {"uv": [13, 0], "uv_size": [13, 66]}, + "west": {"uv": [129, 145], "uv_size": [1, 66]}, + "up": {"uv": [78, 65], "uv_size": [13, 1]}, + "down": {"uv": [91, 66], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [26, 0], "uv_size": [13, 66]}, + "east": {"uv": [92, 151], "uv_size": [1, 66]}, + "south": {"uv": [39, 0], "uv_size": [13, 66]}, + "west": {"uv": [93, 151], "uv_size": [1, 66]}, + "up": {"uv": [104, 65], "uv_size": [13, 1]}, + "down": {"uv": [159, 154], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "uv": { + "north": {"uv": [52, 0], "uv_size": [13, 66]}, + "east": {"uv": [94, 151], "uv_size": [1, 66]}, + "south": {"uv": [65, 0], "uv_size": [13, 66]}, + "west": {"uv": [95, 151], "uv_size": [1, 66]}, + "up": {"uv": [159, 154], "uv_size": [13, 1]}, + "down": {"uv": [172, 154], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [0, 66], "uv_size": [13, 66]}, + "east": {"uv": [96, 151], "uv_size": [1, 66]}, + "south": {"uv": [13, 66], "uv_size": [13, 66]}, + "west": {"uv": [97, 151], "uv_size": [1, 66]}, + "up": {"uv": [172, 154], "uv_size": [13, 1]}, + "down": {"uv": [185, 154], "uv_size": [13, -1]} + } + }, + { + "origin": [-6.56411, 7, -0.7], + "size": [13.12822, 66, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [26, 66], "uv_size": [13, 66]}, + "east": {"uv": [98, 151], "uv_size": [1, 66]}, + "south": {"uv": [39, 66], "uv_size": [13, 66]}, + "west": {"uv": [99, 151], "uv_size": [1, 66]}, + "up": {"uv": [185, 154], "uv_size": [13, 1]}, + "down": {"uv": [191, 59], "uv_size": [13, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [52, 66], "uv_size": [66, 13]}, + "east": {"uv": [126, 165], "uv_size": [1, 13]}, + "south": {"uv": [78, 0], "uv_size": [66, 13]}, + "west": {"uv": [127, 165], "uv_size": [1, 13]}, + "up": {"uv": [144, 60], "uv_size": [66, 1]}, + "down": {"uv": [144, 62], "uv_size": [66, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "uv": { + "north": {"uv": [78, 13], "uv_size": [66, 13]}, + "east": {"uv": [90, 167], "uv_size": [1, 13]}, + "south": {"uv": [78, 26], "uv_size": [66, 13]}, + "west": {"uv": [91, 167], "uv_size": [1, 13]}, + "up": {"uv": [144, 62], "uv_size": [66, 1]}, + "down": {"uv": [144, 64], "uv_size": [66, -1]} + } + }, + { + "origin": [-33, 33.43589, -0.7], + "size": [66, 13.12822, 1], + "pivot": [0, 40, 1.3], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [78, 39], "uv_size": [66, 13]}, + "east": {"uv": [126, 178], "uv_size": [1, 13]}, + "south": {"uv": [78, 52], "uv_size": [66, 13]}, + "west": {"uv": [127, 178], "uv_size": [1, 13]}, + "up": {"uv": [144, 64], "uv_size": [66, 1]}, + "down": {"uv": [143, 156], "uv_size": [66, -1]} + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/entity/doomhunter.geo.json b/common/src/main/resources/assets/azurelib/geo/entity/doomhunter.geo.json new file mode 100644 index 000000000..e537c5e1b --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/entity/doomhunter.geo.json @@ -0,0 +1,1295 @@ +{ + "format_version": "1.21.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 512, + "texture_height": 512, + "visible_bounds_width": 11, + "visible_bounds_height": 10, + "visible_bounds_offset": [0, 4, 0] + }, + "bones": [ + { + "name": "base", + "pivot": [0, 32, 0] + }, + { + "name": "body", + "parent": "base", + "pivot": [0, 16, -2], + "cubes": [ + { + "origin": [-6.5, 27.01142, -2.26147], + "size": [15, 29, 15], + "pivot": [0, 30, 5], + "rotation": [5, 0, 0], + "uv": { + "north": {"uv": [180, 183], "uv_size": [15, 29]}, + "east": {"uv": [165, 183], "uv_size": [15, 29]}, + "south": {"uv": [210, 183], "uv_size": [15, 29]}, + "west": {"uv": [195, 183], "uv_size": [15, 29]}, + "up": {"uv": [180, 168], "uv_size": [15, 15]}, + "down": {"uv": [195, 183], "uv_size": [15, -15]} + } + } + ] + }, + { + "name": "chest", + "parent": "body", + "pivot": [0, 56, 10], + "cubes": [ + { + "origin": [-14, 55.95722, -7.34737], + "size": [31, 20, 19], + "pivot": [0, 56, 8], + "rotation": [7.5, 0, 0], + "uv": { + "north": {"uv": [131, 129], "uv_size": [31, 20]}, + "east": {"uv": [112, 129], "uv_size": [19, 20]}, + "south": {"uv": [181, 129], "uv_size": [31, 20]}, + "west": {"uv": [162, 129], "uv_size": [19, 20]}, + "up": {"uv": [131, 110], "uv_size": [31, 19]}, + "down": {"uv": [162, 129], "uv_size": [31, -19]} + } + }, + { + "origin": [-12, 41, -6.5], + "size": [26, 15, 17], + "pivot": [0, 60, 7], + "rotation": [7.5, 0, 0], + "uv": { + "north": {"uv": [183, 55], "uv_size": [26, 15]}, + "east": {"uv": [166, 55], "uv_size": [17, 15]}, + "south": {"uv": [226, 55], "uv_size": [26, 15]}, + "west": {"uv": [209, 55], "uv_size": [17, 15]}, + "up": {"uv": [183, 38], "uv_size": [26, 17]}, + "down": {"uv": [209, 55], "uv_size": [26, -17]} + } + }, + { + "origin": [-15.25, 57, -11], + "size": [15, 17, 10], + "pivot": [0, 64, -7], + "rotation": [5, 7.5, 0], + "uv": { + "north": {"uv": [176, 80], "uv_size": [15, 17]}, + "east": {"uv": [166, 80], "uv_size": [10, 17]}, + "south": {"uv": [201, 80], "uv_size": [15, 17]}, + "west": {"uv": [191, 80], "uv_size": [10, 17]}, + "up": {"uv": [176, 70], "uv_size": [15, 10]}, + "down": {"uv": [191, 80], "uv_size": [15, -10]} + } + }, + { + "origin": [2.25, 57, -11.75], + "size": [16, 17, 10], + "pivot": [0, 64, -7], + "rotation": [5, -7.5, 0], + "uv": { + "north": {"uv": [220, 166], "uv_size": [16, 17]}, + "east": {"uv": [210, 166], "uv_size": [10, 17]}, + "south": {"uv": [246, 166], "uv_size": [16, 17]}, + "west": {"uv": [236, 166], "uv_size": [10, 17]}, + "up": {"uv": [220, 156], "uv_size": [16, 10]}, + "down": {"uv": [236, 166], "uv_size": [16, -10]} + } + } + ] + }, + { + "name": "neck", + "parent": "chest", + "pivot": [0, 76, 7], + "cubes": [ + { + "origin": [-5, 73.99239, -2.82569], + "size": [12, 11, 12], + "pivot": [0, 74, 7], + "rotation": [20, 0, 0], + "uv": { + "north": {"uv": [112, 195], "uv_size": [12, 11]}, + "east": {"uv": [100, 195], "uv_size": [12, 11]}, + "south": {"uv": [136, 195], "uv_size": [12, 11]}, + "west": {"uv": [124, 195], "uv_size": [12, 11]}, + "up": {"uv": [112, 183], "uv_size": [12, 12]}, + "down": {"uv": [124, 195], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "head", + "parent": "neck", + "pivot": [0.5, 84, 3], + "cubes": [ + { + "origin": [-6.5, 81, -6], + "size": [15, 13, 13], + "pivot": [0.5, 84, 3], + "rotation": [2.5, 0, 0], + "uv": { + "north": {"uv": [200, 13], "uv_size": [15, 13]}, + "east": {"uv": [187, 13], "uv_size": [13, 13]}, + "south": {"uv": [228, 13], "uv_size": [15, 13]}, + "west": {"uv": [215, 13], "uv_size": [13, 13]}, + "up": {"uv": [200, 0], "uv_size": [15, 13]}, + "down": {"uv": [215, 13], "uv_size": [15, -13]} + } + } + ] + }, + { + "name": "topJaw", + "parent": "head", + "pivot": [0.5, 85, -6], + "cubes": [ + { + "origin": [-4.5, 83, -10], + "size": [11, 4, 4], + "uv": { + "north": {"uv": [124, 49], "uv_size": [11, 4]}, + "east": {"uv": [120, 49], "uv_size": [4, 4]}, + "south": {"uv": [139, 49], "uv_size": [11, 4]}, + "west": {"uv": [135, 49], "uv_size": [4, 4]}, + "up": {"uv": [124, 45], "uv_size": [11, 4]}, + "down": {"uv": [135, 49], "uv_size": [11, -4]} + } + } + ] + }, + { + "name": "eye", + "parent": "head", + "pivot": [0.5, 89, -6], + "cubes": [ + { + "origin": [-3.5, 86, -9], + "size": [9, 6, 5], + "pivot": [0.5, 89, -6], + "rotation": [7.5, 0, 0], + "uv": { + "north": {"uv": [5, 75], "uv_size": [9, 6]}, + "east": {"uv": [0, 75], "uv_size": [5, 6]}, + "south": {"uv": [19, 75], "uv_size": [9, 6]}, + "west": {"uv": [14, 75], "uv_size": [5, 6]}, + "up": {"uv": [5, 70], "uv_size": [9, 5]}, + "down": {"uv": [14, 75], "uv_size": [9, -5]} + } + }, + { + "origin": [-0.5, 86.5, -9.5], + "size": [3, 3, 1], + "uv": { + "north": {"uv": [1, 46], "uv_size": [3, 3]}, + "east": {"uv": [0, 46], "uv_size": [1, 3]}, + "south": {"uv": [5, 46], "uv_size": [3, 3]}, + "west": {"uv": [4, 46], "uv_size": [1, 3]}, + "up": {"uv": [1, 45], "uv_size": [3, 1]}, + "down": {"uv": [4, 46], "uv_size": [3, -1]} + } + } + ] + }, + { + "name": "lowJaw", + "parent": "head", + "pivot": [0.5, 82, -3], + "cubes": [ + { + "origin": [-3.5, 80, -10], + "size": [9, 3, 4], + "uv": { + "north": {"uv": [4, 133], "uv_size": [9, 3]}, + "east": {"uv": [0, 133], "uv_size": [4, 3]}, + "south": {"uv": [17, 133], "uv_size": [9, 3]}, + "west": {"uv": [13, 133], "uv_size": [4, 3]}, + "up": {"uv": [4, 129], "uv_size": [9, 4]}, + "down": {"uv": [13, 133], "uv_size": [9, -4]} + } + } + ] + }, + { + "name": "lHorn", + "parent": "head", + "pivot": [5.6, 85.3, 1], + "rotation": [-2.38443, -0.75155, -122.48436], + "cubes": [ + { + "origin": [1.6, 77.3, -2], + "size": [6, 7, 6], + "uv": { + "north": {"uv": [134, 6], "uv_size": [6, 7]}, + "east": {"uv": [128, 6], "uv_size": [6, 7]}, + "south": {"uv": [146, 6], "uv_size": [6, 7]}, + "west": {"uv": [140, 6], "uv_size": [6, 7]}, + "up": {"uv": [134, 0], "uv_size": [6, 6]}, + "down": {"uv": [140, 6], "uv_size": [6, -6]} + } + } + ] + }, + { + "name": "bone2", + "parent": "lHorn", + "pivot": [4.6, 78.3, 1], + "rotation": [0, 0, -15], + "cubes": [ + { + "origin": [2.1, 72.3, -1.5], + "size": [5, 7, 5], + "pivot": [4.6, 78.3, 1], + "rotation": [-20, 0, -7.5], + "uv": { + "north": {"uv": [163, 165], "uv_size": [5, 6]}, + "east": {"uv": [158, 165], "uv_size": [5, 6]}, + "south": {"uv": [168, 154], "uv_size": [5, 7]}, + "west": {"uv": [168, 165], "uv_size": [5, 6]}, + "up": {"uv": [163, 160], "uv_size": [5, 5]}, + "down": {"uv": [168, 165], "uv_size": [5, -5]} + } + } + ] + }, + { + "name": "bone3", + "parent": "bone2", + "pivot": [4.6, 72.3, 1], + "cubes": [ + { + "origin": [3.6, 65.3, -3], + "size": [4, 7, 4], + "pivot": [4.6, 72.3, 1], + "rotation": [-30, 0, -22.5], + "uv": { + "north": {"uv": [154, 49], "uv_size": [4, 7]}, + "east": {"uv": [150, 49], "uv_size": [4, 7]}, + "south": {"uv": [162, 49], "uv_size": [4, 7]}, + "west": {"uv": [158, 49], "uv_size": [4, 7]}, + "up": {"uv": [154, 45], "uv_size": [4, 4]}, + "down": {"uv": [158, 49], "uv_size": [4, -4]} + } + } + ] + }, + { + "name": "bone4", + "parent": "bone3", + "pivot": [5.4, 64.3, 1.25], + "rotation": [0, 0, -17.5], + "cubes": [ + { + "origin": [7.9, 57.3, -5.5], + "size": [3, 7, 3], + "pivot": [5.4, 64.3, 1.25], + "rotation": [-22.5, 0, -27.5], + "uv": { + "north": {"uv": [29, 132], "uv_size": [3, 7]}, + "east": {"uv": [26, 132], "uv_size": [3, 7]}, + "south": {"uv": [35, 132], "uv_size": [3, 7]}, + "west": {"uv": [32, 132], "uv_size": [3, 7]}, + "up": {"uv": [29, 129], "uv_size": [3, 3]}, + "down": {"uv": [32, 132], "uv_size": [3, -3]} + } + } + ] + }, + { + "name": "bone5", + "parent": "bone4", + "pivot": [5.4, 57.3, 1.25], + "cubes": [ + { + "origin": [11.4, 50.3, -7.25], + "size": [2, 7, 2], + "pivot": [5.4, 57.3, 1.25], + "rotation": [-30, 0, -27.5], + "uv": { + "north": {"uv": [27, 2], "uv_size": [2, 7]}, + "east": {"uv": [25, 2], "uv_size": [2, 7]}, + "south": {"uv": [31, 2], "uv_size": [2, 7]}, + "west": {"uv": [29, 2], "uv_size": [2, 7]}, + "up": {"uv": [27, 0], "uv_size": [2, 2]}, + "down": {"uv": [29, 2], "uv_size": [2, -2]} + } + } + ] + }, + { + "name": "lHorn2", + "parent": "head", + "pivot": [-5.5, 84, 1], + "rotation": [0, 0, 122.5], + "cubes": [ + { + "origin": [-9.5, 77, -2], + "size": [6, 7, 6], + "uv": { + "north": {"uv": [77, 132], "uv_size": [6, 7]}, + "east": {"uv": [71, 132], "uv_size": [6, 7]}, + "south": {"uv": [89, 132], "uv_size": [6, 7]}, + "west": {"uv": [83, 132], "uv_size": [6, 7]}, + "up": {"uv": [77, 126], "uv_size": [6, 6]}, + "down": {"uv": [83, 132], "uv_size": [6, -6]} + } + } + ] + }, + { + "name": "bone10", + "parent": "lHorn2", + "pivot": [-6.5, 77, 1], + "rotation": [0, 0, 15], + "cubes": [ + { + "origin": [-9, 72, -1.5], + "size": [5, 7, 5], + "pivot": [-6.5, 77, 1], + "rotation": [-20, 0, 7.5], + "uv": { + "north": {"uv": [163, 154], "uv_size": [5, 6]}, + "east": {"uv": [158, 154], "uv_size": [5, 6]}, + "south": {"uv": [168, 154], "uv_size": [5, 7]}, + "west": {"uv": [168, 154], "uv_size": [5, 6]}, + "up": {"uv": [163, 149], "uv_size": [5, 5]}, + "down": {"uv": [168, 154], "uv_size": [5, -5]} + } + } + ] + }, + { + "name": "bone11", + "parent": "bone10", + "pivot": [-6.5, 77, 1], + "cubes": [ + { + "origin": [-9.5, 65, -3], + "size": [4, 7, 4], + "pivot": [-6.5, 71, 1], + "rotation": [-30, 0, 22.5], + "uv": { + "north": {"uv": [99, 130], "uv_size": [4, 7]}, + "east": {"uv": [95, 130], "uv_size": [4, 7]}, + "south": {"uv": [107, 130], "uv_size": [4, 7]}, + "west": {"uv": [103, 130], "uv_size": [4, 7]}, + "up": {"uv": [99, 126], "uv_size": [4, 4]}, + "down": {"uv": [103, 130], "uv_size": [4, -4]} + } + } + ] + }, + { + "name": "bone12", + "parent": "bone11", + "pivot": [-3.5, 76, 1.25], + "rotation": [0, 0, 17.5], + "cubes": [ + { + "origin": [-9, 57, -5.5], + "size": [3, 7, 3], + "pivot": [-3.5, 63, 1.25], + "rotation": [-22.5, 0, 27.5], + "uv": { + "north": {"uv": [101, 48], "uv_size": [3, 7]}, + "east": {"uv": [98, 48], "uv_size": [3, 7]}, + "south": {"uv": [107, 48], "uv_size": [3, 7]}, + "west": {"uv": [104, 48], "uv_size": [3, 7]}, + "up": {"uv": [101, 45], "uv_size": [3, 3]}, + "down": {"uv": [104, 48], "uv_size": [3, -3]} + } + } + ] + }, + { + "name": "bone13", + "parent": "bone12", + "pivot": [-3.5, 76, 1.25], + "cubes": [ + { + "origin": [-11.5, 50, -7.25], + "size": [2, 7, 2], + "pivot": [-3.5, 56, 1.25], + "rotation": [-30, 0, 27.5], + "uv": { + "north": {"uv": [2, 2], "uv_size": [2, 7]}, + "east": {"uv": [0, 2], "uv_size": [2, 7]}, + "south": {"uv": [6, 2], "uv_size": [2, 7]}, + "west": {"uv": [4, 2], "uv_size": [2, 7]}, + "up": {"uv": [2, 0], "uv_size": [2, 2]}, + "down": {"uv": [4, 2], "uv_size": [2, -2]} + } + } + ] + }, + { + "name": "rShoulder", + "parent": "chest", + "pivot": [-12, 72, 1], + "rotation": [0, 0, 20], + "cubes": [ + { + "origin": [-21, 66, -5], + "size": [11, 11, 12], + "pivot": [-12, 72, 1], + "rotation": [7.5, 0, 0], + "uv": { + "north": {"uv": [233, 82], "uv_size": [11, 11]}, + "east": {"uv": [221, 82], "uv_size": [12, 11]}, + "south": {"uv": [256, 82], "uv_size": [11, 11]}, + "west": {"uv": [244, 82], "uv_size": [12, 11]}, + "up": {"uv": [233, 70], "uv_size": [11, 12]}, + "down": {"uv": [244, 82], "uv_size": [11, -12]} + } + } + ] + }, + { + "name": "rArm1", + "parent": "rShoulder", + "pivot": [-16, 68, 1], + "rotation": [-17.5, 0, -5], + "cubes": [ + { + "origin": [-20, 50.5, -4.75], + "size": [9, 18, 11], + "uv": { + "north": {"uv": [230, 212], "uv_size": [9, 18]}, + "east": {"uv": [219, 212], "uv_size": [11, 18]}, + "south": {"uv": [250, 212], "uv_size": [9, 18]}, + "west": {"uv": [239, 212], "uv_size": [11, 18]}, + "up": {"uv": [230, 201], "uv_size": [9, 11]}, + "down": {"uv": [239, 212], "uv_size": [9, -11]} + } + } + ] + }, + { + "name": "rArm2", + "parent": "rArm1", + "pivot": [-16.5, 51, 6.5], + "rotation": [-20, 0, -17.5], + "cubes": [ + { + "origin": [-19.5, 23, -3], + "size": [8, 28, 9], + "pivot": [-16.5, 51, 6.5], + "rotation": [-17.5, 0, 0], + "uv": { + "north": {"uv": [9, 9], "uv_size": [8, 28]}, + "east": {"uv": [0, 9], "uv_size": [9, 28]}, + "south": {"uv": [26, 9], "uv_size": [8, 28]}, + "west": {"uv": [17, 9], "uv_size": [9, 28]}, + "up": {"uv": [9, 0], "uv_size": [8, 9]}, + "down": {"uv": [17, 9], "uv_size": [8, -9]} + } + }, + { + "origin": [-33, 38.16202, -8.98168], + "size": [4, 18, 0], + "pivot": [-14, 51.5, -10.5], + "rotation": [64.1278, 70.65922, 67.2587], + "uv": { + "north": {"uv": [288, 204], "uv_size": [4, 18]}, + "east": {"uv": [0, 0], "uv_size": [0, 18]}, + "south": {"uv": [292, 204], "uv_size": [-4, 18]}, + "west": {"uv": [0, 0], "uv_size": [0, 18]}, + "up": {"uv": [4, 0], "uv_size": [-4, 0]}, + "down": {"uv": [4, 0], "uv_size": [-4, 0]} + } + } + ] + }, + { + "name": "bigGun", + "parent": "rArm2", + "pivot": [-16.5, 38, 0.5], + "cubes": [ + { + "origin": [-20.5, 22, 0.5], + "size": [10, 25, 11], + "pivot": [-16.5, 38, 0.5], + "rotation": [-17.5, 0, 0], + "uv": { + "north": {"uv": [100, 227], "uv_size": [10, 25]}, + "east": {"uv": [89, 227], "uv_size": [11, 25]}, + "south": {"uv": [121, 227], "uv_size": [10, 25]}, + "west": {"uv": [110, 227], "uv_size": [11, 25]}, + "up": {"uv": [100, 216], "uv_size": [10, 11]}, + "down": {"uv": [110, 227], "uv_size": [10, -11]} + } + }, + { + "origin": [-20, 7, 1], + "size": [9, 15, 10], + "pivot": [-16.5, 38, 0.5], + "rotation": [-17.5, 0, 0], + "uv": { + "north": {"uv": [10, 55], "uv_size": [9, 15]}, + "east": {"uv": [0, 55], "uv_size": [10, 15]}, + "south": {"uv": [29, 55], "uv_size": [9, 15]}, + "west": {"uv": [19, 55], "uv_size": [10, 15]}, + "up": {"uv": [10, 45], "uv_size": [9, 10]}, + "down": {"uv": [19, 55], "uv_size": [9, -10]} + } + } + ] + }, + { + "name": "trigger", + "parent": "bigGun", + "pivot": [-15.75, 21, -1.5], + "cubes": [ + { + "origin": [-17.5, 17, -15.5], + "size": [5, 5, 12], + "pivot": [-15.75, 21, -1.5], + "rotation": [-12.5, 0, 0], + "uv": { + "north": {"uv": [110, 57], "uv_size": [5, 5]}, + "east": {"uv": [98, 57], "uv_size": [12, 5]}, + "south": {"uv": [127, 57], "uv_size": [5, 5]}, + "west": {"uv": [115, 57], "uv_size": [12, 5]}, + "up": {"uv": [110, 45], "uv_size": [5, 12]}, + "down": {"uv": [115, 57], "uv_size": [5, -12]} + } + }, + { + "origin": [-15.5, 4, -12.5], + "size": [1, 18, 3], + "pivot": [-15.75, 21, -1.5], + "rotation": [7.5, 0, 0], + "uv": { + "north": {"uv": [157, 186], "uv_size": [1, 18]}, + "east": {"uv": [154, 186], "uv_size": [3, 18]}, + "south": {"uv": [161, 186], "uv_size": [1, 18]}, + "west": {"uv": [158, 186], "uv_size": [3, 18]}, + "up": {"uv": [157, 183], "uv_size": [1, 3]}, + "down": {"uv": [158, 186], "uv_size": [1, -3]} + } + } + ] + }, + { + "name": "bone6", + "parent": "bigGun", + "pivot": [-16.5, 38, 0.5] + }, + { + "name": "bone7", + "parent": "bone6", + "pivot": [-16.5, 38, 0.5], + "cubes": [ + { + "origin": [-19.5, 0, -6.5], + "size": [8, 8, 8], + "pivot": [-15.75, 21, -1.5], + "rotation": [-12.5, 0, 0], + "uv": { + "north": {"uv": [106, 70], "uv_size": [8, 8]}, + "east": {"uv": [98, 70], "uv_size": [8, 8]}, + "south": {"uv": [122, 70], "uv_size": [8, 8]}, + "west": {"uv": [114, 70], "uv_size": [8, 8]}, + "up": {"uv": [106, 62], "uv_size": [8, 8]}, + "down": {"uv": [114, 70], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "bone8", + "parent": "bone6", + "pivot": [-16.5, 38, 0.5], + "cubes": [ + { + "origin": [-19.5, 0, 4.5], + "size": [8, 7, 3], + "pivot": [-16.5, 38, 0.5], + "rotation": [-10, 0, 0], + "uv": { + "north": {"uv": [74, 101], "uv_size": [8, 7]}, + "east": {"uv": [71, 101], "uv_size": [3, 7]}, + "south": {"uv": [85, 101], "uv_size": [8, 7]}, + "west": {"uv": [82, 101], "uv_size": [3, 7]}, + "up": {"uv": [74, 98], "uv_size": [8, 3]}, + "down": {"uv": [82, 101], "uv_size": [8, -3]} + } + } + ] + }, + { + "name": "lShoulder", + "parent": "chest", + "pivot": [16, 73, 3], + "cubes": [ + { + "origin": [17, 59, -7], + "size": [8, 17, 15], + "uv": { + "north": {"uv": [58, 231], "uv_size": [8, 17]}, + "east": {"uv": [43, 231], "uv_size": [15, 17]}, + "south": {"uv": [81, 231], "uv_size": [8, 17]}, + "west": {"uv": [66, 231], "uv_size": [15, 17]}, + "up": {"uv": [58, 216], "uv_size": [8, 15]}, + "down": {"uv": [66, 231], "uv_size": [8, -15]} + } + } + ] + }, + { + "name": "lArm1", + "parent": "lShoulder", + "pivot": [25, 67.5, 0.5], + "cubes": [ + { + "origin": [24, 62.5, -3.5], + "size": [13, 9, 8], + "uv": { + "north": {"uv": [233, 191], "uv_size": [13, 9]}, + "east": {"uv": [225, 191], "uv_size": [8, 9]}, + "south": {"uv": [254, 191], "uv_size": [13, 9]}, + "west": {"uv": [246, 191], "uv_size": [8, 9]}, + "up": {"uv": [233, 183], "uv_size": [13, 8]}, + "down": {"uv": [246, 191], "uv_size": [13, -8]} + } + } + ] + }, + { + "name": "lArm2", + "parent": "lArm1", + "pivot": [35, 67.5, 0.5], + "cubes": [ + { + "origin": [32, 55.5, -5.5], + "size": [17, 22, 12], + "pivot": [35, 67.5, 0.5], + "rotation": [0, 0, -12.5], + "uv": { + "north": {"uv": [12, 201], "uv_size": [17, 22]}, + "east": {"uv": [0, 201], "uv_size": [12, 22]}, + "south": {"uv": [41, 201], "uv_size": [17, 22]}, + "west": {"uv": [29, 201], "uv_size": [12, 22]}, + "up": {"uv": [12, 189], "uv_size": [17, 12]}, + "down": {"uv": [29, 201], "uv_size": [17, -12]} + } + } + ] + }, + { + "name": "lArm3", + "parent": "lArm2", + "pivot": [44, 57.5, 0.5], + "cubes": [ + { + "origin": [36, 37.5, -3.5], + "size": [12, 23, 8], + "pivot": [44, 57.5, 0.5], + "rotation": [-15, 0, 0], + "uv": { + "north": {"uv": [8, 106], "uv_size": [12, 23]}, + "east": {"uv": [0, 106], "uv_size": [8, 23]}, + "south": {"uv": [28, 106], "uv_size": [12, 23]}, + "west": {"uv": [20, 106], "uv_size": [8, 23]}, + "up": {"uv": [8, 98], "uv_size": [12, 8]}, + "down": {"uv": [20, 106], "uv_size": [12, -8]} + } + }, + { + "origin": [31, 39.5, -3.5], + "size": [4, 18, 0], + "pivot": [35, 48.5, -2.5], + "rotation": [-25, 0, 0], + "uv": { + "north": {"uv": [288, 204], "uv_size": [4, 18]}, + "east": {"uv": [0, 0], "uv_size": [0, 18]}, + "south": {"uv": [292, 204], "uv_size": [-4, 18]}, + "west": {"uv": [0, 0], "uv_size": [0, 18]}, + "up": {"uv": [4, 0], "uv_size": [-4, 0]}, + "down": {"uv": [4, 0], "uv_size": [-4, 0]} + } + } + ] + }, + { + "name": "sawBase", + "parent": "lArm3", + "pivot": [42, 41.5, -4.5], + "cubes": [ + { + "origin": [35, 27.5, -10.5], + "size": [14, 17, 13], + "pivot": [42, 41.5, -4.5], + "rotation": [-47.5, 0, 0], + "uv": { + "north": {"uv": [178, 225], "uv_size": [14, 17]}, + "east": {"uv": [165, 225], "uv_size": [13, 17]}, + "south": {"uv": [205, 225], "uv_size": [14, 17]}, + "west": {"uv": [192, 225], "uv_size": [13, 17]}, + "up": {"uv": [178, 212], "uv_size": [14, 13]}, + "down": {"uv": [192, 225], "uv_size": [14, -13]} + } + } + ] + }, + { + "name": "sawBlades", + "parent": "sawBase", + "pivot": [42, 31.5, -14.5], + "cubes": [ + { + "origin": [45, 35.5, -42.5], + "size": [2, 11, 24], + "pivot": [42, 41.5, -4.5], + "rotation": [40, 0, 0], + "uv": { + "north": {"uv": [217, 110], "uv_size": [2, 11]}, + "east": {"uv": [126, 212], "uv_size": [24, 11]}, + "south": {"uv": [243, 110], "uv_size": [2, 11]}, + "west": {"uv": [150, 212], "uv_size": [-24, 11]}, + "up": {"uv": [217, 86], "uv_size": [2, 24]}, + "down": {"uv": [219, 110], "uv_size": [2, -24]} + } + }, + { + "origin": [37, 35.5, -42.5], + "size": [2, 11, 24], + "pivot": [42, 41.5, -4.5], + "rotation": [40, 0, 0], + "uv": { + "north": {"uv": [150, 212], "uv_size": [2, 11]}, + "east": {"uv": [126, 212], "uv_size": [24, 11]}, + "south": {"uv": [176, 212], "uv_size": [2, 11]}, + "west": {"uv": [150, 212], "uv_size": [-24, 11]}, + "up": {"uv": [150, 188], "uv_size": [2, 24]}, + "down": {"uv": [152, 212], "uv_size": [2, -24]} + } + }, + { + "origin": [38, 32.5, -45.5], + "size": [0, 16, 26], + "pivot": [42, 41.5, -4.5], + "rotation": [40, 0, 0], + "uv": { + "north": {"uv": [81, 151], "uv_size": [0, 16]}, + "east": {"uv": [55, 151], "uv_size": [26, 16]}, + "south": {"uv": [107, 151], "uv_size": [0, 16]}, + "west": {"uv": [81, 151], "uv_size": [26, 16]}, + "up": {"uv": [81, 125], "uv_size": [0, 26]}, + "down": {"uv": [81, 151], "uv_size": [0, -26]} + } + }, + { + "origin": [46, 32.5, -45.5], + "size": [0, 16, 26], + "pivot": [42, 41.5, -4.5], + "rotation": [40, 0, 0], + "uv": { + "north": {"uv": [97, 110], "uv_size": [0, 16]}, + "east": {"uv": [71, 110], "uv_size": [26, 16]}, + "south": {"uv": [123, 110], "uv_size": [0, 16]}, + "west": {"uv": [97, 110], "uv_size": [26, 16]}, + "up": {"uv": [97, 84], "uv_size": [0, 26]}, + "down": {"uv": [97, 110], "uv_size": [0, -26]} + } + } + ] + }, + { + "name": "propulsion6", + "parent": "chest", + "pivot": [1, 43, 9.3], + "rotation": [85, 0, 0], + "cubes": [ + { + "origin": [-5, 32, 8.3], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [230, 241], "uv_size": [11, 12]}, + "east": {"uv": [219, 241], "uv_size": [11, 12]}, + "south": {"uv": [252, 241], "uv_size": [11, 12]}, + "west": {"uv": [241, 241], "uv_size": [11, 12]}, + "up": {"uv": [230, 230], "uv_size": [11, 11]}, + "down": {"uv": [241, 241], "uv_size": [11, -11]} + } + }, + { + "origin": [0.5, 16, 8.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + }, + { + "origin": [-4.6, 16, 13.5], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + } + ] + }, + { + "name": "propulsion5", + "parent": "body", + "pivot": [4.5, 26, 2.3], + "rotation": [7.5, 0, 0], + "cubes": [ + { + "origin": [-4.5, 15, 1.3], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [239, 132], "uv_size": [11, 12]}, + "east": {"uv": [228, 132], "uv_size": [11, 12]}, + "south": {"uv": [261, 132], "uv_size": [11, 12]}, + "west": {"uv": [250, 132], "uv_size": [11, 12]}, + "up": {"uv": [239, 121], "uv_size": [11, 11]}, + "down": {"uv": [254, 26], "uv_size": [11, -11]} + } + } + ] + }, + { + "name": "bone", + "parent": "propulsion5", + "pivot": [4.7, 26, 2.3], + "cubes": [ + { + "origin": [-3.9, -1, 6.5], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + }, + { + "origin": [1.2, -1, 1.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + } + ] + }, + { + "name": "sled", + "parent": "base", + "pivot": [0, 31, 4], + "cubes": [ + { + "origin": [-22.04043, 28.75979, -15], + "size": [15, 12, 41], + "pivot": [32, 22, 0], + "rotation": [0, 0, -17.5], + "uv": { + "north": {"uv": [136, 98], "uv_size": [15, 12]}, + "east": {"uv": [95, 98], "uv_size": [41, 12]}, + "south": {"uv": [192, 98], "uv_size": [15, 12]}, + "west": {"uv": [151, 98], "uv_size": [41, 12]}, + "up": {"uv": [136, 57], "uv_size": [15, 41]}, + "down": {"uv": [151, 98], "uv_size": [15, -41]} + } + }, + { + "origin": [-15, 14, -13], + "size": [30, 15, 38], + "pivot": [0.5, 21, 0], + "rotation": [10, 0, 0], + "uv": { + "north": {"uv": [38, 83], "uv_size": [30, 15]}, + "east": {"uv": [0, 83], "uv_size": [38, 15]}, + "south": {"uv": [106, 83], "uv_size": [30, 15]}, + "west": {"uv": [68, 83], "uv_size": [38, 15]}, + "up": {"uv": [38, 45], "uv_size": [30, 38]}, + "down": {"uv": [68, 83], "uv_size": [30, -38]} + } + }, + { + "origin": [-22, 12, -12.5], + "size": [45, 7, 38], + "uv": { + "north": {"uv": [38, 38], "uv_size": [45, 7]}, + "east": {"uv": [0, 38], "uv_size": [38, 7]}, + "south": {"uv": [121, 38], "uv_size": [45, 7]}, + "west": {"uv": [83, 38], "uv_size": [38, 7]}, + "up": {"uv": [38, 0], "uv_size": [45, 38]}, + "down": {"uv": [83, 38], "uv_size": [45, -38]} + } + }, + { + "origin": [12, 17, -15], + "size": [15, 12, 41], + "pivot": [9, 29, 0], + "rotation": [0, 0, 17.5], + "uv": { + "north": {"uv": [41, 139], "uv_size": [15, 12]}, + "east": {"uv": [0, 139], "uv_size": [41, 12]}, + "south": {"uv": [97, 139], "uv_size": [15, 12]}, + "west": {"uv": [56, 139], "uv_size": [41, 12]}, + "up": {"uv": [41, 98], "uv_size": [15, 41]}, + "down": {"uv": [56, 139], "uv_size": [15, -41]} + } + }, + { + "origin": [-39, 14.5, -9], + "size": [13, 9, 29], + "pivot": [-26, 24, 0], + "rotation": [0, 0, -47.5], + "uv": { + "north": {"uv": [29, 180], "uv_size": [13, 9]}, + "east": {"uv": [0, 180], "uv_size": [29, 9]}, + "south": {"uv": [71, 180], "uv_size": [13, 9]}, + "west": {"uv": [42, 180], "uv_size": [29, 9]}, + "up": {"uv": [29, 151], "uv_size": [13, 29]}, + "down": {"uv": [42, 180], "uv_size": [13, -29]} + } + }, + { + "origin": [25.5, 15.5, -9], + "size": [15, 9, 29], + "pivot": [25, 24, 0], + "rotation": [0, 0, 47.5], + "uv": { + "north": {"uv": [157, 29], "uv_size": [15, 9]}, + "east": {"uv": [128, 29], "uv_size": [29, 9]}, + "south": {"uv": [201, 29], "uv_size": [15, 9]}, + "west": {"uv": [172, 29], "uv_size": [29, 9]}, + "up": {"uv": [157, 0], "uv_size": [15, 29]}, + "down": {"uv": [172, 29], "uv_size": [15, -29]} + } + }, + { + "origin": [-11, 20, -23], + "size": [23, 12, 22], + "pivot": [0, 32, 0], + "rotation": [17.5, 0, 0], + "uv": { + "north": {"uv": [112, 171], "uv_size": [23, 12]}, + "east": {"uv": [90, 171], "uv_size": [22, 12]}, + "south": {"uv": [157, 171], "uv_size": [23, 12]}, + "west": {"uv": [135, 171], "uv_size": [22, 12]}, + "up": {"uv": [112, 149], "uv_size": [23, 22]}, + "down": {"uv": [135, 171], "uv_size": [23, -22]} + } + } + ] + }, + { + "name": "lGun", + "parent": "sled", + "pivot": [18, 12, 1], + "cubes": [ + { + "origin": [15, 5, -3], + "size": [6, 7, 6], + "uv": { + "north": {"uv": [6, 157], "uv_size": [6, 7]}, + "east": {"uv": [0, 157], "uv_size": [6, 7]}, + "south": {"uv": [18, 157], "uv_size": [6, 7]}, + "west": {"uv": [12, 157], "uv_size": [6, 7]}, + "up": {"uv": [6, 151], "uv_size": [6, 6]}, + "down": {"uv": [12, 157], "uv_size": [6, -6]} + } + } + ] + }, + { + "name": "lGunBarrel", + "parent": "lGun", + "pivot": [18, 9, 0.25], + "cubes": [ + { + "origin": [14, 3, -24.75], + "size": [8, 7, 26], + "uv": { + "north": {"uv": [212, 149], "uv_size": [8, 7]}, + "east": {"uv": [186, 149], "uv_size": [26, 7]}, + "south": {"uv": [246, 149], "uv_size": [8, 7]}, + "west": {"uv": [220, 149], "uv_size": [26, 7]}, + "up": {"uv": [212, 123], "uv_size": [8, 26]}, + "down": {"uv": [220, 149], "uv_size": [8, -26]} + } + } + ] + }, + { + "name": "rGun2", + "parent": "sled", + "pivot": [-18, 12, 1], + "cubes": [ + { + "origin": [-21, 5, -3], + "size": [6, 7, 6], + "uv": { + "north": {"uv": [134, 19], "uv_size": [6, 7]}, + "east": {"uv": [128, 19], "uv_size": [6, 7]}, + "south": {"uv": [146, 19], "uv_size": [6, 7]}, + "west": {"uv": [140, 19], "uv_size": [6, 7]}, + "up": {"uv": [134, 13], "uv_size": [6, 6]}, + "down": {"uv": [140, 19], "uv_size": [6, -6]} + } + } + ] + }, + { + "name": "rGunBarrel2", + "parent": "rGun2", + "pivot": [-18, 9, 0.25], + "cubes": [ + { + "origin": [-22, 3, -24.75], + "size": [8, 7, 26], + "uv": { + "north": {"uv": [84, 209], "uv_size": [8, 7]}, + "east": {"uv": [58, 209], "uv_size": [26, 7]}, + "south": {"uv": [118, 209], "uv_size": [8, 7]}, + "west": {"uv": [92, 209], "uv_size": [26, 7]}, + "up": {"uv": [84, 183], "uv_size": [8, 26]}, + "down": {"uv": [92, 209], "uv_size": [8, -26]} + } + } + ] + }, + { + "name": "propulsion1", + "parent": "sled", + "pivot": [-11, 12, -7], + "rotation": [-20, 0, 0], + "cubes": [ + { + "origin": [-13, 1, -17], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [11, 248], "uv_size": [11, 12]}, + "east": {"uv": [0, 248], "uv_size": [11, 12]}, + "south": {"uv": [33, 248], "uv_size": [11, 12]}, + "west": {"uv": [22, 248], "uv_size": [11, 12]}, + "up": {"uv": [11, 237], "uv_size": [11, 11]}, + "down": {"uv": [22, 248], "uv_size": [11, -11]} + } + }, + { + "origin": [-12.6, -15, -11.9], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + }, + { + "origin": [-7.5, -15, -16.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + } + ] + }, + { + "name": "propulsion2", + "parent": "sled", + "pivot": [4, 12, -7], + "rotation": [-20, 0, 0], + "cubes": [ + { + "origin": [2, 1, -17], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [243, 26], "uv_size": [11, 12]}, + "east": {"uv": [232, 26], "uv_size": [11, 12]}, + "south": {"uv": [265, 26], "uv_size": [11, 12]}, + "west": {"uv": [254, 26], "uv_size": [11, 12]}, + "up": {"uv": [243, 15], "uv_size": [11, 11]}, + "down": {"uv": [254, 26], "uv_size": [11, -11]} + } + }, + { + "origin": [7.5, -15, -16.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + }, + { + "origin": [2.4, -15, -11.9], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + } + ] + }, + { + "name": "propulsion3", + "parent": "sled", + "pivot": [10, 12, 14.3], + "rotation": [20, 0, 0], + "cubes": [ + { + "origin": [1, 1, 13.3], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [142, 242], "uv_size": [11, 12]}, + "east": {"uv": [131, 242], "uv_size": [11, 12]}, + "south": {"uv": [164, 242], "uv_size": [11, 12]}, + "west": {"uv": [153, 242], "uv_size": [11, 12]}, + "up": {"uv": [142, 231], "uv_size": [11, 11]}, + "down": {"uv": [153, 242], "uv_size": [11, -11]} + } + }, + { + "origin": [6.5, -15, 13.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + }, + { + "origin": [1.4, -15, 18.5], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + } + ] + }, + { + "name": "propulsion4", + "parent": "sled", + "pivot": [-5, 12, 14.3], + "rotation": [20, 0, 0], + "cubes": [ + { + "origin": [-14, 1, 13.3], + "size": [11, 12, 11], + "uv": { + "north": {"uv": [230, 241], "uv_size": [11, 12]}, + "east": {"uv": [219, 241], "uv_size": [11, 12]}, + "south": {"uv": [252, 241], "uv_size": [11, 12]}, + "west": {"uv": [241, 241], "uv_size": [11, 12]}, + "up": {"uv": [230, 230], "uv_size": [11, 11]}, + "down": {"uv": [241, 241], "uv_size": [11, -11]} + } + }, + { + "origin": [-8.5, -15, 13.7], + "size": [0, 16, 10], + "uv": { + "north": {"uv": [73, 318], "uv_size": [0, 16]}, + "east": {"uv": [83, 317], "uv_size": [-10, -16]}, + "south": {"uv": [83, 318], "uv_size": [0, 16]}, + "west": {"uv": [73, 317], "uv_size": [10, -16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10]}, + "down": {"uv": [73, 318], "uv_size": [0, -10]} + } + }, + { + "origin": [-13.6, -15, 18.5], + "size": [10, 16, 0], + "uv": { + "north": {"uv": [62, 317], "uv_size": [10, -16]}, + "east": {"uv": [73, 318], "uv_size": [0, 16]}, + "south": {"uv": [72, 317], "uv_size": [-10, -16]}, + "west": {"uv": [83, 318], "uv_size": [0, 16]}, + "up": {"uv": [73, 308], "uv_size": [0, 10], "uv_rotation": 90}, + "down": {"uv": [73, 318], "uv_size": [0, -10], "uv_rotation": 270} + } + } + ] + }, + { + "name": "lMissleLaunch", + "parent": "sled", + "pivot": [15, 26, 0], + "cubes": [ + { + "origin": [12, 20, -14], + "size": [6, 7, 15], + "pivot": [15, 26, 0], + "rotation": [-40, 0, 0], + "uv": { + "north": {"uv": [260, 108], "uv_size": [6, 7]}, + "east": {"uv": [245, 108], "uv_size": [15, 7]}, + "south": {"uv": [281, 108], "uv_size": [6, 7]}, + "west": {"uv": [266, 108], "uv_size": [15, 7]}, + "up": {"uv": [260, 93], "uv_size": [6, 15]}, + "down": {"uv": [266, 108], "uv_size": [6, -15]} + } + } + ] + }, + { + "name": "rMissleLaunch2", + "parent": "sled", + "pivot": [-14, 26, 0], + "cubes": [ + { + "origin": [-17, 20, -14], + "size": [6, 7, 15], + "pivot": [-14, 26, 0], + "rotation": [-40, 0, 0], + "uv": { + "north": {"uv": [175, 257], "uv_size": [6, 7]}, + "east": {"uv": [160, 257], "uv_size": [15, 7]}, + "south": {"uv": [196, 257], "uv_size": [6, 7]}, + "west": {"uv": [181, 257], "uv_size": [15, 7]}, + "up": {"uv": [175, 242], "uv_size": [6, 15]}, + "down": {"uv": [181, 257], "uv_size": [6, -15]} + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/entity/marauder.geo.json b/common/src/main/resources/assets/azurelib/geo/entity/marauder.geo.json new file mode 100644 index 000000000..2cd28b0b0 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/entity/marauder.geo.json @@ -0,0 +1,4168 @@ +{ + "format_version": "1.21.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 512, + "texture_height": 128, + "visible_bounds_width": 14, + "visible_bounds_height": 8, + "visible_bounds_offset": [0, 2, 0] + }, + "bones": [ + { + "name": "dreadnought", + "pivot": [0, 0, 0] + }, + { + "name": "body2", + "parent": "dreadnought", + "pivot": [0, 21, 0] + }, + { + "name": "torso", + "parent": "body2", + "pivot": [0, 21, 0], + "cubes": [ + { + "origin": [-4, 19, -2], + "size": [8, 7, 4], + "uv": { + "north": {"uv": [411, 18], "uv_size": [8, 7]}, + "east": {"uv": [384, 55], "uv_size": [4, 7]}, + "south": {"uv": [411, 25], "uv_size": [8, 7]}, + "west": {"uv": [423, 55], "uv_size": [4, 7]}, + "up": {"uv": [438, 27], "uv_size": [8, 4]}, + "down": {"uv": [439, 49], "uv_size": [8, -4]} + } + }, + { + "origin": [-4, 22.25, -2], + "size": [8, 2, 4], + "inflate": 0.25, + "uv": { + "north": {"uv": [451, 33], "uv_size": [8, 2]}, + "east": {"uv": [456, 45], "uv_size": [4, 2]}, + "south": {"uv": [451, 43], "uv_size": [8, 2]}, + "west": {"uv": [456, 47], "uv_size": [4, 2]} + } + } + ] + }, + { + "name": "upper_torso", + "parent": "torso", + "pivot": [0, 25, 0], + "cubes": [ + { + "origin": [-5.5, 25, -2.5], + "size": [11, 9, 5], + "uv": { + "north": {"uv": [403, 0], "uv_size": [11, 9]}, + "east": {"uv": [423, 35], "uv_size": [5, 9]}, + "south": {"uv": [403, 9], "uv_size": [11, 9]}, + "west": {"uv": [425, 0], "uv_size": [5, 9]}, + "up": {"uv": [414, 0], "uv_size": [11, 5]}, + "down": {"uv": [414, 10], "uv_size": [11, -5]} + } + }, + { + "origin": [-2, 34, -2], + "size": [4, 2, 4], + "uv": { + "north": {"uv": [430, 7], "uv_size": [4, 2]}, + "east": {"uv": [446, 29], "uv_size": [4, 2]}, + "south": {"uv": [457, 25], "uv_size": [4, 2]}, + "west": {"uv": [457, 27], "uv_size": [4, 2]}, + "up": {"uv": [449, 9], "uv_size": [4, 4]}, + "down": {"uv": [395, 69], "uv_size": [4, -4]} + } + }, + { + "origin": [0, 27, -2.75], + "size": [6, 7, 5.5], + "inflate": 0.01, + "pivot": [3, 30, 0], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [428, 9], "uv_size": [6, 7]}, + "east": {"uv": [430, 0], "uv_size": [6, 7]}, + "south": {"uv": [427, 46], "uv_size": [6, 7]}, + "west": {"uv": [431, 16], "uv_size": [6, 7]}, + "up": {"uv": [433, 41], "uv_size": [6, 6]}, + "down": {"uv": [433, 53], "uv_size": [6, -6]} + } + }, + { + "origin": [1.75, 29, -2.85], + "size": [3, 3, 0], + "inflate": 0.01, + "uv": { + "north": {"uv": [387, 79], "uv_size": [-3, 3]}, + "east": {"uv": [430, 0], "uv_size": [6, 7]}, + "south": {"uv": [384, 79], "uv_size": [3, 3]}, + "west": {"uv": [431, 16], "uv_size": [6, 7]}, + "up": {"uv": [433, 41], "uv_size": [6, 6]}, + "down": {"uv": [433, 53], "uv_size": [6, -6]} + } + }, + { + "origin": [-6.77164, 29.14805, -2.75], + "size": [7, 2, 0], + "pivot": [0.22836, 31.14805, -2.75], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [438, 29], "uv_size": [-7, 2]}, + "east": {"uv": [384, 0], "uv_size": [0, 2]}, + "south": {"uv": [431, 29], "uv_size": [7, 2]}, + "west": {"uv": [384, 0], "uv_size": [0, 2]}, + "up": {"uv": [384, 0], "uv_size": [7, 0]}, + "down": {"uv": [384, 0], "uv_size": [7, 0]} + } + }, + { + "origin": [-3.39104, 29.23463, -3], + "size": [2, 4, 6], + "pivot": [-4.39104, 29.23463, -2.75], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [393, 72], "uv_size": [2, 4]}, + "east": {"uv": [395, 61], "uv_size": [6, 4]}, + "south": {"uv": [410, 72], "uv_size": [2, 4]}, + "west": {"uv": [445, 31], "uv_size": [6, 4]}, + "up": {"uv": [436, 0], "uv_size": [2, 6]}, + "down": {"uv": [410, 68], "uv_size": [2, -6]} + } + }, + { + "origin": [-3.89104, 31.73463, -2.75], + "size": [3, 3, 5.5], + "pivot": [-4.39104, 29.23463, -2.75], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [455, 49], "uv_size": [3, 3]}, + "east": {"uv": [447, 54], "uv_size": [6, 3]}, + "south": {"uv": [456, 13], "uv_size": [3, 3]}, + "west": {"uv": [448, 0], "uv_size": [6, 3]}, + "up": {"uv": [396, 50], "uv_size": [3, 6]}, + "down": {"uv": [449, 9], "uv_size": [3, -6]} + } + } + ] + }, + { + "name": "h_head_furious", + "parent": "upper_torso", + "pivot": [0, 35, 0], + "cubes": [ + { + "origin": [-3.5, 34.5, -4], + "size": [7, 4, 4], + "inflate": 0.25, + "pivot": [0, 37.5, -2], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [442, 5], "uv_size": [7, 4]}, + "east": {"uv": [449, 13], "uv_size": [4, 4]}, + "south": {"uv": [442, 9], "uv_size": [7, 4]}, + "west": {"uv": [449, 17], "uv_size": [4, 4]}, + "up": {"uv": [442, 13], "uv_size": [7, 4]}, + "down": {"uv": [442, 21], "uv_size": [7, -4]} + } + }, + { + "origin": [-3.5, 35, -3.5], + "size": [7, 7, 7], + "uv": { + "north": {"uv": [414, 10], "uv_size": [7, 7]}, + "east": {"uv": [389, 34], "uv_size": [7, 7]}, + "south": {"uv": [396, 34], "uv_size": [7, 7]}, + "west": {"uv": [419, 17], "uv_size": [7, 7]}, + "up": {"uv": [419, 24], "uv_size": [7, 7]}, + "down": {"uv": [421, 17], "uv_size": [7, -7]} + } + }, + { + "origin": [-0.1, 39.75, -5.25], + "size": [0.1, 2, 2], + "pivot": [0, 40, -3.5], + "rotation": [-45, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 2]}, + "east": {"uv": [446, 72], "uv_size": [-2, 2]}, + "south": {"uv": [384, 0], "uv_size": [0, 2]}, + "west": {"uv": [444, 72], "uv_size": [2, 2]}, + "up": {"uv": [384, 0], "uv_size": [0, 2]}, + "down": {"uv": [384, 2], "uv_size": [0, -2]} + } + }, + { + "origin": [-0.1, 42, -2.5], + "size": [0.1, 2, 2], + "pivot": [0, 42, -2.5], + "rotation": [-45, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 2]}, + "east": {"uv": [448, 72], "uv_size": [-2, 2]}, + "south": {"uv": [384, 0], "uv_size": [0, 2]}, + "west": {"uv": [446, 72], "uv_size": [2, 2]}, + "up": {"uv": [384, 0], "uv_size": [0, 2]}, + "down": {"uv": [384, 2], "uv_size": [0, -2]} + } + }, + { + "origin": [3.5, 38.5, -7.5], + "size": [3, 0.1, 11], + "pivot": [3.5, 38.501, 0.5], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [3, 0]}, + "east": {"uv": [384, 0], "uv_size": [9, 0]}, + "south": {"uv": [384, 0], "uv_size": [3, 0]}, + "west": {"uv": [384, 0], "uv_size": [9, 0]}, + "up": {"uv": [509, 0], "uv_size": [3, 11]}, + "down": {"uv": [509, 11], "uv_size": [3, -11]} + } + }, + { + "origin": [-6.5, 38.5, -7.5], + "size": [3, 0.1, 11], + "pivot": [-3.5, 38.501, 0.5], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [387, 0], "uv_size": [-3, 0]}, + "east": {"uv": [393, 0], "uv_size": [-9, 0]}, + "south": {"uv": [387, 0], "uv_size": [-3, 0]}, + "west": {"uv": [393, 0], "uv_size": [-9, 0]}, + "up": {"uv": [512, 0], "uv_size": [-3, 11]}, + "down": {"uv": [512, 11], "uv_size": [-3, -11]} + } + }, + { + "origin": [0, 34.25, -5.32843], + "size": [4, 4, 3], + "pivot": [0, 38.25, -5.32843], + "rotation": [0, -22.5, 0], + "uv": { + "north": {"uv": [423, 65], "uv_size": [4, 4]}, + "east": {"uv": [453, 25], "uv_size": [3, 4]}, + "south": {"uv": [449, 57], "uv_size": [4, 4]}, + "west": {"uv": [451, 69], "uv_size": [3, 4]}, + "up": {"uv": [454, 0], "uv_size": [4, 3]}, + "down": {"uv": [454, 38], "uv_size": [4, -3]} + } + }, + { + "origin": [-4, 34.25, -5.32843], + "size": [4, 4, 3], + "pivot": [0, 38.25, -5.32843], + "rotation": [0, 22.5, 0], + "uv": { + "north": {"uv": [427, 65], "uv_size": [-4, 4]}, + "east": {"uv": [454, 69], "uv_size": [-3, 4]}, + "south": {"uv": [453, 57], "uv_size": [-4, 4]}, + "west": {"uv": [456, 25], "uv_size": [-3, 4]}, + "up": {"uv": [458, 0], "uv_size": [-4, 3]}, + "down": {"uv": [458, 38], "uv_size": [-4, -3]} + } + } + ] + }, + { + "name": "eyes_attack", + "parent": "h_head_furious", + "pivot": [-2.9, 38.25, -3.6], + "cubes": [ + { + "origin": [-3.4, 38.25, -3.6], + "size": [2.5, 2, 0.1], + "pivot": [-2.9, 38.25, -3.6], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [454, 12], "uv_size": [-1, 2]}, + "east": {"uv": [426, 17], "uv_size": [-7, 7]}, + "south": {"uv": [454, 12], "uv_size": [-1, 2]}, + "west": {"uv": [396, 34], "uv_size": [-7, 7]}, + "up": {"uv": [426, 24], "uv_size": [-7, 7]}, + "down": {"uv": [428, 17], "uv_size": [-7, -7]} + } + }, + { + "origin": [0.9, 38.25, -3.6], + "size": [2.5, 2, 0.1], + "pivot": [2.9, 38.25, -3.6], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [453, 12], "uv_size": [1, 2]}, + "east": {"uv": [389, 34], "uv_size": [7, 7]}, + "south": {"uv": [453, 12], "uv_size": [1, 2]}, + "west": {"uv": [419, 17], "uv_size": [7, 7]}, + "up": {"uv": [419, 24], "uv_size": [7, 7]}, + "down": {"uv": [421, 17], "uv_size": [7, -7]} + } + }, + { + "origin": [1.4, 38.25, -3.8], + "size": [1, 1, 0.1], + "uv": { + "north": {"uv": [451, 126], "uv_size": [1, 2]}, + "east": {"uv": [389, 34], "uv_size": [7, 7]}, + "south": {"uv": [393, 15], "uv_size": [1, 2]}, + "west": {"uv": [419, 17], "uv_size": [7, 7]}, + "up": {"uv": [419, 24], "uv_size": [7, 7]}, + "down": {"uv": [421, 17], "uv_size": [7, -7]} + } + }, + { + "origin": [-2.4, 38.25, -3.8], + "size": [1, 1, 0.1], + "uv": { + "north": {"uv": [452, 126], "uv_size": [-1, 2]}, + "east": {"uv": [426, 17], "uv_size": [-7, 7]}, + "south": {"uv": [394, 15], "uv_size": [-1, 2]}, + "west": {"uv": [396, 34], "uv_size": [-7, 7]}, + "up": {"uv": [426, 24], "uv_size": [-7, 7]}, + "down": {"uv": [428, 17], "uv_size": [-7, -7]} + } + } + ] + }, + { + "name": "eyes_normal", + "parent": "h_head_furious", + "pivot": [-2.9, 38.25, -3.6], + "cubes": [ + { + "origin": [-3.4, 38.25, -3.6], + "size": [2.5, 2, 0.1], + "pivot": [-2.9, 38.25, -3.6], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [456, 13], "uv_size": [-2, 2]}, + "east": {"uv": [426, 17], "uv_size": [-7, 7]}, + "south": {"uv": [456, 13], "uv_size": [-2, 2]}, + "west": {"uv": [396, 34], "uv_size": [-7, 7]}, + "up": {"uv": [426, 24], "uv_size": [-7, 7]}, + "down": {"uv": [428, 17], "uv_size": [-7, -7]} + } + }, + { + "origin": [0.9, 38.25, -3.6], + "size": [2.5, 2, 0.1], + "pivot": [2.9, 38.25, -3.6], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [456, 13], "uv_size": [-2, 2]}, + "east": {"uv": [389, 34], "uv_size": [7, 7]}, + "south": {"uv": [456, 13], "uv_size": [-2, 2]}, + "west": {"uv": [419, 17], "uv_size": [7, 7]}, + "up": {"uv": [419, 24], "uv_size": [7, 7]}, + "down": {"uv": [421, 17], "uv_size": [7, -7]} + } + }, + { + "origin": [-2.4, 38.25, -3.8], + "size": [1, 1, 0.1], + "uv": { + "north": {"uv": [454, 12], "uv_size": [-1, 2]}, + "east": {"uv": [454, 12], "uv_size": [-1, 2]}, + "south": {"uv": [454, 12], "uv_size": [-1, 2]}, + "west": {"uv": [454, 12], "uv_size": [-1, 2]}, + "up": {"uv": [453, 14], "uv_size": [1, -2]}, + "down": {"uv": [428, 17], "uv_size": [-7, -7]} + } + }, + { + "origin": [1.4, 38.25, -3.8], + "size": [1, 1, 0.1], + "uv": { + "north": {"uv": [454, 12], "uv_size": [-1, 2]}, + "east": {"uv": [454, 12], "uv_size": [-1, 2]}, + "south": {"uv": [454, 12], "uv_size": [-1, 2]}, + "west": {"uv": [454, 12], "uv_size": [-1, 2]}, + "up": {"uv": [453, 14], "uv_size": [1, -2]}, + "down": {"uv": [421, 17], "uv_size": [7, -7]} + } + } + ] + }, + { + "name": "h_left_horn_furious", + "parent": "h_head_furious", + "pivot": [0, 40.5, 0], + "rotation": [60, -15, -15], + "cubes": [ + { + "origin": [1.5, 41, -3], + "size": [3, 5, 3], + "pivot": [2.5, 42.5, -1.5], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [427, 65], "uv_size": [3, 5]}, + "east": {"uv": [388, 68], "uv_size": [3, 5]}, + "south": {"uv": [453, 7], "uv_size": [3, 5]}, + "west": {"uv": [395, 69], "uv_size": [3, 5]}, + "up": {"uv": [398, 72], "uv_size": [3, 3]}, + "down": {"uv": [401, 75], "uv_size": [3, -3]} + } + }, + { + "origin": [3.18715, 44.96821, -2.5], + "size": [2, 5, 2], + "pivot": [5.68715, 44.96821, -3], + "rotation": [-22.5, 0, 0], + "uv": { + "north": {"uv": [455, 38], "uv_size": [2, 5]}, + "east": {"uv": [440, 71], "uv_size": [2, 5]}, + "south": {"uv": [442, 71], "uv_size": [2, 5]}, + "west": {"uv": [384, 72], "uv_size": [2, 5]}, + "up": {"uv": [456, 64], "uv_size": [2, 2]}, + "down": {"uv": [456, 68], "uv_size": [2, -2]} + } + }, + { + "origin": [4.08715, 47.39627, -0.62464], + "size": [0.1, 2, 5], + "pivot": [4.18715, 49.39627, -0.62464], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 5]}, + "east": {"uv": [394, 79], "uv_size": [-5, -2], "uv_rotation": 90}, + "south": {"uv": [384, 0], "uv_size": [0, 5]}, + "west": {"uv": [389, 79], "uv_size": [5, -2], "uv_rotation": 90}, + "up": {"uv": [384, 0], "uv_size": [0, 2]}, + "down": {"uv": [384, 2], "uv_size": [0, -2]} + } + } + ] + }, + { + "name": "h_right_horn_furious", + "parent": "h_head_furious", + "pivot": [0, 40.5, 0], + "rotation": [60, 15, 15], + "cubes": [ + { + "origin": [-4.5, 41, -3], + "size": [3, 5, 3], + "pivot": [-2.5, 42.5, -1.5], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [430, 65], "uv_size": [-3, 5]}, + "east": {"uv": [398, 69], "uv_size": [-3, 5]}, + "south": {"uv": [456, 7], "uv_size": [-3, 5]}, + "west": {"uv": [391, 68], "uv_size": [-3, 5]}, + "up": {"uv": [401, 72], "uv_size": [-3, 3]}, + "down": {"uv": [404, 75], "uv_size": [-3, -3]} + } + }, + { + "origin": [-5.18715, 44.96821, -2.5], + "size": [2, 5, 2], + "pivot": [-5.68715, 44.96821, -3], + "rotation": [-22.5, 0, 0], + "uv": { + "north": {"uv": [391, 123], "uv_size": [2, 5]}, + "east": {"uv": [393, 123], "uv_size": [2, 5]}, + "south": {"uv": [389, 123], "uv_size": [2, 5]}, + "west": {"uv": [395, 123], "uv_size": [2, 5]}, + "up": {"uv": [391, 123], "uv_size": [-2, -2]}, + "down": {"uv": [393, 123], "uv_size": [-2, -2]} + } + }, + { + "origin": [-4.28715, 47.39627, -0.62464], + "size": [0.1, 2, 5], + "pivot": [-4.18715, 49.39627, -0.62464], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [395, 85], "uv_size": [-5, -2], "uv_rotation": 90}, + "east": {"uv": [394, 79], "uv_size": [-5, -2], "uv_rotation": 90}, + "south": {"uv": [395, 85], "uv_size": [-5, -2], "uv_rotation": 90}, + "west": {"uv": [389, 79], "uv_size": [5, -2], "uv_rotation": 90}, + "up": {"uv": [390, 83], "uv_size": [5, 2], "uv_rotation": 90}, + "down": {"uv": [390, 83], "uv_size": [5, 2], "uv_rotation": 90} + } + } + ] + }, + { + "name": "left_arm", + "parent": "upper_torso", + "pivot": [6, 32.5, 0], + "rotation": [0, 0, -22.5], + "cubes": [ + { + "origin": [4, 26, -2], + "size": [5, 9, 4], + "uv": { + "north": {"uv": [389, 41], "uv_size": [5, 9]}, + "east": {"uv": [388, 50], "uv_size": [4, 9]}, + "south": {"uv": [394, 41], "uv_size": [5, 9]}, + "west": {"uv": [434, 7], "uv_size": [4, 9]}, + "up": {"uv": [446, 41], "uv_size": [5, 4]}, + "down": {"uv": [436, 66], "uv_size": [5, -4]} + } + }, + { + "origin": [7, 30, -2], + "size": [4, 0.1, 4], + "pivot": [9, 29, 0], + "rotation": [0, -45, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [4, 0]}, + "east": {"uv": [384, 0], "uv_size": [4, 0]}, + "south": {"uv": [384, 0], "uv_size": [4, 0]}, + "west": {"uv": [384, 0], "uv_size": [4, 0]}, + "up": {"uv": [449, 61], "uv_size": [4, 4]}, + "down": {"uv": [449, 65], "uv_size": [4, -4]} + } + }, + { + "origin": [6.75, 29, -1.75], + "size": [4, 0.1, 4], + "pivot": [9, 29, 0], + "rotation": [0, -45, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [4, 0]}, + "east": {"uv": [384, 0], "uv_size": [4, 0]}, + "south": {"uv": [384, 0], "uv_size": [4, 0]}, + "west": {"uv": [384, 0], "uv_size": [4, 0]}, + "up": {"uv": [449, 61], "uv_size": [4, 4]}, + "down": {"uv": [449, 65], "uv_size": [4, -4]} + } + }, + { + "origin": [6.5, 28, -1.5], + "size": [4, 0.1, 4], + "pivot": [9, 29, 0], + "rotation": [0, -45, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [4, 0]}, + "east": {"uv": [384, 0], "uv_size": [4, 0]}, + "south": {"uv": [384, 0], "uv_size": [4, 0]}, + "west": {"uv": [384, 0], "uv_size": [4, 0]}, + "up": {"uv": [449, 61], "uv_size": [4, 4]}, + "down": {"uv": [449, 65], "uv_size": [4, -4]} + } + }, + { + "origin": [6, 31, -3], + "size": [4, 5, 6], + "uv": { + "north": {"uv": [441, 62], "uv_size": [4, 5]}, + "east": {"uv": [396, 56], "uv_size": [6, 5]}, + "south": {"uv": [401, 63], "uv_size": [4, 5]}, + "west": {"uv": [406, 57], "uv_size": [6, 5]}, + "up": {"uv": [445, 57], "uv_size": [4, 6]}, + "down": {"uv": [384, 68], "uv_size": [4, -6]} + } + }, + { + "origin": [10, 31, -2.5], + "size": [3, 0.1, 5], + "pivot": [10, 31, 0], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [384, 0], "uv_size": [3, 0]}, + "east": {"uv": [384, 0], "uv_size": [5, 0]}, + "south": {"uv": [384, 0], "uv_size": [3, 0]}, + "west": {"uv": [384, 0], "uv_size": [5, 0]}, + "up": {"uv": [423, 69], "uv_size": [3, 5]}, + "down": {"uv": [423, 74], "uv_size": [3, -5]} + } + }, + { + "origin": [8.9, 33, -3.5], + "size": [0.1, 6, 7], + "pivot": [9, 36, 0], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 6]}, + "east": {"uv": [438, 23], "uv_size": [-7, 6]}, + "south": {"uv": [384, 0], "uv_size": [0, 6]}, + "west": {"uv": [431, 23], "uv_size": [7, 6]}, + "up": {"uv": [384, 0], "uv_size": [0, 7]}, + "down": {"uv": [384, 7], "uv_size": [0, -7]} + } + } + ] + }, + { + "name": "left_elbow", + "parent": "left_arm", + "pivot": [6.5, 26, 1], + "rotation": [-22.5, 0, 0], + "cubes": [ + { + "origin": [4.5, 17, -2], + "size": [4, 9, 4], + "uv": { + "north": {"uv": [392, 50], "uv_size": [4, 9]}, + "east": {"uv": [413, 51], "uv_size": [4, 9]}, + "south": {"uv": [417, 51], "uv_size": [4, 9]}, + "west": {"uv": [427, 53], "uv_size": [4, 9]}, + "up": {"uv": [451, 49], "uv_size": [4, 4]}, + "down": {"uv": [440, 71], "uv_size": [4, -4]} + } + }, + { + "origin": [5.5, 24, 0.5], + "size": [2, 3, 2], + "uv": { + "north": {"uv": [476, 2], "uv_size": [-2, 3]}, + "east": {"uv": [474, 5], "uv_size": [-2, 3]}, + "south": {"uv": [476, 5], "uv_size": [-2, 3]}, + "west": {"uv": [474, 2], "uv_size": [-2, 3]}, + "up": {"uv": [478, 4], "uv_size": [2, -2]}, + "down": {"uv": [476, 4], "uv_size": [2, -2]} + } + } + ] + }, + { + "name": "hand_boomstick", + "parent": "left_elbow", + "pivot": [6.5, 20, -2], + "cubes": [ + { + "origin": [4.5, 5, -5], + "size": [4, 15, 3], + "uv": { + "north": {"uv": [403, 18], "uv_size": [4, 15]}, + "east": {"uv": [399, 41], "uv_size": [3, 15]}, + "south": {"uv": [407, 18], "uv_size": [4, 15]}, + "west": {"uv": [410, 42], "uv_size": [3, 15]}, + "up": {"uv": [426, 70], "uv_size": [4, 3]}, + "down": {"uv": [436, 73], "uv_size": [4, -3]} + } + }, + { + "origin": [6.75, 4, -5.25], + "size": [2, 13, 2], + "uv": { + "north": {"uv": [412, 60], "uv_size": [2, 13]}, + "east": {"uv": [414, 60], "uv_size": [2, 13]}, + "south": {"uv": [416, 60], "uv_size": [2, 13]}, + "west": {"uv": [418, 60], "uv_size": [2, 13]}, + "up": {"uv": [388, 73], "uv_size": [2, 2]}, + "down": {"uv": [412, 75], "uv_size": [2, -2]} + } + }, + { + "origin": [4.25, 4, -5.25], + "size": [2, 13, 2], + "uv": { + "north": {"uv": [414, 60], "uv_size": [-2, 13]}, + "east": {"uv": [420, 60], "uv_size": [-2, 13]}, + "south": {"uv": [418, 60], "uv_size": [-2, 13]}, + "west": {"uv": [416, 60], "uv_size": [-2, 13]}, + "up": {"uv": [390, 73], "uv_size": [-2, 2]}, + "down": {"uv": [414, 75], "uv_size": [-2, -2]} + } + }, + { + "origin": [5, 17.5, -4], + "size": [3, 3, 7], + "pivot": [6.5, 19, -3], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [456, 19], "uv_size": [3, 3]}, + "east": {"uv": [446, 26], "uv_size": [7, 3]}, + "south": {"uv": [404, 72], "uv_size": [3, 3]}, + "west": {"uv": [423, 62], "uv_size": [7, 3]}, + "up": {"uv": [430, 62], "uv_size": [3, 7]}, + "down": {"uv": [433, 69], "uv_size": [3, -7]} + } + } + ] + }, + { + "name": "right_arm", + "parent": "upper_torso", + "pivot": [-6, 32.5, 0], + "rotation": [0, 0, 22.5], + "cubes": [ + { + "origin": [-9, 26, -2], + "size": [5, 9, 4], + "uv": { + "north": {"uv": [426, 17], "uv_size": [5, 9]}, + "east": {"uv": [431, 53], "uv_size": [4, 9]}, + "south": {"uv": [413, 42], "uv_size": [5, 9]}, + "west": {"uv": [435, 53], "uv_size": [4, 9]}, + "up": {"uv": [447, 21], "uv_size": [5, 4]}, + "down": {"uv": [447, 49], "uv_size": [5, -4]} + } + }, + { + "origin": [-11, 28, -2], + "size": [4, 0.1, 4], + "pivot": [-9, 27, 0], + "rotation": [0, 45, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [4, 0]}, + "east": {"uv": [384, 0], "uv_size": [4, 0]}, + "south": {"uv": [384, 0], "uv_size": [4, 0]}, + "west": {"uv": [384, 0], "uv_size": [4, 0]}, + "up": {"uv": [452, 3], "uv_size": [4, 4]}, + "down": {"uv": [452, 7], "uv_size": [4, -4]} + } + }, + { + "origin": [-10, 29, -3], + "size": [4, 5, 6], + "uv": { + "north": {"uv": [445, 62], "uv_size": [-4, 5]}, + "east": {"uv": [412, 57], "uv_size": [-6, 5]}, + "south": {"uv": [405, 63], "uv_size": [-4, 5]}, + "west": {"uv": [402, 56], "uv_size": [-6, 5]}, + "up": {"uv": [449, 57], "uv_size": [-4, 6]}, + "down": {"uv": [388, 68], "uv_size": [-4, -6]} + } + }, + { + "origin": [-12, 29.41421, -2.5], + "size": [3, 0.1, 5], + "pivot": [-10, 30.41421, 0], + "rotation": [0, 0, 45], + "uv": { + "north": {"uv": [387, 0], "uv_size": [-3, 0]}, + "east": {"uv": [389, 0], "uv_size": [-5, 0]}, + "south": {"uv": [387, 0], "uv_size": [-3, 0]}, + "west": {"uv": [389, 0], "uv_size": [-5, 0]}, + "up": {"uv": [426, 69], "uv_size": [-3, 5]}, + "down": {"uv": [426, 74], "uv_size": [-3, -5]} + } + }, + { + "origin": [-10.1, 31.41421, -3.5], + "size": [0.1, 6, 7], + "pivot": [-9, 35.41421, 0], + "rotation": [0, 0, -45], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 6]}, + "east": {"uv": [438, 23], "uv_size": [-7, 6]}, + "south": {"uv": [384, 0], "uv_size": [0, 6]}, + "west": {"uv": [431, 23], "uv_size": [7, 6]}, + "up": {"uv": [384, 0], "uv_size": [0, 7]}, + "down": {"uv": [384, 7], "uv_size": [0, -7]} + } + } + ] + }, + { + "name": "right_elbow", + "parent": "right_arm", + "pivot": [-6.5, 26, 1], + "rotation": [-22.5, 0, 0], + "cubes": [ + { + "origin": [-8.5, 17, -2], + "size": [4, 9, 4], + "uv": { + "north": {"uv": [438, 0], "uv_size": [4, 9]}, + "east": {"uv": [438, 9], "uv_size": [4, 9]}, + "south": {"uv": [402, 54], "uv_size": [4, 9]}, + "west": {"uv": [438, 18], "uv_size": [4, 9]}, + "up": {"uv": [399, 68], "uv_size": [4, 4]}, + "down": {"uv": [403, 72], "uv_size": [4, -4]} + } + }, + { + "origin": [-7.5, 24, 0.5], + "size": [2, 3, 2], + "uv": { + "north": {"uv": [474, 2], "uv_size": [2, 3]}, + "east": {"uv": [472, 2], "uv_size": [2, 3]}, + "south": {"uv": [474, 5], "uv_size": [2, 3]}, + "west": {"uv": [472, 5], "uv_size": [2, 3]}, + "up": {"uv": [480, 4], "uv_size": [-2, -2]}, + "down": {"uv": [478, 4], "uv_size": [-2, -2]} + } + } + ] + }, + { + "name": "axe", + "parent": "right_elbow", + "pivot": [-6.5, 19, -1], + "rotation": [45, 45, -15], + "cubes": [ + { + "origin": [-6.6, 10.5, -32], + "size": [0.1, 17, 19], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 17]}, + "east": {"uv": [461, 111], "uv_size": [-19, 17]}, + "south": {"uv": [384, 0], "uv_size": [0, 17]}, + "west": {"uv": [442, 111], "uv_size": [19, 17]}, + "up": {"uv": [384, 0], "uv_size": [0, 19]}, + "down": {"uv": [384, 19], "uv_size": [0, -19]} + } + }, + { + "origin": [-7.5, 18, -26], + "size": [2, 2, 32], + "uv": { + "north": {"uv": [414, 73], "uv_size": [2, 2]}, + "east": {"uv": [421, 31], "uv_size": [24, 2]}, + "south": {"uv": [416, 73], "uv_size": [2, 2]}, + "west": {"uv": [421, 33], "uv_size": [24, 2]}, + "up": {"uv": [408, 33], "uv_size": [2, 24]}, + "down": {"uv": [421, 59], "uv_size": [2, -24]} + } + }, + { + "origin": [-7.5, 17.5, -31], + "size": [2, 3, 3], + "uv": { + "north": {"uv": [399, 65], "uv_size": [2, 3]}, + "east": {"uv": [456, 22], "uv_size": [3, 3]}, + "south": {"uv": [420, 72], "uv_size": [2, 3]}, + "west": {"uv": [407, 72], "uv_size": [3, 3]}, + "up": {"uv": [456, 52], "uv_size": [2, 3]}, + "down": {"uv": [456, 58], "uv_size": [2, -3]} + } + }, + { + "origin": [-6.5, 17.5, -32.5], + "size": [0, 4, 4], + "pivot": [-6.5, 19, -31], + "rotation": [-45, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 4]}, + "east": {"uv": [407, 68], "uv_size": [4, 4]}, + "south": {"uv": [384, 0], "uv_size": [0, 4]}, + "west": {"uv": [411, 68], "uv_size": [-4, 4]}, + "up": {"uv": [384, 0], "uv_size": [0, 4]}, + "down": {"uv": [384, 4], "uv_size": [0, -4]} + } + } + ] + }, + { + "name": "inactive_axe", + "parent": "right_elbow", + "pivot": [-6.5, 19, -1], + "rotation": [45, 45, -15], + "cubes": [ + { + "origin": [-7.5, 18, -26], + "size": [2, 2, 32], + "uv": { + "north": {"uv": [414, 73], "uv_size": [2, 2]}, + "east": {"uv": [421, 31], "uv_size": [24, 2]}, + "south": {"uv": [416, 73], "uv_size": [2, 2]}, + "west": {"uv": [421, 33], "uv_size": [24, 2]}, + "up": {"uv": [408, 33], "uv_size": [2, 24]}, + "down": {"uv": [421, 59], "uv_size": [2, -24]} + } + }, + { + "origin": [-7.5, 17.5, -29], + "size": [2, 3, 3], + "uv": { + "north": {"uv": [404, 75], "uv_size": [2, 3]}, + "east": {"uv": [459, 22], "uv_size": [3, 3]}, + "south": {"uv": [420, 75], "uv_size": [2, 3]}, + "west": {"uv": [407, 75], "uv_size": [3, 3]}, + "up": {"uv": [458, 52], "uv_size": [2, 3]}, + "down": {"uv": [458, 58], "uv_size": [2, -3]} + } + }, + { + "origin": [-6.5, 17.5, -30.5], + "size": [0, 4, 4], + "pivot": [-6.5, 19, -29], + "rotation": [-45, 0, 0], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 4]}, + "east": {"uv": [407, 68], "uv_size": [4, 4]}, + "south": {"uv": [384, 0], "uv_size": [0, 4]}, + "west": {"uv": [411, 68], "uv_size": [-4, 4]}, + "up": {"uv": [384, 0], "uv_size": [0, 4]}, + "down": {"uv": [384, 4], "uv_size": [0, -4]} + } + } + ] + }, + { + "name": "b_torso", + "parent": "torso", + "pivot": [0, 50, 0], + "cubes": [ + { + "origin": [-8, 16, -8], + "size": [16, 16, 16], + "uv": { + "north": {"uv": [384, 0], "uv_size": [16, 16]}, + "east": {"uv": [384, 0], "uv_size": [16, 16]}, + "south": {"uv": [384, 0], "uv_size": [16, 16]}, + "west": {"uv": [384, 0], "uv_size": [16, 16]}, + "up": {"uv": [400, 16], "uv_size": [-16, -16]}, + "down": {"uv": [400, 16], "uv_size": [-16, -16]} + } + } + ] + }, + { + "name": "b_head", + "parent": "torso", + "pivot": [0, 66, 0], + "cubes": [ + { + "origin": [-4, 32, -4], + "size": [8, 8, 8], + "uv": { + "north": {"uv": [384, 0], "uv_size": [8, 8]}, + "east": {"uv": [384, 0], "uv_size": [8, 8]}, + "south": {"uv": [384, 0], "uv_size": [8, 8]}, + "west": {"uv": [384, 0], "uv_size": [8, 8]}, + "up": {"uv": [392, 8], "uv_size": [-8, -8]}, + "down": {"uv": [392, 8], "uv_size": [-8, -8]} + } + } + ] + }, + { + "name": "left_leg", + "parent": "body2", + "pivot": [2.5, 21, 0], + "rotation": [0, -10, -5], + "cubes": [ + { + "origin": [0, 11, -2.5], + "size": [5, 10, 5], + "uv": { + "north": {"uv": [411, 32], "uv_size": [5, 10]}, + "east": {"uv": [416, 32], "uv_size": [5, 10]}, + "south": {"uv": [403, 33], "uv_size": [5, 10]}, + "west": {"uv": [384, 34], "uv_size": [5, 10]}, + "up": {"uv": [426, 26], "uv_size": [5, 5]}, + "down": {"uv": [442, 26], "uv_size": [5, -5]} + } + }, + { + "origin": [2, 17, -2.75], + "size": [3, 5, 0.1], + "pivot": [4, 18.5, -2.75], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [456, 53], "uv_size": [-3, 5]}, + "east": {"uv": [384, 0], "uv_size": [0, 5]}, + "south": {"uv": [453, 53], "uv_size": [3, 5]}, + "west": {"uv": [384, 0], "uv_size": [0, 5]}, + "up": {"uv": [384, 0], "uv_size": [3, 0]}, + "down": {"uv": [384, 0], "uv_size": [3, 0]} + } + }, + { + "origin": [2, 15, -2.75], + "size": [3, 4, 0.1], + "pivot": [4, 15.5, -2.75], + "rotation": [0, 0, 22.5], + "uv": { + "north": {"uv": [457, 68], "uv_size": [-3, 4]}, + "east": {"uv": [384, 0], "uv_size": [0, 4]}, + "south": {"uv": [454, 68], "uv_size": [3, 4]}, + "west": {"uv": [384, 0], "uv_size": [0, 4]}, + "up": {"uv": [384, 0], "uv_size": [3, 0]}, + "down": {"uv": [384, 0], "uv_size": [3, 0]} + } + } + ] + }, + { + "name": "left_knee", + "parent": "left_leg", + "pivot": [2.5, 11, -1.5], + "rotation": [5, 0, 0], + "cubes": [ + { + "origin": [0.5, 0, -2.5], + "size": [4, 11, 4], + "uv": { + "north": {"uv": [402, 43], "uv_size": [4, 11]}, + "east": {"uv": [384, 44], "uv_size": [4, 11]}, + "south": {"uv": [428, 35], "uv_size": [4, 11]}, + "west": {"uv": [423, 44], "uv_size": [4, 11]}, + "up": {"uv": [452, 45], "uv_size": [4, 4]}, + "down": {"uv": [444, 72], "uv_size": [4, -4]} + } + }, + { + "origin": [1, 8, -3.5], + "size": [3, 5, 2], + "uv": { + "north": {"uv": [453, 63], "uv_size": [3, 5]}, + "east": {"uv": [391, 72], "uv_size": [2, 5]}, + "south": {"uv": [448, 69], "uv_size": [3, 5]}, + "west": {"uv": [456, 8], "uv_size": [2, 5]}, + "up": {"uv": [453, 19], "uv_size": [3, 2]}, + "down": {"uv": [456, 60], "uv_size": [3, -2]} + } + } + ] + }, + { + "name": "leg_boomstick", + "parent": "left_leg", + "pivot": [6.5, 21, 0], + "cubes": [ + { + "origin": [5, 19, -0.5], + "size": [3, 3, 7], + "pivot": [6.5, 20.5, 0.5], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [456, 19], "uv_size": [3, 3]}, + "east": {"uv": [446, 26], "uv_size": [7, 3]}, + "south": {"uv": [404, 72], "uv_size": [3, 3]}, + "west": {"uv": [423, 62], "uv_size": [7, 3]}, + "up": {"uv": [430, 62], "uv_size": [3, 7]}, + "down": {"uv": [433, 69], "uv_size": [3, -7]} + } + }, + { + "origin": [4.5, 6.5, -1.5], + "size": [4, 15, 3], + "uv": { + "north": {"uv": [403, 18], "uv_size": [4, 15]}, + "east": {"uv": [399, 41], "uv_size": [3, 15]}, + "south": {"uv": [407, 18], "uv_size": [4, 15]}, + "west": {"uv": [410, 42], "uv_size": [3, 15]}, + "up": {"uv": [426, 70], "uv_size": [4, 3]}, + "down": {"uv": [436, 73], "uv_size": [4, -3]} + } + }, + { + "origin": [4.25, 5.5, -1.75], + "size": [2, 13, 2], + "uv": { + "north": {"uv": [414, 60], "uv_size": [-2, 13]}, + "east": {"uv": [420, 60], "uv_size": [-2, 13]}, + "south": {"uv": [418, 60], "uv_size": [-2, 13]}, + "west": {"uv": [416, 60], "uv_size": [-2, 13]}, + "up": {"uv": [390, 73], "uv_size": [-2, 2]}, + "down": {"uv": [414, 75], "uv_size": [-2, -2]} + } + }, + { + "origin": [6.75, 5.5, -1.75], + "size": [2, 13, 2], + "uv": { + "north": {"uv": [412, 60], "uv_size": [2, 13]}, + "east": {"uv": [414, 60], "uv_size": [2, 13]}, + "south": {"uv": [416, 60], "uv_size": [2, 13]}, + "west": {"uv": [418, 60], "uv_size": [2, 13]}, + "up": {"uv": [388, 73], "uv_size": [2, 2]}, + "down": {"uv": [412, 75], "uv_size": [2, -2]} + } + } + ] + }, + { + "name": "right_leg", + "parent": "body2", + "pivot": [-2.5, 21, 0], + "rotation": [0, 10, 5], + "cubes": [ + { + "origin": [-5, 11, -2.5], + "size": [5, 10, 5], + "uv": { + "north": {"uv": [416, 32], "uv_size": [-5, 10]}, + "east": {"uv": [389, 34], "uv_size": [-5, 10]}, + "south": {"uv": [408, 33], "uv_size": [-5, 10]}, + "west": {"uv": [421, 32], "uv_size": [-5, 10]}, + "up": {"uv": [431, 26], "uv_size": [-5, 5]}, + "down": {"uv": [447, 26], "uv_size": [-5, -5]} + } + }, + { + "origin": [-5, 17, -2.75], + "size": [3, 5, 0.1], + "pivot": [-4, 18.5, -2.75], + "rotation": [22.5, 0, 0], + "uv": { + "north": {"uv": [453, 53], "uv_size": [3, 5]}, + "east": {"uv": [384, 0], "uv_size": [0, 5]}, + "south": {"uv": [456, 53], "uv_size": [-3, 5]}, + "west": {"uv": [384, 0], "uv_size": [0, 5]}, + "up": {"uv": [387, 0], "uv_size": [-3, 0]}, + "down": {"uv": [387, 0], "uv_size": [-3, 0]} + } + }, + { + "origin": [-5, 15, -2.75], + "size": [3, 4, 0.1], + "pivot": [-4, 15.5, -2.75], + "rotation": [0, 0, -22.5], + "uv": { + "north": {"uv": [454, 68], "uv_size": [3, 4]}, + "east": {"uv": [384, 0], "uv_size": [0, 4]}, + "south": {"uv": [457, 68], "uv_size": [-3, 4]}, + "west": {"uv": [384, 0], "uv_size": [0, 4]}, + "up": {"uv": [387, 0], "uv_size": [-3, 0]}, + "down": {"uv": [387, 0], "uv_size": [-3, 0]} + } + } + ] + }, + { + "name": "right_knee", + "parent": "right_leg", + "pivot": [-2.5, 11, -1.5], + "rotation": [5, 0, 0], + "cubes": [ + { + "origin": [-4.5, 0, -2.5], + "size": [4, 11, 4], + "uv": { + "north": {"uv": [406, 43], "uv_size": [-4, 11]}, + "east": {"uv": [427, 44], "uv_size": [-4, 11]}, + "south": {"uv": [432, 35], "uv_size": [-4, 11]}, + "west": {"uv": [388, 44], "uv_size": [-4, 11]}, + "up": {"uv": [456, 45], "uv_size": [-4, 4]}, + "down": {"uv": [448, 72], "uv_size": [-4, -4]} + } + }, + { + "origin": [-4, 8, -3.5], + "size": [3, 5, 2], + "uv": { + "north": {"uv": [456, 63], "uv_size": [-3, 5]}, + "east": {"uv": [458, 8], "uv_size": [-2, 5]}, + "south": {"uv": [451, 69], "uv_size": [-3, 5]}, + "west": {"uv": [393, 72], "uv_size": [-2, 5]}, + "up": {"uv": [456, 19], "uv_size": [-3, 2]}, + "down": {"uv": [459, 60], "uv_size": [-3, -2]} + } + } + ] + }, + { + "name": "h_slash", + "parent": "body2", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash2", + "parent": "h_slash", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash3", + "parent": "h_slash2", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash4", + "parent": "h_slash3", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash5", + "parent": "h_slash4", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash6", + "parent": "h_slash5", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash7", + "parent": "h_slash6", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash8", + "parent": "h_slash7", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash9", + "parent": "h_slash8", + "pivot": [0, 24, -32] + }, + { + "name": "h_slash10", + "parent": "h_slash9", + "pivot": [0, 24, -32], + "cubes": [ + { + "origin": [-0.1, 10, -48], + "size": [0.1, 32, 32], + "uv": { + "north": {"uv": [384, 0], "uv_size": [0, 32]}, + "east": {"uv": [512, 96], "uv_size": [-32, 32]}, + "south": {"uv": [384, 0], "uv_size": [0, 32]}, + "west": {"uv": [480, 96], "uv_size": [32, 32]}, + "up": {"uv": [384, 32], "uv_size": [0, -32]}, + "down": {"uv": [384, 32], "uv_size": [0, -32]} + } + } + ] + }, + { + "name": "dreadnought_portal", + "pivot": [0, 0, 0] + }, + { + "name": "body", + "parent": "dreadnought_portal", + "pivot": [0, 0, 0] + }, + { + "name": "black", + "parent": "body", + "pivot": [0, 24, 0], + "cubes": [ + { + "origin": [-46, -22, 0], + "size": [92, 92, 0.1], + "uv": { + "north": {"uv": [128, 0], "uv_size": [128, 128]}, + "east": {"uv": [128, 0], "uv_size": [0, 32]}, + "south": {"uv": [256, 0], "uv_size": [-128, 128]}, + "west": {"uv": [128, 0], "uv_size": [0, 32]}, + "up": {"uv": [160, 0], "uv_size": [-32, 0]}, + "down": {"uv": [160, 0], "uv_size": [-32, 0]} + } + } + ] + }, + { + "name": "cluster1", + "parent": "body", + "pivot": [0, 24, 0] + }, + { + "name": "cloud1", + "parent": "cluster1", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud2", + "parent": "cluster1", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud3", + "parent": "cluster1", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud4", + "parent": "cluster1", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster2", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 10] + }, + { + "name": "cloud5", + "parent": "cluster2", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud6", + "parent": "cluster2", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud7", + "parent": "cluster2", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud8", + "parent": "cluster2", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud9", + "parent": "cluster2", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster3", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 22.5] + }, + { + "name": "cloud10", + "parent": "cluster3", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud11", + "parent": "cluster3", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud12", + "parent": "cluster3", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud13", + "parent": "cluster3", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster4", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 32.5] + }, + { + "name": "cloud14", + "parent": "cluster4", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud15", + "parent": "cluster4", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud16", + "parent": "cluster4", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud17", + "parent": "cluster4", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud18", + "parent": "cluster4", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster5", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 45] + }, + { + "name": "cloud19", + "parent": "cluster5", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud20", + "parent": "cluster5", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud21", + "parent": "cluster5", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud22", + "parent": "cluster5", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster6", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 55] + }, + { + "name": "cloud23", + "parent": "cluster6", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud24", + "parent": "cluster6", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud25", + "parent": "cluster6", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud26", + "parent": "cluster6", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud27", + "parent": "cluster6", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster7", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 67.5] + }, + { + "name": "cloud28", + "parent": "cluster7", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud29", + "parent": "cluster7", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud30", + "parent": "cluster7", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud31", + "parent": "cluster7", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster8", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 77.5] + }, + { + "name": "cloud32", + "parent": "cluster8", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud33", + "parent": "cluster8", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud34", + "parent": "cluster8", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud35", + "parent": "cluster8", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud36", + "parent": "cluster8", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster9", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 90] + }, + { + "name": "cloud37", + "parent": "cluster9", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud38", + "parent": "cluster9", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud39", + "parent": "cluster9", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud40", + "parent": "cluster9", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster10", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 100] + }, + { + "name": "cloud41", + "parent": "cluster10", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud42", + "parent": "cluster10", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud43", + "parent": "cluster10", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud44", + "parent": "cluster10", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud45", + "parent": "cluster10", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster11", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 112.5] + }, + { + "name": "cloud46", + "parent": "cluster11", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud47", + "parent": "cluster11", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud48", + "parent": "cluster11", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud49", + "parent": "cluster11", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster12", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 122.5] + }, + { + "name": "cloud50", + "parent": "cluster12", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud51", + "parent": "cluster12", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud52", + "parent": "cluster12", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud53", + "parent": "cluster12", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud54", + "parent": "cluster12", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster13", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 135] + }, + { + "name": "cloud55", + "parent": "cluster13", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud56", + "parent": "cluster13", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud57", + "parent": "cluster13", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud58", + "parent": "cluster13", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster14", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 145] + }, + { + "name": "cloud59", + "parent": "cluster14", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud60", + "parent": "cluster14", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud61", + "parent": "cluster14", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud62", + "parent": "cluster14", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud63", + "parent": "cluster14", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster15", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 157.5] + }, + { + "name": "cloud64", + "parent": "cluster15", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud65", + "parent": "cluster15", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud66", + "parent": "cluster15", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud67", + "parent": "cluster15", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster16", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, 167.5] + }, + { + "name": "cloud68", + "parent": "cluster16", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud69", + "parent": "cluster16", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud70", + "parent": "cluster16", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud71", + "parent": "cluster16", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud72", + "parent": "cluster16", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster17", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -180] + }, + { + "name": "cloud73", + "parent": "cluster17", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud74", + "parent": "cluster17", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud75", + "parent": "cluster17", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud76", + "parent": "cluster17", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster18", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -170] + }, + { + "name": "cloud77", + "parent": "cluster18", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud78", + "parent": "cluster18", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud79", + "parent": "cluster18", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud80", + "parent": "cluster18", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud81", + "parent": "cluster18", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster19", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -157.5] + }, + { + "name": "cloud82", + "parent": "cluster19", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud83", + "parent": "cluster19", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud84", + "parent": "cluster19", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud85", + "parent": "cluster19", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster20", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -147.5] + }, + { + "name": "cloud86", + "parent": "cluster20", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud87", + "parent": "cluster20", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud88", + "parent": "cluster20", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud89", + "parent": "cluster20", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud90", + "parent": "cluster20", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster21", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -135] + }, + { + "name": "cloud91", + "parent": "cluster21", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud92", + "parent": "cluster21", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud93", + "parent": "cluster21", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud94", + "parent": "cluster21", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster22", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -125] + }, + { + "name": "cloud95", + "parent": "cluster22", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud96", + "parent": "cluster22", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud97", + "parent": "cluster22", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud98", + "parent": "cluster22", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud99", + "parent": "cluster22", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster23", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -112.5] + }, + { + "name": "cloud100", + "parent": "cluster23", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud101", + "parent": "cluster23", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud102", + "parent": "cluster23", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud103", + "parent": "cluster23", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster24", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -102.5] + }, + { + "name": "cloud104", + "parent": "cluster24", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud105", + "parent": "cluster24", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud106", + "parent": "cluster24", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud107", + "parent": "cluster24", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud108", + "parent": "cluster24", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster25", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -90] + }, + { + "name": "cloud109", + "parent": "cluster25", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud110", + "parent": "cluster25", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud111", + "parent": "cluster25", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud112", + "parent": "cluster25", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster26", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -80] + }, + { + "name": "cloud113", + "parent": "cluster26", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud114", + "parent": "cluster26", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud115", + "parent": "cluster26", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud116", + "parent": "cluster26", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud117", + "parent": "cluster26", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster27", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -67.5] + }, + { + "name": "cloud118", + "parent": "cluster27", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud119", + "parent": "cluster27", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud120", + "parent": "cluster27", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud121", + "parent": "cluster27", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster28", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -57.5] + }, + { + "name": "cloud122", + "parent": "cluster28", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud123", + "parent": "cluster28", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud124", + "parent": "cluster28", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud125", + "parent": "cluster28", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud126", + "parent": "cluster28", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster29", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -45] + }, + { + "name": "cloud127", + "parent": "cluster29", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud128", + "parent": "cluster29", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud129", + "parent": "cluster29", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud130", + "parent": "cluster29", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster30", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -35] + }, + { + "name": "cloud131", + "parent": "cluster30", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud132", + "parent": "cluster30", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud133", + "parent": "cluster30", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud134", + "parent": "cluster30", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud135", + "parent": "cluster30", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cluster31", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -22.5] + }, + { + "name": "cloud136", + "parent": "cluster31", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [10, 48], "uv_size": [8, 8]}, + "east": {"uv": [34, 52], "uv_size": [8, 8]}, + "south": {"uv": [42, 52], "uv_size": [8, 8]}, + "west": {"uv": [50, 52], "uv_size": [8, 8]}, + "up": {"uv": [54, 42], "uv_size": [8, 8]}, + "down": {"uv": [10, 64], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud137", + "parent": "cluster31", + "pivot": [3, 64, 1], + "cubes": [ + { + "origin": [1, 62, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [56, 10], "uv_size": [8, 8]}, + "east": {"uv": [18, 56], "uv_size": [8, 8]}, + "south": {"uv": [56, 18], "uv_size": [8, 8]}, + "west": {"uv": [26, 56], "uv_size": [8, 8]}, + "up": {"uv": [56, 26], "uv_size": [8, 8]}, + "down": {"uv": [56, 42], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud138", + "parent": "cluster31", + "pivot": [3, 69, 0], + "cubes": [ + { + "origin": [0, 66, -3], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [0, 0], "uv_size": [12, 12]}, + "east": {"uv": [0, 12], "uv_size": [12, 12]}, + "south": {"uv": [12, 0], "uv_size": [12, 12]}, + "west": {"uv": [12, 12], "uv_size": [12, 12]}, + "up": {"uv": [0, 24], "uv_size": [12, 12]}, + "down": {"uv": [24, 12], "uv_size": [12, -12]} + } + } + ] + }, + { + "name": "cloud139", + "parent": "cluster31", + "pivot": [-2, 64, 0], + "cubes": [ + { + "origin": [-4.5, 61.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [36, 12], "uv_size": [10, 10]}, + "east": {"uv": [36, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 36], "uv_size": [10, 10]}, + "west": {"uv": [36, 32], "uv_size": [10, 10]}, + "up": {"uv": [34, 42], "uv_size": [10, 10]}, + "down": {"uv": [44, 52], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cluster32", + "parent": "body", + "pivot": [0, 24, 0], + "rotation": [0, 0, -12.5] + }, + { + "name": "cloud140", + "parent": "cluster32", + "pivot": [0, 67, 0], + "cubes": [ + { + "origin": [-2, 65, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [0, 58], "uv_size": [8, 8]}, + "east": {"uv": [58, 0], "uv_size": [8, 8]}, + "south": {"uv": [58, 50], "uv_size": [8, 8]}, + "west": {"uv": [58, 58], "uv_size": [8, 8]}, + "up": {"uv": [34, 60], "uv_size": [8, 8]}, + "down": {"uv": [42, 68], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud141", + "parent": "cluster32", + "pivot": [4, 65, 1], + "cubes": [ + { + "origin": [2, 63, -1], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [50, 60], "uv_size": [8, 8]}, + "east": {"uv": [62, 42], "uv_size": [8, 8]}, + "south": {"uv": [8, 64], "uv_size": [8, 8]}, + "west": {"uv": [64, 8], "uv_size": [8, 8]}, + "up": {"uv": [16, 64], "uv_size": [8, 8]}, + "down": {"uv": [64, 24], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud142", + "parent": "cluster32", + "pivot": [2, 70, -0.5], + "cubes": [ + { + "origin": [-0.5, 67.5, -2.5], + "size": [5, 5, 5], + "uv": { + "north": {"uv": [46, 12], "uv_size": [10, 10]}, + "east": {"uv": [46, 22], "uv_size": [10, 10]}, + "south": {"uv": [24, 46], "uv_size": [10, 10]}, + "west": {"uv": [46, 32], "uv_size": [10, 10]}, + "up": {"uv": [0, 48], "uv_size": [10, 10]}, + "down": {"uv": [48, 10], "uv_size": [10, -10]} + } + } + ] + }, + { + "name": "cloud143", + "parent": "cluster32", + "pivot": [6, 69, 0], + "cubes": [ + { + "origin": [4, 67, -2], + "size": [4, 4, 4], + "uv": { + "north": {"uv": [24, 64], "uv_size": [8, 8]}, + "east": {"uv": [64, 24], "uv_size": [8, 8]}, + "south": {"uv": [64, 32], "uv_size": [8, 8]}, + "west": {"uv": [0, 66], "uv_size": [8, 8]}, + "up": {"uv": [66, 0], "uv_size": [8, 8]}, + "down": {"uv": [66, 58], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "cloud144", + "parent": "cluster32", + "pivot": [0, 64, 0.5], + "cubes": [ + { + "origin": [-3, 61, -2.5], + "size": [6, 6, 6], + "uv": { + "north": {"uv": [12, 24], "uv_size": [12, 12]}, + "east": {"uv": [24, 12], "uv_size": [12, 12]}, + "south": {"uv": [24, 24], "uv_size": [12, 12]}, + "west": {"uv": [0, 36], "uv_size": [12, 12]}, + "up": {"uv": [36, 0], "uv_size": [12, 12]}, + "down": {"uv": [12, 48], "uv_size": [12, -12]} + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/entity/ovamorph.geo.json b/common/src/main/resources/assets/azurelib/geo/entity/ovamorph.geo.json new file mode 100644 index 000000000..269270839 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/entity/ovamorph.geo.json @@ -0,0 +1,113 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.Alien Egg", + "texture_width": 64, + "texture_height": 64, + "visible_bounds_width": 3, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [0, 0.75, 0] + }, + "bones": [ + { + "name": "gEgg", + "pivot": [0, 0, 0], + "rotation": [0, 45, 0] + }, + { + "name": "gEggWalls", + "parent": "gEgg", + "pivot": [-0.0729, 6.4, 0.0558], + "cubes": [ + {"origin": [-4.0729, -0.6, -3.9442], "size": [8, 9, 2], "inflate": -0.5, "uv": [40, 1]}, + {"origin": [-3.93148, -0.6, -3.9442], "size": [8, 9, 2], "inflate": -0.501, "pivot": [-0.00219, 6.4, -0.01491], "rotation": [0, -90, 0], "uv": [40, 1]}, + {"origin": [-3.93148, -0.6, -4.08562], "size": [8, 9, 2], "inflate": -0.5, "pivot": [-0.00219, 6.4, -0.01491], "rotation": [0, 180, 0], "uv": [40, 1]}, + {"origin": [-4.0729, -0.6, -4.08562], "size": [8, 9, 2], "inflate": -0.501, "pivot": [-0.00219, 6.4, -0.01491], "rotation": [0, 90, 0], "uv": [40, 1]}, + {"origin": [-4.0729, -0.6, -3.9442], "size": [8, 2, 8], "inflate": -0.49, "uv": [0, 14]} + ] + }, + { + "name": "gVeinBottom", + "parent": "gEgg", + "pivot": [-0.0729, 0, 0.0558], + "cubes": [ + {"origin": [-5.94868, 0.1, -5.57102], "size": [12, 0, 12], "uv": [3, 1]}, + {"origin": [-3.5729, 9.31832, -7.58432], "size": [7, 0, 3], "pivot": [-0.00219, 6.4, -0.01491], "rotation": [83.5, 0, 0], "uv": [-3, 10]}, + {"origin": [-3.53069, 9.25234, -7.60931], "size": [7, 0, 3], "pivot": [-0.00219, 6.4, -0.01491], "rotation": [0, 90, -81.5], "uv": [-3, 10], "mirror": true}, + {"origin": [-3.53148, 8.82918, -7.97539], "size": [7, 0, 3], "pivot": [-0.00219, 6.4, -0.01491], "rotation": [-103.5, 0, -180], "uv": [-3, 10]}, + {"origin": [-3.5737, 9.37573, -7.59086], "size": [7, 0, 3], "pivot": [-0.00219, 6.4, -0.01491], "rotation": [0, -90, 83.5], "uv": [-3, 10], "mirror": true} + ] + }, + { + "name": "gPetal1", + "parent": "gEgg", + "pivot": [2.00445, 6.8849, 0.0558], + "rotation": [0, 90, 0], + "cubes": [ + {"origin": [-4.49221, 6.5852, -0.73352], "size": [5, 3, 1], "inflate": 0.129, "pivot": [-0.00219, 6.4, -0.01491], "rotation": [176, 0, 180], "uv": [0, 0], "mirror": true} + ] + }, + { + "name": "gPetalTop1", + "parent": "gPetal1", + "pivot": [1.98316, 9.1958, 0.40465], + "cubes": [ + {"origin": [-2.19337, 7.04419, -3.15724], "size": [3, 3, 1], "inflate": 0.029, "pivot": [-0.00219, 6.4, -0.01491], "rotation": [121.19939, 41.03733, -158.31665], "uv": [0, 5], "mirror": true} + ] + }, + { + "name": "gPetal2", + "parent": "gEgg", + "pivot": [-2.15025, 6.8849, 0.0558], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-0.37076, 6.5852, -0.73352], "size": [5, 3, 1], "inflate": 0.129, "pivot": [-0.00219, 6.4, -0.01491], "rotation": [176, 0, -180], "uv": [0, 0]} + ] + }, + { + "name": "gPetalTop2", + "parent": "gPetal2", + "pivot": [-2.12896, 9.1958, 0.40465], + "cubes": [ + {"origin": [-0.71189, 7.14506, -3.15724], "size": [3, 3, 1], "inflate": 0.029, "pivot": [-0.00219, 6.4, -0.01491], "rotation": [121.19939, -41.03733, 158.31665], "uv": [0, 5]} + ] + }, + { + "name": "gPetal4", + "parent": "gEgg", + "pivot": [-0.0729, 6.8849, -2.02155], + "rotation": [-180, 0, 180], + "cubes": [ + {"origin": [-2.44811, 6.73011, 1.33877], "size": [5, 3, 1], "inflate": 0.129, "pivot": [-0.00219, 6.4, -0.01491], "rotation": [176, 0, -180], "uv": [0, 0]} + ] + }, + { + "name": "gPetalTop4", + "parent": "gPetal4", + "pivot": [-0.05161, 9.1958, -1.6727], + "cubes": [ + {"origin": [-3.53181, 7.00367, -2.34555], "size": [3, 3, 1], "inflate": 0.029, "pivot": [-0.00219, 6.4, -0.01491], "rotation": [121.19939, -41.03733, 158.31665], "uv": [0, 5]} + ] + }, + { + "name": "gPetal3", + "parent": "gEgg", + "pivot": [-0.0729, 6.8849, 2.13315], + "cubes": [ + {"origin": [-2.41486, 6.44029, -2.80581], "size": [5, 3, 1], "inflate": 0.129, "pivot": [-0.00219, 6.4, -0.01491], "rotation": [176, 0, 180], "uv": [0, 0], "mirror": true} + ] + }, + { + "name": "gPetalTop3", + "parent": "gPetal3", + "pivot": [-0.09419, 9.1958, 2.482], + "cubes": [ + {"origin": [-2.10122, 4.22223, -3.96893], "size": [3, 3, 1], "inflate": 0.029, "pivot": [-0.00219, 6.4, -0.01491], "rotation": [121.19939, 41.03733, -158.31665], "uv": [0, 5], "mirror": true} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/item/doomicorn.geo.json b/common/src/main/resources/assets/azurelib/geo/item/doomicorn.geo.json new file mode 100644 index 000000000..2f4ec1a72 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/item/doomicorn.geo.json @@ -0,0 +1,17113 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 64, + "texture_height": 64, + "visible_bounds_width": 4, + "visible_bounds_height": 4.5, + "visible_bounds_offset": [ + 0, + 1.75, + 0 + ] + }, + "bones": [ + { + "name": "bipedHead", + "pivot": [ + 0, + 24, + 0 + ] + }, + { + "name": "armorHead", + "parent": "bipedHead", + "pivot": [ + 0, + 24, + 0 + ] + }, + { + "name": "horn", + "parent": "armorHead", + "pivot": [ + 0, + 33, + -3 + ] + }, + { + "name": "group3", + "parent": "horn", + "pivot": [ + 8, + 34.7, + -12 + ], + "cubes": [ + { + "origin": [ + -0.75, + 38, + -5.75 + ], + "size": [ + 1.5, + 2, + 1.5 + ], + "pivot": [ + 0, + 38.7, + -5 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 25, + 23 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 25, + 23 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 24, + 24 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 24, + 25 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 24, + 25 + ], + "uv_size": [ + 1, + 1 + ] + } + } + }, + { + "origin": [ + -1, + 35, + -6 + ], + "size": [ + 2, + 3, + 2 + ], + "pivot": [ + 0, + 38.7, + -5 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 23, + 23 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 23, + 24 + ], + "uv_size": [ + 2, + 3 + ] + }, + "south": { + "uv": [ + 23, + 24 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 23, + 22 + ], + "uv_size": [ + 2, + 3 + ] + }, + "up": { + "uv": [ + 23, + 23 + ], + "uv_size": [ + 2, + 2 + ] + } + } + }, + { + "origin": [ + -0.4, + 40, + -5.4 + ], + "size": [ + 0.8, + 1.2, + 0.8 + ], + "pivot": [ + 0, + 38.7, + -5 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 24, + 23 + ], + "uv_size": [ + 0, + 1 + ] + }, + "east": { + "uv": [ + 25, + 25 + ], + "uv_size": [ + 0, + 1 + ] + }, + "south": { + "uv": [ + 25, + 25 + ], + "uv_size": [ + 0, + 1 + ] + }, + "west": { + "uv": [ + 25, + 23 + ], + "uv_size": [ + 0, + 1 + ] + }, + "up": { + "uv": [ + 26, + 26 + ], + "uv_size": [ + 0, + 0 + ] + } + } + } + ] + }, + { + "name": "bone2", + "parent": "horn", + "pivot": [ + 8, + 31.7, + -16.5 + ], + "cubes": [ + { + "origin": [ + -2.5, + 32.7, + -6 + ], + "size": [ + 5, + 3, + 7 + ], + "uv": { + "north": { + "uv": [ + 10, + 3 + ], + "uv_size": [ + 5, + 3 + ] + }, + "east": { + "uv": [ + 7, + 0 + ], + "uv_size": [ + -7, + 3 + ] + }, + "south": { + "uv": [ + 10, + 4 + ], + "uv_size": [ + 5, + 3 + ] + }, + "west": { + "uv": [ + 0, + 0 + ], + "uv_size": [ + 7, + 3 + ] + }, + "up": { + "uv": [ + 9, + 1 + ], + "uv_size": [ + 5, + 7 + ] + }, + "down": { + "uv": [ + 9, + 8 + ], + "uv_size": [ + 5, + -7 + ] + } + } + }, + { + "origin": [ + -0.5, + 35.7, + -2.3 + ], + "size": [ + 1, + 1.2, + 3.3 + ], + "uv": { + "north": { + "uv": [ + 21, + 23 + ], + "uv_size": [ + 5, + 3 + ] + }, + "east": { + "uv": [ + 23, + 24 + ], + "uv_size": [ + 3, + 3 + ] + }, + "south": { + "uv": [ + 22, + 23 + ], + "uv_size": [ + 5, + 3 + ] + }, + "west": { + "uv": [ + 22, + 23 + ], + "uv_size": [ + 5, + 3 + ] + }, + "up": { + "uv": [ + 22, + 22 + ], + "uv_size": [ + 4, + 5 + ] + } + } + }, + { + "origin": [ + -0.5, + 33, + -2.1 + ], + "size": [ + 1, + 2.2, + 5.5 + ], + "pivot": [ + -2.5, + 32.5, + 1.4 + ], + "rotation": [ + -47.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 21, + 23 + ], + "uv_size": [ + 5, + 3 + ] + }, + "east": { + "uv": [ + 23, + 24 + ], + "uv_size": [ + 3, + 3 + ] + }, + "west": { + "uv": [ + 22, + 23 + ], + "uv_size": [ + 5, + 3 + ] + } + } + }, + { + "origin": [ + 0.6, + 34.8, + -0.9 + ], + "size": [ + 1.8, + 2.8, + 0.8 + ], + "uv": { + "north": { + "uv": [ + 10, + 3 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 3 + ] + }, + "south": { + "uv": [ + 11, + 2 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 14, + 3 + ], + "uv_size": [ + 1, + 3 + ] + }, + "up": { + "uv": [ + 10, + 3 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + -2.4, + 34.8, + -0.9 + ], + "size": [ + 1.8, + 2.8, + 0.8 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 3 + ] + }, + "south": { + "uv": [ + 11, + 2 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 12, + 2 + ], + "uv_size": [ + 1, + 3 + ] + }, + "up": { + "uv": [ + 10, + 3 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + -2, + 32.7, + -8 + ], + "size": [ + 4, + 3, + 2 + ], + "uv": { + "north": { + "uv": [ + 10, + 3 + ], + "uv_size": [ + 4, + 3 + ] + }, + "east": { + "uv": [ + 12, + 3 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 12, + 2 + ], + "uv_size": [ + 2, + 3 + ] + }, + "up": { + "uv": [ + 11, + 4 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 10, + 5 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + -1, + 32.7, + 0.5 + ], + "size": [ + 2, + 1.9, + 2 + ], + "uv": { + "east": { + "uv": [ + 11, + 0 + ], + "uv_size": [ + 2, + 8 + ] + }, + "south": { + "uv": [ + 11, + 0 + ], + "uv_size": [ + 2, + 8 + ] + }, + "west": { + "uv": [ + 11, + 0 + ], + "uv_size": [ + 2, + 8 + ] + }, + "up": { + "uv": [ + 13, + 3 + ], + "uv_size": [ + 2, + 2 + ] + } + } + } + ] + }, + { + "name": "bone5", + "parent": "armorHead", + "pivot": [ + 0, + 0, + 0 + ], + "cubes": [ + { + "origin": [ + 2, + 24, + -5 + ], + "size": [ + 3, + 2, + 1 + ], + "uv": { + "north": { + "uv": [ + 46, + 14 + ], + "uv_size": [ + 3, + 2 + ] + }, + "west": { + "uv": [ + 48, + 14 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 41, + 14 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 46, + 16 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 24, + -5 + ], + "size": [ + 3, + 2, + 1 + ], + "uv": { + "north": { + "uv": [ + 39, + 14 + ], + "uv_size": [ + 3, + 2 + ] + }, + "east": { + "uv": [ + 39, + 14 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 41, + 14 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 39, + 16 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 26, + -5 + ], + "size": [ + 2, + 1, + 1 + ], + "uv": { + "north": { + "uv": [ + 39, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 39, + 13 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 39, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 41, + 14 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 27, + -5 + ], + "size": [ + 1, + 3, + 1 + ], + "uv": { + "north": { + "uv": [ + 39, + 10 + ], + "uv_size": [ + 1, + 3 + ] + }, + "east": { + "uv": [ + 39, + 10 + ], + "uv_size": [ + 1, + 3 + ] + }, + "west": { + "uv": [ + 39, + 10 + ], + "uv_size": [ + 1, + 3 + ] + } + } + }, + { + "origin": [ + 4, + 27, + -5 + ], + "size": [ + 1, + 3, + 1 + ], + "uv": { + "north": { + "uv": [ + 39, + 10 + ], + "uv_size": [ + 1, + 3 + ] + }, + "east": { + "uv": [ + 39, + 10 + ], + "uv_size": [ + 1, + 3 + ] + }, + "west": { + "uv": [ + 48, + 10 + ], + "uv_size": [ + 1, + 3 + ] + } + } + }, + { + "origin": [ + -5, + 30, + -5 + ], + "size": [ + 10, + 1, + 1 + ], + "uv": { + "north": { + "uv": [ + 39, + 9 + ], + "uv_size": [ + 10, + 1 + ] + }, + "east": { + "uv": [ + 39, + 9 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 48, + 9 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 49, + 10 + ], + "uv_size": [ + -10, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 31, + -5 + ], + "size": [ + 10, + 2, + 1 + ], + "uv": { + "north": { + "uv": [ + 59, + 8 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 59, + 8 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 59, + 8 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 61, + 9 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -2, + 29, + -5 + ], + "size": [ + 4, + 1, + 1 + ], + "uv": { + "north": { + "uv": [ + 42, + 10 + ], + "uv_size": [ + 4, + 1 + ] + }, + "east": { + "uv": [ + 42, + 10 + ], + "uv_size": [ + 4, + 1 + ] + }, + "west": { + "uv": [ + 42, + 10 + ], + "uv_size": [ + 4, + 1 + ] + }, + "down": { + "uv": [ + 46, + 11 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 3, + 26, + -5 + ], + "size": [ + 2, + 1, + 1 + ], + "uv": { + "north": { + "uv": [ + 47, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 39, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 48, + 13 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 49, + 14 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -2, + 24, + -5 + ], + "size": [ + 4, + 2, + 9 + ], + "uv": { + "north": { + "uv": [ + 42, + 14 + ], + "uv_size": [ + 4, + 2 + ] + }, + "up": { + "uv": [ + 41, + 14 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 46, + 16 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + -1, + 26, + -5 + ], + "size": [ + 2, + 1, + 1 + ], + "uv": { + "north": { + "uv": [ + 43, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 8, + 6 + ], + "uv_size": [ + 8, + 1 + ] + }, + "west": { + "uv": [ + 8, + 6 + ], + "uv_size": [ + 8, + 1 + ] + }, + "up": { + "uv": [ + 16, + 7 + ], + "uv_size": [ + -8, + -1 + ] + } + } + }, + { + "origin": [ + -4, + 27, + -4.5 + ], + "size": [ + 8, + 2, + 0.1 + ], + "uv": { + "north": { + "uv": [ + 40, + 11 + ], + "uv_size": [ + 8, + 2 + ] + }, + "south": { + "uv": [ + 42, + 11 + ], + "uv_size": [ + 4, + 2 + ] + } + } + }, + { + "origin": [ + 1, + 26, + -4.5 + ], + "size": [ + 2, + 1, + 0.1 + ], + "uv": { + "north": { + "uv": [ + 45, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 11 + ], + "uv_size": [ + 4, + 2 + ] + } + } + }, + { + "origin": [ + -3, + 26, + -4.5 + ], + "size": [ + 2, + 1, + 0.1 + ], + "uv": { + "north": { + "uv": [ + 41, + 13 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 11 + ], + "uv_size": [ + 4, + 2 + ] + } + } + }, + { + "origin": [ + -4, + 29, + -4.5 + ], + "size": [ + 2, + 1, + 0.1 + ], + "uv": { + "north": { + "uv": [ + 40, + 10 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 11 + ], + "uv_size": [ + 4, + 2 + ] + } + } + }, + { + "origin": [ + 2, + 29, + -4.5 + ], + "size": [ + 2, + 1, + 0.1 + ], + "uv": { + "north": { + "uv": [ + 46, + 10 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 11 + ], + "uv_size": [ + 4, + 2 + ] + } + } + }, + { + "origin": [ + -5, + 32, + -2 + ], + "size": [ + 10, + 1, + 6 + ], + "uv": { + "east": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "up": { + "uv": [ + 48, + 7 + ], + "uv_size": [ + -8, + -6 + ] + } + } + }, + { + "origin": [ + -5, + 32, + -4 + ], + "size": [ + 10, + 1, + 2 + ], + "uv": { + "east": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "up": { + "uv": [ + 11, + 6 + ], + "uv_size": [ + -3, + -5 + ] + } + } + }, + { + "origin": [ + -5, + 25, + 4 + ], + "size": [ + 10, + 1, + 1 + ], + "pivot": [ + 5, + 25, + 4 + ], + "rotation": [ + -90, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "east": { + "uv": [ + 54, + 15 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 54, + 15 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 59, + 16 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 33, + 4 + ], + "size": [ + 10, + 1, + 1 + ], + "pivot": [ + 5, + 33, + 4 + ], + "rotation": [ + -90, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "east": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "up": { + "uv": [ + 61, + 9 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 4, + 32, + 4 + ], + "size": [ + 1, + 1, + 7 + ], + "pivot": [ + 5, + 32, + 4 + ], + "rotation": [ + -90, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 57, + 15 + ], + "uv_size": [ + 7, + 1 + ] + }, + "up": { + "uv": [ + 58, + 16 + ], + "uv_size": [ + -1, + -7 + ] + } + } + }, + { + "origin": [ + -5, + 32, + 4 + ], + "size": [ + 1, + 1, + 7 + ], + "pivot": [ + -4, + 32, + 4 + ], + "rotation": [ + -90, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 8, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "east": { + "uv": [ + 57, + 15 + ], + "uv_size": [ + 7, + 1 + ] + }, + "up": { + "uv": [ + 63, + 16 + ], + "uv_size": [ + -1, + -7 + ] + } + } + }, + { + "origin": [ + -4, + 32, + 4 + ], + "size": [ + 8, + 1, + 7 + ], + "pivot": [ + 3.5, + 32, + 4 + ], + "rotation": [ + -90, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 40, + 1 + ], + "uv_size": [ + 3, + 5 + ] + }, + "up": { + "uv": [ + 63, + 16 + ], + "uv_size": [ + -6, + -7 + ] + } + } + }, + { + "origin": [ + 2, + 24, + -4 + ], + "size": [ + 3, + 6, + 7 + ], + "uv": { + "west": { + "uv": [ + 49, + 10 + ], + "uv_size": [ + 6, + 6 + ] + }, + "down": { + "uv": [ + 54, + 14 + ], + "uv_size": [ + -5, + -4 + ] + } + } + }, + { + "origin": [ + -5, + 24, + -4 + ], + "size": [ + 3, + 6, + 7 + ], + "uv": { + "east": { + "uv": [ + 32, + 10 + ], + "uv_size": [ + 7, + 6 + ] + }, + "down": { + "uv": [ + 49, + 14 + ], + "uv_size": [ + 5, + -4 + ] + } + } + }, + { + "origin": [ + 4, + 30, + -4 + ], + "size": [ + 1, + 2, + 7 + ], + "uv": { + "west": { + "uv": [ + 49, + 8 + ], + "uv_size": [ + 6, + 2 + ] + } + } + }, + { + "origin": [ + -5, + 30, + -4 + ], + "size": [ + 1, + 2, + 7 + ], + "uv": { + "east": { + "uv": [ + 55, + 8 + ], + "uv_size": [ + -6, + 2 + ] + } + } + }, + { + "origin": [ + 2, + 24, + 3 + ], + "size": [ + 3, + 6, + 1 + ], + "uv": { + "south": { + "uv": [ + 0, + 0 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 54, + 10 + ], + "uv_size": [ + 1, + 6 + ] + }, + "down": { + "uv": [ + 46, + 16 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -5, + 24, + 3 + ], + "size": [ + 3, + 6, + 1 + ], + "uv": { + "east": { + "uv": [ + 54, + 10 + ], + "uv_size": [ + 1, + 6 + ] + }, + "south": { + "uv": [ + 0, + 0 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 46, + 16 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + 4, + 30, + 3 + ], + "size": [ + 1, + 2, + 1 + ], + "uv": { + "west": { + "uv": [ + 54, + 10 + ], + "uv_size": [ + 1, + 2 + ] + } + } + }, + { + "origin": [ + -5, + 30, + 3 + ], + "size": [ + 1, + 2, + 1 + ], + "uv": { + "east": { + "uv": [ + 54, + 10 + ], + "uv_size": [ + 1, + 2 + ] + } + } + } + ] + }, + { + "name": "bipedBody", + "pivot": [ + 0, + 24, + 0 + ] + }, + { + "name": "armorBody", + "parent": "bipedBody", + "pivot": [ + 0, + 24, + 0 + ] + }, + { + "name": "bone", + "parent": "armorBody", + "pivot": [ + 0, + 21.3, + 3.1 + ] + }, + { + "name": "group", + "parent": "bone", + "pivot": [ + 0.10714, + 20.31429, + 3.4 + ], + "cubes": [ + { + "origin": [ + -0.35, + 20.5, + 2.3 + ], + "size": [ + 12.1, + 1.6, + 1.6 + ], + "inflate": 0.1, + "pivot": [ + 1.2, + 21.3, + 3.1 + ], + "rotation": [ + 0, + 0, + -22.5 + ], + "uv": { + "north": { + "uv": [ + 22, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 23, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 22, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 23, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 22, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 22, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 5.67, + 21.27, + 2.32 + ], + "size": [ + 7.56, + 1.56, + 1.56 + ], + "inflate": 0.06, + "pivot": [ + 7.2, + 21.3, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 21, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 10.155, + 23.505, + 2.305 + ], + "size": [ + 9.09, + 1.59, + 1.59 + ], + "inflate": 0.09, + "pivot": [ + 11.7, + 24.3, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 21, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 8.66, + 22.76, + 2.31 + ], + "size": [ + 9.08, + 1.58, + 1.58 + ], + "inflate": 0.08, + "pivot": [ + 10.2, + 22.8, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 21, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 2.68, + 19.78, + 2.33 + ], + "size": [ + 6.04, + 1.54, + 1.54 + ], + "inflate": 0.04, + "pivot": [ + 4.2, + 19.8, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 21, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 7.165, + 22.015, + 2.315 + ], + "size": [ + 7.57, + 1.57, + 1.57 + ], + "inflate": 0.07, + "pivot": [ + 8.7, + 21.3, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 20, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 4.175, + 20.525, + 2.325 + ], + "size": [ + 6.05, + 1.55, + 1.55 + ], + "inflate": 0.05, + "pivot": [ + 5.7, + 19.8, + 3.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 21, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + } + ] + }, + { + "name": "group2", + "parent": "bone", + "pivot": [ + -0.19286, + 20.31429, + 3.6 + ], + "rotation": [ + -180, + 0, + 180 + ], + "cubes": [ + { + "origin": [ + -0.65, + 20.5, + 3.3 + ], + "size": [ + 12.1, + 1.6, + 1.6 + ], + "inflate": 0.1, + "pivot": [ + 0.9, + 21.3, + 4.1 + ], + "rotation": [ + 0, + 0, + -22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 25, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 25, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 23, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 5.37, + 21.27, + 3.32 + ], + "size": [ + 7.56, + 1.56, + 1.56 + ], + "inflate": 0.06, + "pivot": [ + 6.9, + 21.3, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 23, + 23 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 21, + 24 + ], + "uv_size": [ + 5, + 1 + ] + }, + "down": { + "uv": [ + 22, + 25 + ], + "uv_size": [ + 5, + -1 + ] + } + } + }, + { + "origin": [ + 9.855, + 23.505, + 3.305 + ], + "size": [ + 9.09, + 1.59, + 1.59 + ], + "inflate": 0.09, + "pivot": [ + 11.4, + 24.3, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 26, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 23, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 8.36, + 22.76, + 3.31 + ], + "size": [ + 9.08, + 1.58, + 1.58 + ], + "inflate": 0.08, + "pivot": [ + 9.9, + 22.8, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 23, + 23 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 24, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 21, + 25 + ], + "uv_size": [ + 6, + -1 + ] + } + } + }, + { + "origin": [ + 2.38, + 19.78, + 3.33 + ], + "size": [ + 6.04, + 1.54, + 1.54 + ], + "inflate": 0.04, + "pivot": [ + 3.9, + 19.8, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 26, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 22, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "down": { + "uv": [ + 23, + 45 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 6.865, + 22.015, + 3.315 + ], + "size": [ + 7.57, + 1.57, + 1.57 + ], + "inflate": 0.07, + "pivot": [ + 8.4, + 21.3, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 23, + 23 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 24, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 21, + 25 + ], + "uv_size": [ + 5, + -1 + ] + } + } + }, + { + "origin": [ + 3.875, + 20.525, + 3.325 + ], + "size": [ + 6.05, + 1.55, + 1.55 + ], + "inflate": 0.05, + "pivot": [ + 5.4, + 19.8, + 4.1 + ], + "rotation": [ + 0, + 0, + 22.5 + ], + "uv": { + "north": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "east": { + "uv": [ + 23, + 25 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 23, + 43 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 25, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 22, + 24 + ], + "uv_size": [ + 4, + 1 + ] + }, + "down": { + "uv": [ + 22, + 25 + ], + "uv_size": [ + 4, + -1 + ] + } + } + } + ] + }, + { + "name": "bone3", + "parent": "armorBody", + "pivot": [ + 0, + 24, + 0 + ], + "cubes": [ + { + "origin": [ + -4, + 12, + -2 + ], + "size": [ + 8, + 12, + 4 + ], + "uv": { + "north": { + "uv": [ + 20, + 20 + ], + "uv_size": [ + 8, + 12 + ] + }, + "south": { + "uv": [ + 32, + 20 + ], + "uv_size": [ + 8, + 12 + ] + } + } + } + ] + }, + { + "name": "bone15", + "parent": "bone3", + "pivot": [ + 0, + 18, + -2.3 + ], + "cubes": [ + { + "origin": [ + -4.1, + 12, + -2.4 + ], + "size": [ + 8.2, + 3, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 20, + 45 + ], + "uv_size": [ + 8, + 3 + ] + }, + "east": { + "uv": [ + 20, + 45 + ], + "uv_size": [ + 1, + 3 + ] + }, + "west": { + "uv": [ + 27, + 45 + ], + "uv_size": [ + 1, + 3 + ] + }, + "up": { + "uv": [ + 20, + 38 + ], + "uv_size": [ + 8, + 1 + ] + }, + "down": { + "uv": [ + 20, + 47 + ], + "uv_size": [ + 8, + 1 + ] + } + } + }, + { + "origin": [ + -4.1, + 12, + 2.1 + ], + "size": [ + 8.2, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 8, + 1 + ] + }, + "east": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 8, + 1 + ] + }, + "west": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 40, + 48 + ], + "uv_size": [ + -8, + -1 + ] + }, + "down": { + "uv": [ + 40, + 48 + ], + "uv_size": [ + -8, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 13, + 2.1 + ], + "size": [ + 3.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 46 + ], + "uv_size": [ + -3, + 1 + ] + }, + "east": { + "uv": [ + 34, + 46 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 32, + 46 + ], + "uv_size": [ + 3, + 1 + ] + }, + "west": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 35, + 47 + ], + "uv_size": [ + -3, + -1 + ] + } + } + }, + { + "origin": [ + -4.1, + 13, + 2.1 + ], + "size": [ + 3.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 32, + 46 + ], + "uv_size": [ + 3, + 1 + ] + }, + "east": { + "uv": [ + 32, + 47 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + 3, + 1 + ] + }, + "west": { + "uv": [ + 34, + 46 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 40, + 47 + ], + "uv_size": [ + -3, + -1 + ] + } + } + }, + { + "origin": [ + -1, + 14, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -1, + 16, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 17, + 2.1 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -2, + 17, + 2.1 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 19, + 2.1 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 32, + 41 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 32, + 41 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 32, + 41 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 32, + 41 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 33, + 42 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1, + 18, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -4, + 20, + 2.1 + ], + "size": [ + 8.1, + 2, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 32, + 38 + ], + "uv_size": [ + 8, + 2 + ] + }, + "east": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 32, + 38 + ], + "uv_size": [ + 8, + 2 + ] + }, + "west": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 40, + 39 + ], + "uv_size": [ + -8, + -1 + ] + }, + "down": { + "uv": [ + 40, + 40 + ], + "uv_size": [ + -8, + -1 + ] + } + } + }, + { + "origin": [ + -2.1, + 23, + 2.1 + ], + "size": [ + 4.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 34, + 36 + ], + "uv_size": [ + 4, + 1 + ] + }, + "east": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 34, + 36 + ], + "uv_size": [ + 4, + 1 + ] + }, + "west": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + } + } + }, + { + "origin": [ + -3.1, + 22, + 2.1 + ], + "size": [ + 6.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 33, + 37 + ], + "uv_size": [ + 6, + 1 + ] + }, + "east": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 33, + 37 + ], + "uv_size": [ + 6, + 1 + ] + }, + "west": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + -6, + -1 + ] + } + } + }, + { + "origin": [ + -2, + 19, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 36, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 37, + 40 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 36, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 36, + 40 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 38, + 41 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 3, + 18, + 2.1 + ], + "size": [ + 1.1, + 2, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 32, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 32, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 32, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 33, + 42 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -4, + 18, + 2.1 + ], + "size": [ + 1.1, + 2, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 39, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 39, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 39, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 40, + 42 + ], + "uv_size": [ + -1, + -2 + ] + } + } + }, + { + "origin": [ + -3, + 15, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 38, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 37, + 44 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 39, + 45 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 15, + 2.1 + ], + "size": [ + 2.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 33, + 44 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 33, + 44 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 35, + 45 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 37, + 46 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -3.1, + 15, + -2.1 + ], + "size": [ + 6.2, + 2, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 6, + 2 + ] + }, + "east": { + "uv": [ + 26, + 43 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 26, + 43 + ], + "uv_size": [ + 1, + 2 + ] + } + } + }, + { + "origin": [ + -3.1, + 22, + -2.4 + ], + "size": [ + 6.2, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 21, + 37 + ], + "uv_size": [ + 6, + 1 + ] + }, + "east": { + "uv": [ + 21, + 37 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 21, + 37 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 27, + 38 + ], + "uv_size": [ + -6, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 23, + -2.4 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + } + } + }, + { + "origin": [ + 2, + 20, + -2.7 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 26, + 39 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 26, + 39 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 26, + 39 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 27, + 40 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 27, + 40 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -2.1, + 23, + -2.4 + ], + "size": [ + 1.1, + 1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 22, + 36 + ], + "uv_size": [ + 1, + 1 + ] + } + } + }, + { + "origin": [ + -4.1, + 17, + -2.4 + ], + "size": [ + 8.2, + 5, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 20, + 38 + ], + "uv_size": [ + 8, + 5 + ] + }, + "east": { + "uv": [ + 20, + 38 + ], + "uv_size": [ + 1, + 5 + ] + }, + "west": { + "uv": [ + 27, + 38 + ], + "uv_size": [ + 1, + 5 + ] + }, + "up": { + "uv": [ + 20, + 38 + ], + "uv_size": [ + 8, + 1 + ] + }, + "down": { + "uv": [ + 20, + 47 + ], + "uv_size": [ + 8, + 1 + ] + } + } + } + ] + }, + { + "name": "bipedRightArm", + "pivot": [ + -4, + 22, + 0 + ] + }, + { + "name": "armorRightArm", + "parent": "bipedRightArm", + "pivot": [ + -4, + 22, + 0 + ] + }, + { + "name": "bone11", + "parent": "armorRightArm", + "pivot": [ + -4, + 22, + 0 + ], + "cubes": [ + { + "origin": [ + -8.1, + 11.9, + -2.1 + ], + "size": [ + 4.2, + 12.1, + 4.2 + ], + "uv": { + "north": { + "uv": [ + 44, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "east": { + "uv": [ + 40, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "south": { + "uv": [ + 52, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "west": { + "uv": [ + 48, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "up": { + "uv": [ + 44, + 20 + ], + "uv_size": [ + 4, + -4 + ] + } + } + } + ] + }, + { + "name": "armorRightOut", + "parent": "bone11", + "pivot": [ + -7.1, + 24.1, + 2 + ], + "cubes": [ + { + "origin": [ + -8.45, + 20, + -2.25 + ], + "size": [ + 0.35, + 3.1, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 43, + 37 + ], + "uv_size": [ + 1, + 3 + ] + }, + "east": { + "uv": [ + 40, + 37 + ], + "uv_size": [ + 4, + 3 + ] + }, + "south": { + "uv": [ + 43, + 37 + ], + "uv_size": [ + 1, + 3 + ] + }, + "west": { + "uv": [ + 40, + 37 + ], + "uv_size": [ + 4, + 3 + ] + }, + "up": { + "uv": [ + 44, + 40 + ], + "uv_size": [ + -1, + -3 + ] + }, + "down": { + "uv": [ + 44, + 40 + ], + "uv_size": [ + -1, + -3 + ] + } + } + }, + { + "origin": [ + -8.45, + 17, + 1.15 + ], + "size": [ + 0.35, + 1, + 1.1 + ], + "uv": { + "north": { + "uv": [ + 40, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 40, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 40, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 41, + 43 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -3.95, + 16, + 1.15 + ], + "size": [ + 0.35, + 1, + 1.1 + ], + "uv": { + "east": { + "uv": [ + 51, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 51, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 51, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 52, + 44 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 23.1, + -1.15 + ], + "size": [ + 0.35, + 0.9, + 2.3 + ], + "uv": { + "north": { + "uv": [ + 41, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 41, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 41, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 43, + 37 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -7.25, + 23, + 2.55 + ], + "size": [ + 0.35, + 1.1, + 2.3 + ], + "pivot": [ + -7.25, + 23, + 2.45 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 53, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 53, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 53, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 55, + 37 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 55, + 37 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -8.35, + 20.05, + 2.55 + ], + "size": [ + 0.25, + 2.95, + 1.2 + ], + "pivot": [ + -8.35, + 22, + 2.45 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 53, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 53, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 55, + 37 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 55, + 37 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -8.35, + 16, + 2.55 + ], + "size": [ + 0.35, + 2, + 2.3 + ], + "pivot": [ + -8.35, + 17, + 2.45 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 42 + ], + "uv_size": [ + 2, + 2 + ] + }, + "east": { + "uv": [ + 54, + 42 + ], + "uv_size": [ + 2, + 2 + ] + }, + "up": { + "uv": [ + 56, + 44 + ], + "uv_size": [ + -2, + -2 + ] + }, + "down": { + "uv": [ + 56, + 44 + ], + "uv_size": [ + -2, + -2 + ] + } + } + }, + { + "origin": [ + -6.25, + 16, + 2.75 + ], + "size": [ + 0.35, + 1, + 2.1 + ], + "pivot": [ + -6.25, + 17, + 2.45 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 52, + 43 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 52, + 43 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 54, + 44 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 54, + 44 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + -8.25, + 11.9, + 2.55 + ], + "size": [ + 0.35, + 4.1, + 4.3 + ], + "pivot": [ + -8.25, + 11.9, + 2.45 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 61, + 60 + ], + "uv_size": [ + -1, + 4 + ] + }, + "east": { + "uv": [ + 64, + 60 + ], + "uv_size": [ + -4, + 4 + ] + }, + "up": { + "uv": [ + 61, + 60 + ], + "uv_size": [ + -1, + 4 + ] + }, + "down": { + "uv": [ + 61, + 53 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -7.35, + 23.1, + -2.05 + ], + "size": [ + 0.35, + 0.9, + 2.3 + ], + "pivot": [ + -7.25, + 23, + -2.15 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 55, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "east": { + "uv": [ + 45, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "west": { + "uv": [ + 45, + 36 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + }, + "down": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 16, + -2.05 + ], + "size": [ + 0.35, + 1, + 3.4 + ], + "pivot": [ + -8.35, + 16, + -2.15 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + -2, + 1 + ] + }, + "east": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + -2, + 1 + ] + }, + "south": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + -2, + 1 + ] + }, + "west": { + "uv": [ + 44, + 43 + ], + "uv_size": [ + 3, + 1 + ] + }, + "up": { + "uv": [ + 54, + 60 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 21, + -2.05 + ], + "size": [ + 0.35, + 2.1, + 4.5 + ], + "pivot": [ + -8.35, + 22, + -2.15 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 55, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "east": { + "uv": [ + 48, + 37 + ], + "uv_size": [ + -4, + 2 + ] + }, + "south": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "west": { + "uv": [ + 44, + 37 + ], + "uv_size": [ + 4, + 2 + ] + }, + "up": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + }, + "down": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 20, + -2.05 + ], + "size": [ + 0.35, + 1, + 3.4 + ], + "pivot": [ + -8.35, + 21, + -2.15 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 55, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "east": { + "uv": [ + 52, + 53 + ], + "uv_size": [ + 4, + 2 + ] + }, + "south": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "west": { + "uv": [ + 44, + 39 + ], + "uv_size": [ + 3, + 1 + ] + }, + "down": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 11.9, + -2.05 + ], + "size": [ + 0.35, + 4.1, + 4.5 + ], + "pivot": [ + -8.35, + 15, + -2.15 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + -1, + 4 + ] + }, + "east": { + "uv": [ + 52, + 60 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 53, + 60 + ], + "uv_size": [ + -1, + 4 + ] + }, + "west": { + "uv": [ + 44, + 44 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + }, + "down": { + "uv": [ + 53, + 53 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -8.45, + 11.9, + -2.25 + ], + "size": [ + 0.35, + 5.1, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 43, + 43 + ], + "uv_size": [ + 1, + 5 + ] + }, + "east": { + "uv": [ + 40, + 43 + ], + "uv_size": [ + 4, + 5 + ] + }, + "south": { + "uv": [ + 40, + 43 + ], + "uv_size": [ + 1, + 5 + ] + }, + "west": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + 4, + 5 + ] + }, + "up": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + 3, + -1 + ] + }, + "down": { + "uv": [ + 55, + 64 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -3.95, + 11.9, + -2.25 + ], + "size": [ + 0.35, + 4.1, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 49, + 59 + ], + "uv_size": [ + 4, + 5 + ] + }, + "east": { + "uv": [ + 52, + 44 + ], + "uv_size": [ + -4, + 4 + ] + }, + "south": { + "uv": [ + 49, + 59 + ], + "uv_size": [ + 4, + 5 + ] + }, + "west": { + "uv": [ + 48, + 44 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + 3, + -1 + ] + } + } + }, + { + "origin": [ + -7.1, + 24, + -2.3 + ], + "size": [ + 2.2, + 0.2, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 45, + 35 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 54, + 49 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 45, + 32 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 47, + 32 + ], + "uv_size": [ + -2, + 4 + ] + }, + "down": { + "uv": [ + 47, + 36 + ], + "uv_size": [ + -2, + -4 + ] + } + } + }, + { + "origin": [ + -8.2, + 11.9, + -2.2 + ], + "size": [ + 4.4, + 0.2, + 4.4 + ], + "uv": { + "north": { + "uv": [ + 55, + 48 + ], + "uv_size": [ + -2, + 1 + ] + }, + "south": { + "uv": [ + 53, + 48 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 52, + 36 + ], + "uv_size": [ + -4, + -4 + ] + }, + "down": { + "uv": [ + 52, + 36 + ], + "uv_size": [ + -4, + -4 + ] + } + } + }, + { + "origin": [ + -8.2, + 24, + -1.3 + ], + "size": [ + 1.1, + 0.2, + 2.5 + ], + "uv": { + "north": { + "uv": [ + 55, + 49 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 55, + 49 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 55, + 49 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 45, + 35 + ], + "uv_size": [ + -1, + -2 + ] + }, + "down": { + "uv": [ + 45, + 35 + ], + "uv_size": [ + -1, + -2 + ] + } + } + } + ] + }, + { + "name": "bipedLeftArm", + "pivot": [ + 4, + 22, + 0 + ] + }, + { + "name": "armorLeftArm", + "parent": "bipedLeftArm", + "pivot": [ + 4, + 22, + 0 + ] + }, + { + "name": "bone8", + "parent": "armorLeftArm", + "pivot": [ + -4, + 22, + 0 + ], + "cubes": [ + { + "origin": [ + 3.9, + 11.9, + -2.1 + ], + "size": [ + 4.2, + 12.2, + 4.2 + ], + "uv": { + "north": { + "uv": [ + 36, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "east": { + "uv": [ + 32, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "south": { + "uv": [ + 44, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "west": { + "uv": [ + 40, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "up": { + "uv": [ + 36, + 48 + ], + "uv_size": [ + 4, + 4 + ] + } + } + } + ] + }, + { + "name": "armorLeftArmOut", + "parent": "bone8", + "pivot": [ + 7.1, + 24.1, + 2 + ], + "cubes": [ + { + "origin": [ + 8.1, + 18, + -2.25 + ], + "size": [ + 0.35, + 5, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 56, + 53 + ], + "uv_size": [ + 1, + 5 + ] + }, + "east": { + "uv": [ + 60, + 53 + ], + "uv_size": [ + -4, + 5 + ] + }, + "south": { + "uv": [ + 59, + 53 + ], + "uv_size": [ + 1, + 5 + ] + }, + "west": { + "uv": [ + 56, + 53 + ], + "uv_size": [ + 4, + 5 + ] + }, + "up": { + "uv": [ + 57, + 57 + ], + "uv_size": [ + -1, + -4 + ] + }, + "down": { + "uv": [ + 60, + 57 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 17, + -1.25 + ], + "size": [ + 0.35, + 1, + 3.5 + ], + "uv": { + "north": { + "uv": [ + 58, + 58 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 59, + 58 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 57, + 58 + ], + "uv_size": [ + 3, + 1 + ] + } + } + }, + { + "origin": [ + 8.1, + 23, + -1.15 + ], + "size": [ + 0.35, + 1, + 2.3 + ], + "uv": { + "north": { + "uv": [ + 57, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 57, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 57, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 59, + 53 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 6.9, + 23, + 2.55 + ], + "size": [ + 0.35, + 1, + 2.3 + ], + "pivot": [ + 7.25, + 23, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 20.95, + 2.55 + ], + "size": [ + 0.25, + 2.05, + 1.2 + ], + "pivot": [ + 8.35, + 22, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 8, + 17.9, + 2.55 + ], + "size": [ + 0.35, + 1.1, + 1.2 + ], + "pivot": [ + 8.35, + 18, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + 4.7, + 17.9, + 2.55 + ], + "size": [ + 0.35, + 1.1, + 1.2 + ], + "pivot": [ + 5.05, + 18, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 63, + 59 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 63, + 59 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 64, + 60 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 64, + 60 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.7, + 19, + 2.65 + ], + "size": [ + 0.35, + 1, + 1.1 + ], + "pivot": [ + 5.05, + 19, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 63, + 59 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 63, + 59 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 64, + 60 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8, + 19, + 2.55 + ], + "size": [ + 0.35, + 2, + 3.4 + ], + "pivot": [ + 8.35, + 19, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 60, + 55 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 60, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "up": { + "uv": [ + 64, + 60 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 63, + 56 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 8, + 16, + 2.55 + ], + "size": [ + 0.35, + 2, + 2.3 + ], + "pivot": [ + 8.35, + 17, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 61, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 7.9, + 11.9, + 2.55 + ], + "size": [ + 0.35, + 4.1, + 4.3 + ], + "pivot": [ + 8.25, + 11.9, + 2.45 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 60, + 60 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 60, + 60 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 60, + 60 + ], + "uv_size": [ + 1, + 4 + ] + }, + "down": { + "uv": [ + 63, + 53 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 7, + 23, + -2.05 + ], + "size": [ + 0.35, + 1, + 2.3 + ], + "pivot": [ + 7.25, + 23, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 16, + -2.05 + ], + "size": [ + 0.35, + 1, + 2.3 + ], + "pivot": [ + 8.35, + 16, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 4.9, + 16, + -1.95 + ], + "size": [ + 0.35, + 1, + 1.2 + ], + "pivot": [ + 5.15, + 16, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 54, + 59 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 21, + -2.05 + ], + "size": [ + 0.35, + 2, + 4.5 + ], + "pivot": [ + 8.35, + 22, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 52, + 53 + ], + "uv_size": [ + 4, + 2 + ] + }, + "south": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 56, + 53 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 20, + -2.05 + ], + "size": [ + 0.35, + 1, + 3.4 + ], + "pivot": [ + 8.35, + 21, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 53, + 55 + ], + "uv_size": [ + 3, + 1 + ] + }, + "south": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 56, + 53 + ], + "uv_size": [ + -4, + 2 + ] + } + } + }, + { + "origin": [ + 8.1, + 17.9, + -2.05 + ], + "size": [ + 0.35, + 2.1, + 4.5 + ], + "pivot": [ + 8.35, + 19, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 54, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 52, + 56 + ], + "uv_size": [ + 4, + 2 + ] + }, + "south": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 56, + 56 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 11.9, + -2.05 + ], + "size": [ + 0.35, + 4.1, + 4.5 + ], + "pivot": [ + 8.35, + 15, + -2.15 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 55, + 60 + ], + "uv_size": [ + 1, + 4 + ] + }, + "east": { + "uv": [ + 52, + 60 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 52, + 60 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 56, + 60 + ], + "uv_size": [ + -4, + 4 + ] + }, + "up": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 54, + 53 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.1, + 11.9, + -2.25 + ], + "size": [ + 0.35, + 5.1, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + 1, + 5 + ] + }, + "east": { + "uv": [ + 60, + 59 + ], + "uv_size": [ + -4, + 5 + ] + }, + "south": { + "uv": [ + 59, + 59 + ], + "uv_size": [ + 1, + 5 + ] + }, + "west": { + "uv": [ + 56, + 59 + ], + "uv_size": [ + 4, + 5 + ] + }, + "up": { + "uv": [ + 59, + 60 + ], + "uv_size": [ + -3, + -1 + ] + }, + "down": { + "uv": [ + 56, + 64 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.6, + 11.9, + -2.25 + ], + "size": [ + 0.35, + 5.1, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 53, + 59 + ], + "uv_size": [ + -4, + 5 + ] + }, + "east": { + "uv": [ + 53, + 59 + ], + "uv_size": [ + -4, + 5 + ] + }, + "south": { + "uv": [ + 53, + 59 + ], + "uv_size": [ + -4, + 5 + ] + }, + "west": { + "uv": [ + 53, + 59 + ], + "uv_size": [ + -4, + 5 + ] + }, + "up": { + "uv": [ + 59, + 60 + ], + "uv_size": [ + -3, + -1 + ] + }, + "down": { + "uv": [ + 56, + 64 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.6, + 17.9, + -2.25 + ], + "size": [ + 0.35, + 2.1, + 4.5 + ], + "uv": { + "east": { + "uv": [ + 53, + 56 + ], + "uv_size": [ + -4, + 2 + ] + }, + "south": { + "uv": [ + 53, + 56 + ], + "uv_size": [ + -4, + 2 + ] + }, + "west": { + "uv": [ + 53, + 56 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 49, + 58 + ], + "uv_size": [ + 4, + -2 + ] + }, + "down": { + "uv": [ + 49, + 58 + ], + "uv_size": [ + 4, + -2 + ] + } + } + }, + { + "origin": [ + 4.9, + 24, + -2.3 + ], + "size": [ + 2.2, + 0.2, + 4.5 + ], + "uv": { + "north": { + "uv": [ + 53, + 48 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 55, + 48 + ], + "uv_size": [ + -2, + 1 + ] + }, + "west": { + "uv": [ + 55, + 49 + ], + "uv_size": [ + -1, + 2 + ] + }, + "up": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 2, + -4 + ] + }, + "down": { + "uv": [ + 53, + 52 + ], + "uv_size": [ + 2, + -4 + ] + } + } + }, + { + "origin": [ + 3.8, + 11.9, + -2.2 + ], + "size": [ + 4.4, + 0.2, + 4.4 + ], + "uv": { + "north": { + "uv": [ + 53, + 48 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 55, + 48 + ], + "uv_size": [ + -2, + 1 + ] + }, + "up": { + "uv": [ + 53, + 64 + ], + "uv_size": [ + 2, + -4 + ] + }, + "down": { + "uv": [ + 56, + 52 + ], + "uv_size": [ + 4, + -4 + ] + } + } + }, + { + "origin": [ + 7.1, + 24, + -1.3 + ], + "size": [ + 1.1, + 0.2, + 2.5 + ], + "uv": { + "north": { + "uv": [ + 56, + 49 + ], + "uv_size": [ + -1, + 2 + ] + }, + "south": { + "uv": [ + 56, + 49 + ], + "uv_size": [ + -1, + 2 + ] + }, + "west": { + "uv": [ + 56, + 49 + ], + "uv_size": [ + -1, + 2 + ] + }, + "up": { + "uv": [ + 55, + 51 + ], + "uv_size": [ + 1, + -2 + ] + }, + "down": { + "uv": [ + 55, + 51 + ], + "uv_size": [ + 1, + -2 + ] + } + } + } + ] + }, + { + "name": "launcher", + "parent": "bone8", + "pivot": [ + 6, + 23.75, + -0.75 + ], + "cubes": [ + { + "origin": [ + 6.5, + 22.95, + 0.5 + ], + "size": [ + 1, + 3.5, + 1 + ], + "pivot": [ + 7.5, + 22.95, + 0.25 + ], + "rotation": [ + -47.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6, + 24.2, + 0.25 + ], + "size": [ + 2, + 1, + 1.5 + ], + "pivot": [ + 7.5, + 22.95, + 0.25 + ], + "rotation": [ + -47.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 24.8, + 3.35 + ], + "size": [ + 1, + 1.25, + 1.5 + ], + "inflate": 0.01, + "pivot": [ + 7.5, + 25.05, + 3.35 + ], + "rotation": [ + 55, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 24.35, + 2.7 + ], + "size": [ + 1, + 1.25, + 1 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.25, + 25.6, + 2.2 + ], + "size": [ + 1.5, + 1.25, + 1.75 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + } + ] + }, + { + "name": "bone4", + "parent": "launcher", + "pivot": [ + 7, + 27.25, + 2.7 + ], + "cubes": [ + { + "origin": [ + 7.5, + 26.45, + -1.3 + ], + "size": [ + 0.5, + 1.6, + 5 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 7.5, + 27.9, + -1.05 + ], + "size": [ + 0.5, + 0.6, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6, + 27.9, + -1.05 + ], + "size": [ + 0.5, + 0.6, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 7.75, + 27.2, + -0.3 + ], + "size": [ + 0.5, + 0.85, + 3 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.75, + 27.2, + -0.3 + ], + "size": [ + 0.5, + 0.85, + 3 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 7.75, + 26.35, + -0.8 + ], + "size": [ + 0.5, + 0.85, + 3.5 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.75, + 26.35, + -0.8 + ], + "size": [ + 0.5, + 0.85, + 3.5 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 7.5, + 26.1, + -1.05 + ], + "size": [ + 0.5, + 0.35, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 25.85, + -1.05 + ], + "size": [ + 1, + 0.35, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 28.35, + -1.05 + ], + "size": [ + 1, + 0.35, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 28.1, + 1.45 + ], + "size": [ + 1, + 0.6, + 1.75 + ], + "inflate": 0.1, + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6, + 26.1, + -1.05 + ], + "size": [ + 0.5, + 0.35, + 3.75 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6, + 26.45, + -1.3 + ], + "size": [ + 0.5, + 1.6, + 5 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 26.1, + -1.3 + ], + "size": [ + 1, + 0.65, + 5 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 27.85, + -1.3 + ], + "size": [ + 1, + 0.65, + 5 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 6.5, + 26.6, + 3.7 + ], + "size": [ + 1, + 1.4, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 59, + 13 + ], + "uv_size": [ + -1, + -1 + ] + } + } + } + ] + }, + { + "name": "doomblade", + "parent": "bone8", + "pivot": [ + 8.2, + 14.8, + 0 + ], + "rotation": [ + 90, + 180, + 90 + ] + }, + { + "name": "group4", + "parent": "doomblade", + "pivot": [ + -16.2, + 16.65, + 16.5 + ], + "cubes": [ + { + "origin": [ + 8.95, + 14.05, + 0.375 + ], + "size": [ + 0.75, + 1.5, + 1.125 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 9.7, + 14.05, + 0.375 + ], + "size": [ + 0.75, + 1.5, + 0.75 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.3, + 14.05, + 0.375 + ], + "size": [ + 0.45, + 1.5, + 0.875 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.33, + 14.3, + 0.375 + ], + "size": [ + 0.95, + 1, + 0.375 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 2.83, + 14.3, + -0.02 + ], + "size": [ + 2.45, + 1, + 0.375 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.08, + 14.55, + 0.375 + ], + "size": [ + 2.2, + 0.5, + 0.375 + ], + "inflate": 0.01, + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.55, + 14.05, + 0.875 + ], + "size": [ + 0.7, + 1.5, + 0.625 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.55, + 14.05, + 0.5 + ], + "size": [ + 0.45, + 1.5, + 0.375 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.7, + 14.05, + 1 + ], + "size": [ + 0.45, + 1.5, + 0.375 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 8.55, + 14.05, + 0.375 + ], + "size": [ + 0.7, + 1.5, + 0.625 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.05, + 14.05, + 0 + ], + "size": [ + 5.25, + 1.5, + 0.375 + ], + "uv": { + "north": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 11, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 12, + 4 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.7, + 14.2, + 0.375 + ], + "size": [ + 3.25, + 1.2, + 0.9 + ], + "uv": { + "north": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 3, + 1 + ] + }, + "east": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 3, + 1 + ] + }, + "south": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 3, + 1 + ] + }, + "west": { + "uv": [ + 58, + 12 + ], + "uv_size": [ + 3, + 1 + ] + }, + "up": { + "uv": [ + 61, + 13 + ], + "uv_size": [ + -3, + -1 + ] + }, + "down": { + "uv": [ + 61, + 13 + ], + "uv_size": [ + -3, + -1 + ] + } + } + } + ] + }, + { + "name": "group5", + "parent": "doomblade", + "pivot": [ + -16.2, + 16.65, + 16.5 + ], + "cubes": [ + { + "origin": [ + 4, + 15.565, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -10.1, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.225, + 15.565, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.875, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.45, + 15.565, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.65, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.675, + 15.565, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.425, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + } + ] + }, + { + "name": "group6", + "parent": "doomblade", + "pivot": [ + -16.2, + 16.65, + 16.5 + ], + "cubes": [ + { + "origin": [ + 4, + 14.035, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -10.1, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.225, + 14.035, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.875, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.45, + 14.035, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.65, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.675, + 14.035, + -6.375 + ], + "size": [ + 0.15, + 0.015, + 0.375 + ], + "pivot": [ + -9.425, + 9.55, + 6.75 + ], + "rotation": [ + 0, + -22.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 2, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 3, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + } + ] + }, + { + "name": "blade", + "parent": "doomblade", + "pivot": [ + 4.8, + 14.85, + 0.7 + ], + "cubes": [ + { + "origin": [ + 0.36392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 0.4223, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 0.26662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 0.26662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 0.75396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + -0.18766, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 1.11392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 1.1723, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.01662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.05, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 1.25, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.01662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.50396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 0.56234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 2.25396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 1.31234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 1.76662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.8, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 2, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "up": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + }, + "down": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + } + } + }, + { + "origin": [ + 1.76662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 1.86392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 1.9223, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.00396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 2.06234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 2.51662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 2.55, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 2.75, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "up": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + }, + "down": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + } + } + }, + { + "origin": [ + 2.51662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 2.61392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 2.6723, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.75396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 2.81234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 3.26662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.3, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 3.5, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "up": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + }, + "down": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + } + } + }, + { + "origin": [ + 3.26662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.36392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 3.4223, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.50396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 3.56234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 4.01662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.05, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 4.25, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "up": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + }, + "down": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + } + } + }, + { + "origin": [ + 4.01662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.11392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 4.1723, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 5.25396, + 14.7, + 0.69158 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 4.31234, + 14.55, + 1.51658 + ], + "rotation": [ + 0, + 27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.375, + 0.2 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 0.5, + 0.2 + ] + }, + "up": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + }, + "down": { + "uv": [ + 5.375, + 5.5 + ], + "uv_size": [ + -0.375, + -0.5 + ] + } + } + }, + { + "origin": [ + 4.76662, + 14.7, + 0.1 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.8, + 14.75, + 1.15 + ], + "size": [ + 0.25, + 0.1, + 0.225 + ], + "pivot": [ + 5, + 14.75, + 1.25 + ], + "rotation": [ + 0, + -62.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.25, + 0.1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 0.225, + 0.1 + ] + }, + "up": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + }, + "down": { + "uv": [ + 0.25, + 5.225 + ], + "uv_size": [ + -0.25, + -0.225 + ] + } + } + }, + { + "origin": [ + 4.76662, + 14.7, + 0.9 + ], + "size": [ + 0.375, + 0.2, + 0.25 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 4.86392, + 14.7, + 0.45238 + ], + "size": [ + 0.375, + 0.2, + 0.5 + ], + "pivot": [ + 4.9223, + 14.55, + 0.72738 + ], + "rotation": [ + 0, + -27.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 0.55, + 14.75, + 0.15 + ], + "size": [ + 4.75, + 0.1, + 0.975 + ], + "uv": { + "north": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 0, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 1, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.2, + 14.75, + 0.15 + ], + "size": [ + 1.75, + 0.1, + 0.725 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -2.00595, + 14.7, + 0.0951 + ], + "size": [ + 2.5, + 0.2, + 0.225 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.50595, + 14.7, + 0.3201 + ], + "size": [ + 2, + 0.2, + 0.225 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -0.23338, + 14.7, + 0.675 + ], + "size": [ + 0.75, + 0.2, + 0.475 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.00595, + 14.7, + 0.5451 + ], + "size": [ + 1.75, + 0.2, + 0.225 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.55597, + 14.7, + 1.07007 + ], + "size": [ + 1, + 0.2, + 0.475 + ], + "pivot": [ + 0.39403, + 0, + 0.42007 + ], + "rotation": [ + 0, + -25, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.73967, + 14.7, + 1.57457 + ], + "size": [ + 0.25, + 0.2, + 0.475 + ], + "pivot": [ + -0.03967, + 0, + 0.92457 + ], + "rotation": [ + 0, + -47.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -1.92377, + 14.7, + 1.71887 + ], + "size": [ + 0.25, + 0.2, + 0.225 + ], + "pivot": [ + -0.22377, + 0, + 0.81887 + ], + "rotation": [ + 0, + -50, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -0.88962, + 14.7, + 0.5842 + ], + "size": [ + 0.75, + 0.2, + 0.475 + ], + "pivot": [ + -0.79584, + 15, + 0.74701 + ], + "rotation": [ + 0, + -10, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + -0.35269, + 14.7, + 0.66088 + ], + "size": [ + 0.5, + 0.2, + 0.475 + ], + "pivot": [ + -0.25891, + 15, + 0.82369 + ], + "rotation": [ + 0, + -17.5, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 5, + 5 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 6, + 6 + ], + "uv_size": [ + -1, + -1 + ] + } + } + } + ] + }, + { + "name": "bipedRightLeg", + "pivot": [ + -2, + 12, + 0 + ] + }, + { + "name": "armorRightLeg", + "parent": "bipedRightLeg", + "pivot": [ + -2, + 12, + 0 + ] + }, + { + "name": "bone6", + "parent": "armorRightLeg", + "pivot": [ + -4, + 22, + 0 + ], + "cubes": [ + { + "origin": [ + -0.1, + 0.2, + -2.2 + ], + "size": [ + 4.4, + 11.8, + 4.4 + ], + "uv": { + "north": { + "uv": [ + 8, + 20 + ], + "uv_size": [ + -4, + 12 + ] + }, + "south": { + "uv": [ + 16, + 20 + ], + "uv_size": [ + -4, + 12 + ] + }, + "west": { + "uv": [ + 4, + 20 + ], + "uv_size": [ + -4, + 12 + ] + }, + "up": { + "uv": [ + 8, + 20 + ], + "uv_size": [ + -4, + -4 + ] + } + } + } + ] + }, + { + "name": "armorRightBoot", + "parent": "bipedRightLeg", + "pivot": [ + -2, + 12, + 0 + ] + }, + { + "name": "bone9", + "parent": "armorRightBoot", + "pivot": [ + -4, + 22, + 0 + ] + }, + { + "name": "bone14", + "parent": "bone9", + "pivot": [ + -4, + 22, + 0 + ], + "cubes": [ + { + "origin": [ + 0, + -0.3, + -2.3 + ], + "size": [ + 4.6, + 2.2, + 4.6 + ], + "uv": { + "north": { + "uv": [ + 4, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "south": { + "uv": [ + 12, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "west": { + "uv": [ + 8, + 52 + ], + "uv_size": [ + 4, + 12 + ] + }, + "up": { + "uv": [ + 12, + 20 + ], + "uv_size": [ + -4, + -4 + ] + }, + "down": { + "uv": [ + 12, + 20 + ], + "uv_size": [ + -4, + -4 + ] + } + } + }, + { + "origin": [ + 0, + 2.8, + -2.5 + ], + "size": [ + 4.6, + 4.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 4, + 57 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 4, + 57 + ], + "uv_size": [ + 4, + 4 + ] + }, + "west": { + "uv": [ + 5, + 57 + ], + "uv_size": [ + -1, + 4 + ] + }, + "up": { + "uv": [ + 8, + 58 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 4, + 61 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + 0, + 5.8, + 2.2 + ], + "size": [ + 4.6, + 1.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 12, + 57 + ], + "uv_size": [ + 4, + 1 + ] + }, + "south": { + "uv": [ + 12, + 57 + ], + "uv_size": [ + 4, + 1 + ] + }, + "west": { + "uv": [ + 12, + 57 + ], + "uv_size": [ + 4, + 1 + ] + }, + "up": { + "uv": [ + 16, + 58 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 16, + 58 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 0, + 2.8, + 2 + ], + "size": [ + 4.6, + 1.1, + 0.5 + ], + "uv": { + "north": { + "uv": [ + 12, + 60 + ], + "uv_size": [ + 4, + 1 + ] + }, + "south": { + "uv": [ + 12, + 60 + ], + "uv_size": [ + 4, + 1 + ] + }, + "west": { + "uv": [ + 12, + 60 + ], + "uv_size": [ + 4, + 1 + ] + }, + "up": { + "uv": [ + 16, + 61 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 16, + 61 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 0, + -0.2, + -2.5 + ], + "size": [ + 4.6, + 2.1, + 0.7 + ], + "uv": { + "north": { + "uv": [ + 4, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 1, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "up": { + "uv": [ + 8, + 63 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 8, + 64 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 2.3, + 6.9, + -2.5 + ], + "size": [ + 2.3, + 2.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 6, + 55 + ], + "uv_size": [ + 2, + 2 + ] + }, + "east": { + "uv": [ + 6, + 55 + ], + "uv_size": [ + 2, + 2 + ] + }, + "south": { + "uv": [ + 6, + 55 + ], + "uv_size": [ + 2, + 2 + ] + }, + "west": { + "uv": [ + 6, + 55 + ], + "uv_size": [ + 2, + 2 + ] + }, + "up": { + "uv": [ + 8, + 57 + ], + "uv_size": [ + -2, + -2 + ] + } + } + }, + { + "origin": [ + 0, + 6.9, + 2.2 + ], + "size": [ + 3.5, + 2.1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "south": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "west": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "up": { + "uv": [ + 15, + 57 + ], + "uv_size": [ + -3, + -2 + ] + } + } + }, + { + "origin": [ + 0, + 9, + 2.2 + ], + "size": [ + 1.2, + 1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "south": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "west": { + "uv": [ + 12, + 55 + ], + "uv_size": [ + 3, + 2 + ] + }, + "up": { + "uv": [ + 15, + 57 + ], + "uv_size": [ + -3, + -2 + ] + } + } + }, + { + "origin": [ + 0, + 10.9, + -2.5 + ], + "size": [ + 1.2, + 1.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 4, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 4, + 52 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 5, + 53 + ], + "uv_size": [ + -1, + -1 + ] + }, + "down": { + "uv": [ + 5, + 53 + ], + "uv_size": [ + -1, + -1 + ] + } + } + }, + { + "origin": [ + 3.3, + 9, + -2.5 + ], + "size": [ + 1.3, + 2, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 7, + 53 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 7, + 53 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 7, + 53 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 7, + 53 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 8, + 55 + ], + "uv_size": [ + -1, + -2 + ] + } + } + }, + { + "origin": [ + 4.6, + -0.2, + 2 + ], + "size": [ + 4.6, + 2.1, + 0.5 + ], + "pivot": [ + 4.6, + -0.2, + 2.3 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "east": { + "uv": [ + 12, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "south": { + "uv": [ + 8, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "up": { + "uv": [ + 8, + 63 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 8, + 64 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 4.6, + 2.8, + 2.2 + ], + "size": [ + 4.6, + 8.2, + 0.3 + ], + "pivot": [ + 4.6, + 2.8, + 2.3 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "north": { + "uv": [ + 12, + 53 + ], + "uv_size": [ + -4, + 8 + ] + }, + "east": { + "uv": [ + 11, + 53 + ], + "uv_size": [ + 1, + 8 + ] + }, + "south": { + "uv": [ + 8, + 53 + ], + "uv_size": [ + 4, + 8 + ] + }, + "up": { + "uv": [ + 12, + 54 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 11, + 61 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + -0.2, + 2.8, + 2.3 + ], + "size": [ + 4.6, + 4.1, + 0.3 + ], + "pivot": [ + -0.2, + 2.8, + 2.3 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "up": { + "uv": [ + 4, + 58 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 11, + 61 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + -0.2, + -0.2, + 2.3 + ], + "size": [ + 4.6, + 2.1, + 0.4 + ], + "pivot": [ + -0.2, + -0.2, + 2.3 + ], + "rotation": [ + 0, + 90, + 0 + ], + "uv": { + "up": { + "uv": [ + 8, + 63 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 8, + 64 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 0, + -0.2, + 2.1 + ], + "size": [ + 4.6, + 2.1, + 0.4 + ], + "uv": { + "south": { + "uv": [ + 12, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "west": { + "uv": [ + 12, + 62 + ], + "uv_size": [ + 4, + 2 + ] + }, + "up": { + "uv": [ + 8, + 63 + ], + "uv_size": [ + -4, + -1 + ] + }, + "down": { + "uv": [ + 16, + 64 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + 1.1, + 1.9, + 2.2 + ], + "size": [ + 2.4, + 1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + } + } + }, + { + "origin": [ + 0, + 3.9, + 2.1 + ], + "size": [ + 1.2, + 1, + 0.4 + ], + "uv": { + "south": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 15, + 62 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 3.4, + 3.9, + 1.9 + ], + "size": [ + 1.2, + 1, + 0.6 + ], + "uv": { + "east": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 15, + 62 + ], + "uv_size": [ + -2, + -1 + ] + }, + "down": { + "uv": [ + 15, + 62 + ], + "uv_size": [ + -2, + -1 + ] + } + } + }, + { + "origin": [ + 1.1, + 1.9, + -2.5 + ], + "size": [ + 2.4, + 1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 13, + 61 + ], + "uv_size": [ + 2, + 1 + ] + } + } + } + ] + }, + { + "name": "bipedLeftLeg", + "pivot": [ + 2, + 12, + 0 + ] + }, + { + "name": "armorLeftLeg", + "parent": "bipedLeftLeg", + "pivot": [ + 2, + 12, + 0 + ] + }, + { + "name": "bone7", + "parent": "armorLeftLeg", + "pivot": [ + -4, + 22, + 0 + ] + }, + { + "name": "armorLeftBoot", + "parent": "bipedLeftLeg", + "pivot": [ + 2, + 12, + 0 + ] + }, + { + "name": "bone10", + "parent": "armorLeftBoot", + "pivot": [ + -4, + 22, + 0 + ], + "cubes": [ + { + "origin": [ + -4.2, + -0.2, + -2.3 + ], + "size": [ + 4.6, + 12.2, + 4.6 + ], + "uv": { + "north": { + "uv": [ + 4, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "east": { + "uv": [ + 0, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "south": { + "uv": [ + 12, + 20 + ], + "uv_size": [ + 4, + 12 + ] + }, + "west": { + "uv": [ + 4, + 52 + ], + "uv_size": [ + -4, + 12 + ] + }, + "up": { + "uv": [ + 4, + 0 + ], + "uv_size": [ + 4, + 4 + ] + } + } + }, + { + "origin": [ + -4.2, + -0.3, + -2.3 + ], + "size": [ + 4.6, + 2.2, + 4.6 + ], + "uv": { + "north": { + "uv": [ + 8, + 52 + ], + "uv_size": [ + -4, + 12 + ] + }, + "east": { + "uv": [ + 12, + 52 + ], + "uv_size": [ + -4, + 12 + ] + }, + "south": { + "uv": [ + 16, + 52 + ], + "uv_size": [ + -4, + 12 + ] + }, + "down": { + "uv": [ + 8, + 20 + ], + "uv_size": [ + 4, + -4 + ] + } + } + }, + { + "origin": [ + -4.2, + 2.8, + -2.5 + ], + "size": [ + 4.6, + 4.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 8, + 57 + ], + "uv_size": [ + -4, + 4 + ] + }, + "east": { + "uv": [ + 4, + 57 + ], + "uv_size": [ + 1, + 4 + ] + }, + "up": { + "uv": [ + 4, + 58 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 8, + 61 + ], + "uv_size": [ + -4, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + 5.8, + 2.2 + ], + "size": [ + 4.6, + 1.1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 16, + 57 + ], + "uv_size": [ + -4, + 1 + ] + }, + "south": { + "uv": [ + 16, + 57 + ], + "uv_size": [ + -4, + 1 + ] + }, + "up": { + "uv": [ + 12, + 58 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 12, + 58 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + 2.8, + 2 + ], + "size": [ + 4.6, + 1.1, + 0.5 + ], + "uv": { + "east": { + "uv": [ + 16, + 60 + ], + "uv_size": [ + -4, + 1 + ] + }, + "south": { + "uv": [ + 16, + 60 + ], + "uv_size": [ + -4, + 1 + ] + }, + "up": { + "uv": [ + 12, + 61 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 12, + 61 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + -0.2, + -2.5 + ], + "size": [ + 4.6, + 2.1, + 0.7 + ], + "uv": { + "north": { + "uv": [ + 8, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "east": { + "uv": [ + 5, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 4, + 63 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 4, + 64 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + 6.9, + -2.5 + ], + "size": [ + 2.3, + 2.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 8, + 55 + ], + "uv_size": [ + -2, + 2 + ] + }, + "east": { + "uv": [ + 8, + 55 + ], + "uv_size": [ + -2, + 2 + ] + }, + "west": { + "uv": [ + 8, + 55 + ], + "uv_size": [ + -2, + 2 + ] + }, + "up": { + "uv": [ + 6, + 57 + ], + "uv_size": [ + 2, + -2 + ] + } + } + }, + { + "origin": [ + -4.2, + 6.9, + 2.2 + ], + "size": [ + 3.5, + 2.1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "south": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "west": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "up": { + "uv": [ + 12, + 57 + ], + "uv_size": [ + 3, + -2 + ] + } + } + }, + { + "origin": [ + -4.2, + 9, + 2.2 + ], + "size": [ + 1.2, + 1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "south": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "west": { + "uv": [ + 15, + 55 + ], + "uv_size": [ + -3, + 2 + ] + }, + "up": { + "uv": [ + 12, + 57 + ], + "uv_size": [ + 3, + -2 + ] + } + } + }, + { + "origin": [ + -0.8, + 10.9, + -2.5 + ], + "size": [ + 1.2, + 1.1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 5, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "east": { + "uv": [ + 5, + 52 + ], + "uv_size": [ + -1, + 1 + ] + }, + "up": { + "uv": [ + 4, + 53 + ], + "uv_size": [ + 1, + -1 + ] + }, + "down": { + "uv": [ + 4, + 53 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + 9, + -2.5 + ], + "size": [ + 1.3, + 2, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 8, + 53 + ], + "uv_size": [ + -1, + 2 + ] + }, + "east": { + "uv": [ + 8, + 53 + ], + "uv_size": [ + -1, + 2 + ] + }, + "west": { + "uv": [ + 8, + 53 + ], + "uv_size": [ + -1, + 2 + ] + }, + "up": { + "uv": [ + 7, + 55 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + -8.8, + -0.2, + 2 + ], + "size": [ + 4.6, + 2.1, + 0.5 + ], + "pivot": [ + -4.2, + -0.2, + 2.3 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "south": { + "uv": [ + 12, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "west": { + "uv": [ + 16, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 4, + 63 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 4, + 64 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -8.8, + 2.8, + 2.2 + ], + "size": [ + 4.6, + 8.2, + 0.3 + ], + "pivot": [ + -4.2, + 2.8, + 2.3 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 8, + 53 + ], + "uv_size": [ + 4, + 8 + ] + }, + "south": { + "uv": [ + 12, + 53 + ], + "uv_size": [ + -4, + 8 + ] + }, + "west": { + "uv": [ + 12, + 53 + ], + "uv_size": [ + -1, + 8 + ] + }, + "up": { + "uv": [ + 8, + 54 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 7, + 61 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4, + 2.8, + 2.3 + ], + "size": [ + 4.6, + 4.1, + 0.3 + ], + "pivot": [ + 0.6, + 2.8, + 2.3 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "north": { + "uv": [ + 4, + 57 + ], + "uv_size": [ + -4, + 4 + ] + }, + "west": { + "uv": [ + 4, + 57 + ], + "uv_size": [ + -4, + 4 + ] + }, + "up": { + "uv": [ + 0, + 58 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 7, + 61 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4, + -0.2, + 2.3 + ], + "size": [ + 4.6, + 2.1, + 0.4 + ], + "pivot": [ + 0.6, + -0.2, + 2.3 + ], + "rotation": [ + 0, + -90, + 0 + ], + "uv": { + "up": { + "uv": [ + 4, + 63 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 4, + 64 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + -0.2, + 2.1 + ], + "size": [ + 4.6, + 2.1, + 0.4 + ], + "uv": { + "east": { + "uv": [ + 16, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "south": { + "uv": [ + 16, + 62 + ], + "uv_size": [ + -4, + 2 + ] + }, + "up": { + "uv": [ + 4, + 63 + ], + "uv_size": [ + 4, + -1 + ] + }, + "down": { + "uv": [ + 12, + 64 + ], + "uv_size": [ + 4, + -1 + ] + } + } + }, + { + "origin": [ + -3.1, + 1.9, + 2.2 + ], + "size": [ + 2.4, + 1, + 0.3 + ], + "uv": { + "east": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "south": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "west": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + } + } + }, + { + "origin": [ + -0.8, + 3.9, + 2.1 + ], + "size": [ + 1.2, + 1, + 0.4 + ], + "uv": { + "east": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "south": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "up": { + "uv": [ + 13, + 62 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -4.2, + 3.9, + 1.9 + ], + "size": [ + 1.2, + 1, + 0.6 + ], + "uv": { + "east": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "south": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "west": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "up": { + "uv": [ + 13, + 62 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -3.1, + 1.9, + -2.5 + ], + "size": [ + 2.4, + 1, + 0.3 + ], + "uv": { + "north": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "east": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + }, + "west": { + "uv": [ + 15, + 61 + ], + "uv_size": [ + -2, + 1 + ] + } + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/geo/item/pistol.geo.json b/common/src/main/resources/assets/azurelib/geo/item/pistol.geo.json new file mode 100644 index 000000000..dfef26e61 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/geo/item/pistol.geo.json @@ -0,0 +1,3690 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 128, + "texture_height": 64, + "visible_bounds_width": 3, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [ + 0, + 0.75, + 0 + ] + }, + "bones": [ + { + "name": "group", + "pivot": [ + -0.49601, + 4.03502, + -0.09665 + ], + "cubes": [ + { + "origin": [ + -2, + -0.25, + -9.25 + ], + "size": [ + 3, + 4, + 7.75 + ], + "uv": { + "north": { + "uv": [ + 30, + 18 + ], + "uv_size": [ + 3, + 4 + ] + }, + "east": { + "uv": [ + 14, + 12 + ], + "uv_size": [ + 8, + 4 + ] + }, + "south": { + "uv": [ + 25, + 30 + ], + "uv_size": [ + 3, + 4 + ] + }, + "west": { + "uv": [ + 14, + 16 + ], + "uv_size": [ + 8, + 4 + ] + }, + "up": { + "uv": [ + 5, + 19 + ], + "uv_size": [ + 3, + 8 + ] + }, + "down": { + "uv": [ + 19, + 28 + ], + "uv_size": [ + 3, + -8 + ] + } + } + }, + { + "origin": [ + -1.375, + 1.25, + -11.75 + ], + "size": [ + 1.75, + 2.5, + 4.25 + ], + "uv": { + "north": { + "uv": [ + 37, + 6 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 30, + 26 + ], + "uv_size": [ + 4, + 3 + ] + }, + "south": { + "uv": [ + 16, + 37 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 28, + 30 + ], + "uv_size": [ + 4, + 3 + ] + }, + "up": { + "uv": [ + 17, + 29 + ], + "uv_size": [ + 2, + 4 + ] + }, + "down": { + "uv": [ + 3, + 40 + ], + "uv_size": [ + 2, + -4 + ] + } + } + }, + { + "origin": [ + -2.125, + 2, + -2.875 + ], + "size": [ + 3.25, + 1.5, + 2.75 + ], + "pivot": [ + -0.5, + 2.25, + -2.5 + ], + "rotation": [ + 45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 27, + 4 + ], + "uv_size": [ + 3, + 2 + ] + }, + "east": { + "uv": [ + 37, + 18 + ], + "uv_size": [ + 3, + 2 + ] + }, + "south": { + "uv": [ + 37, + 20 + ], + "uv_size": [ + 3, + 2 + ] + }, + "west": { + "uv": [ + 37, + 22 + ], + "uv_size": [ + 3, + 2 + ] + }, + "up": { + "uv": [ + 32, + 33 + ], + "uv_size": [ + 3, + 3 + ] + }, + "down": { + "uv": [ + 34, + 9 + ], + "uv_size": [ + 3, + -3 + ] + } + } + }, + { + "origin": [ + -2.25, + 3.75, + -12 + ], + "size": [ + 3.5, + 3, + 18.5 + ], + "uv": { + "north": { + "uv": [ + 31, + 0 + ], + "uv_size": [ + 4, + 3 + ] + }, + "east": { + "uv": [ + 8, + 0 + ], + "uv_size": [ + 19, + 3 + ] + }, + "south": { + "uv": [ + 31, + 3 + ], + "uv_size": [ + 4, + 3 + ] + }, + "west": { + "uv": [ + 8, + 3 + ], + "uv_size": [ + 19, + 3 + ] + }, + "up": { + "uv": [ + 0, + 0 + ], + "uv_size": [ + 4, + 19 + ] + }, + "down": { + "uv": [ + 4, + 19 + ], + "uv_size": [ + 4, + -19 + ] + } + } + }, + { + "origin": [ + -1.875, + 4.75, + -11.875 + ], + "size": [ + 2.75, + 3, + 18.25 + ], + "uv": { + "north": { + "uv": [ + 14, + 34 + ], + "uv_size": [ + 3, + 3 + ] + }, + "east": { + "uv": [ + 8, + 6 + ], + "uv_size": [ + 18, + 3 + ] + }, + "south": { + "uv": [ + 34, + 21 + ], + "uv_size": [ + 3, + 3 + ] + }, + "west": { + "uv": [ + 8, + 9 + ], + "uv_size": [ + 18, + 3 + ] + }, + "up": { + "uv": [ + 8, + 12 + ], + "uv_size": [ + 3, + 18 + ] + }, + "down": { + "uv": [ + 11, + 30 + ], + "uv_size": [ + 3, + -18 + ] + } + } + }, + { + "origin": [ + -2.125, + -2.89866, + 3.40497 + ], + "size": [ + 3.25, + 4.5, + 3.5 + ], + "pivot": [ + -0.5, + 0.57009, + 6.21747 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 5, + 27 + ], + "uv_size": [ + 3, + 5 + ] + }, + "east": { + "uv": [ + 22, + 12 + ], + "uv_size": [ + 4, + 5 + ] + }, + "south": { + "uv": [ + 19, + 28 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 22, + 17 + ], + "uv_size": [ + 4, + 5 + ] + }, + "up": { + "uv": [ + 31, + 6 + ], + "uv_size": [ + 3, + 4 + ] + }, + "down": { + "uv": [ + 31, + 26 + ], + "uv_size": [ + 3, + -4 + ] + } + } + }, + { + "origin": [ + -2, + -5.46979, + 4.98488 + ], + "size": [ + 3, + 3.125, + 3.125 + ], + "uv": { + "north": { + "uv": [ + 34, + 24 + ], + "uv_size": [ + 3, + 3 + ] + }, + "east": { + "uv": [ + 25, + 34 + ], + "uv_size": [ + 3, + 3 + ] + }, + "south": { + "uv": [ + 35, + 0 + ], + "uv_size": [ + 3, + 3 + ] + }, + "west": { + "uv": [ + 35, + 3 + ], + "uv_size": [ + 3, + 3 + ] + }, + "up": { + "uv": [ + 8, + 35 + ], + "uv_size": [ + 3, + 3 + ] + }, + "down": { + "uv": [ + 35, + 12 + ], + "uv_size": [ + 3, + -3 + ] + } + } + }, + { + "origin": [ + -2, + 0.47634, + 3.27997 + ], + "size": [ + 3, + 4.125, + 3.125 + ], + "uv": { + "north": { + "uv": [ + 0, + 32 + ], + "uv_size": [ + 3, + 4 + ] + }, + "east": { + "uv": [ + 3, + 32 + ], + "uv_size": [ + 3, + 4 + ] + }, + "south": { + "uv": [ + 32, + 29 + ], + "uv_size": [ + 3, + 4 + ] + }, + "west": { + "uv": [ + 17, + 33 + ], + "uv_size": [ + 3, + 4 + ] + }, + "up": { + "uv": [ + 11, + 35 + ], + "uv_size": [ + 3, + 3 + ] + }, + "down": { + "uv": [ + 35, + 15 + ], + "uv_size": [ + 3, + -3 + ] + } + } + }, + { + "origin": [ + -1.75, + -2.64866, + 2.65497 + ], + "size": [ + 2.5, + 4.75, + 4.75 + ], + "pivot": [ + -0.5, + 0.57009, + 6.21747 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 14, + 29 + ], + "uv_size": [ + 3, + 5 + ] + }, + "east": { + "uv": [ + 0, + 19 + ], + "uv_size": [ + 5, + 5 + ] + }, + "south": { + "uv": [ + 8, + 30 + ], + "uv_size": [ + 3, + 5 + ] + }, + "west": { + "uv": [ + 14, + 20 + ], + "uv_size": [ + 5, + 5 + ] + }, + "up": { + "uv": [ + 11, + 30 + ], + "uv_size": [ + 3, + 5 + ] + }, + "down": { + "uv": [ + 22, + 35 + ], + "uv_size": [ + 3, + -5 + ] + } + } + }, + { + "origin": [ + -1.625, + -4.96979, + 4.23488 + ], + "size": [ + 2.25, + 3.125, + 4.25 + ], + "uv": { + "north": { + "uv": [ + 18, + 37 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 33, + 18 + ], + "uv_size": [ + 4, + 3 + ] + }, + "south": { + "uv": [ + 37, + 24 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 28, + 33 + ], + "uv_size": [ + 4, + 3 + ] + }, + "up": { + "uv": [ + 36, + 27 + ], + "uv_size": [ + 2, + 4 + ] + }, + "down": { + "uv": [ + 28, + 40 + ], + "uv_size": [ + 2, + -4 + ] + } + } + }, + { + "origin": [ + -1.625, + 0.60134, + 2.40497 + ], + "size": [ + 2.25, + 4, + 4.375 + ], + "uv": { + "north": { + "uv": [ + 30, + 36 + ], + "uv_size": [ + 2, + 4 + ] + }, + "east": { + "uv": [ + 26, + 18 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 36, + 31 + ], + "uv_size": [ + 2, + 4 + ] + }, + "west": { + "uv": [ + 22, + 26 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 32, + 36 + ], + "uv_size": [ + 2, + 4 + ] + }, + "down": { + "uv": [ + 34, + 40 + ], + "uv_size": [ + 2, + -4 + ] + } + } + }, + { + "origin": [ + -1.5, + 0.875, + -1.5 + ], + "size": [ + 2, + 0.5, + 6 + ], + "uv": { + "north": { + "uv": [ + 30, + 29 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 38, + 0 + ], + "uv_size": [ + 6, + 1 + ] + }, + "south": { + "uv": [ + 40, + 21 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 38, + 1 + ], + "uv_size": [ + 6, + 1 + ] + }, + "up": { + "uv": [ + 6, + 32 + ], + "uv_size": [ + 2, + 6 + ] + }, + "down": { + "uv": [ + 20, + 39 + ], + "uv_size": [ + 2, + -6 + ] + } + } + }, + { + "origin": [ + -2, + 3.875, + 4.5 + ], + "size": [ + 3, + 1, + 3 + ], + "uv": { + "north": { + "uv": [ + 39, + 38 + ], + "uv_size": [ + 3, + 1 + ] + }, + "east": { + "uv": [ + 40, + 4 + ], + "uv_size": [ + 3, + 1 + ] + }, + "south": { + "uv": [ + 40, + 10 + ], + "uv_size": [ + 3, + 1 + ] + }, + "west": { + "uv": [ + 40, + 11 + ], + "uv_size": [ + 3, + 1 + ] + }, + "up": { + "uv": [ + 35, + 15 + ], + "uv_size": [ + 3, + 3 + ] + }, + "down": { + "uv": [ + 22, + 38 + ], + "uv_size": [ + 3, + -3 + ] + } + } + }, + { + "origin": [ + -1.625, + 4, + 7.5 + ], + "size": [ + 2.25, + 0.75, + 2 + ], + "uv": { + "north": { + "uv": [ + 40, + 22 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 40, + 23 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 25, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 28, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 8, + 38 + ], + "uv_size": [ + 2, + 2 + ] + }, + "down": { + "uv": [ + 38, + 11 + ], + "uv_size": [ + 2, + -2 + ] + } + } + }, + { + "origin": [ + 1, + 0.625, + -7.5 + ], + "size": [ + 0.5, + 4.125, + 5 + ], + "uv": { + "north": { + "uv": [ + 4, + 28 + ], + "uv_size": [ + 1, + 4 + ] + }, + "east": { + "uv": [ + 22, + 22 + ], + "uv_size": [ + 5, + 4 + ] + }, + "south": { + "uv": [ + 10, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 0, + 24 + ], + "uv_size": [ + 5, + 4 + ] + }, + "up": { + "uv": [ + 5, + 36 + ], + "uv_size": [ + 1, + 5 + ] + }, + "down": { + "uv": [ + 27, + 42 + ], + "uv_size": [ + 1, + -5 + ] + } + } + }, + { + "origin": [ + -2.5, + 0.625, + -7.5 + ], + "size": [ + 0.5, + 4.125, + 5 + ], + "uv": { + "north": { + "uv": [ + 11, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "east": { + "uv": [ + 14, + 25 + ], + "uv_size": [ + 5, + 4 + ] + }, + "south": { + "uv": [ + 38, + 11 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 26, + 6 + ], + "uv_size": [ + 5, + 4 + ] + }, + "up": { + "uv": [ + 6, + 38 + ], + "uv_size": [ + 1, + 5 + ] + }, + "down": { + "uv": [ + 7, + 43 + ], + "uv_size": [ + 1, + -5 + ] + } + } + }, + { + "origin": [ + 1.25, + 4.625, + -10 + ], + "size": [ + 0.75, + 1.75, + 9 + ], + "uv": { + "north": { + "uv": [ + 30, + 4 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 26, + 10 + ], + "uv_size": [ + 9, + 2 + ] + }, + "south": { + "uv": [ + 34, + 27 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 26, + 12 + ], + "uv_size": [ + 9, + 2 + ] + }, + "up": { + "uv": [ + 35, + 27 + ], + "uv_size": [ + 1, + 9 + ] + }, + "down": { + "uv": [ + 0, + 45 + ], + "uv_size": [ + 1, + -9 + ] + } + } + }, + { + "origin": [ + -2.875, + 4.625, + -10 + ], + "size": [ + 0.625, + 1.75, + 9 + ], + "uv": { + "north": { + "uv": [ + 19, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 26, + 14 + ], + "uv_size": [ + 9, + 2 + ] + }, + "south": { + "uv": [ + 30, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 26, + 16 + ], + "uv_size": [ + 9, + 2 + ] + }, + "up": { + "uv": [ + 1, + 36 + ], + "uv_size": [ + 1, + 9 + ] + }, + "down": { + "uv": [ + 2, + 45 + ], + "uv_size": [ + 1, + -9 + ] + } + } + }, + { + "origin": [ + 0.375, + 2.625, + -11.5 + ], + "size": [ + 1.375, + 3.625, + 4 + ], + "uv": { + "north": { + "uv": [ + 12, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "east": { + "uv": [ + 26, + 26 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 13, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 27, + 0 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 22, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "down": { + "uv": [ + 23, + 42 + ], + "uv_size": [ + 1, + -4 + ] + } + } + }, + { + "origin": [ + -2.75, + 2.625, + -11.5 + ], + "size": [ + 1.375, + 3.625, + 4 + ], + "uv": { + "north": { + "uv": [ + 24, + 38 + ], + "uv_size": [ + 1, + 4 + ] + }, + "east": { + "uv": [ + 27, + 22 + ], + "uv_size": [ + 4, + 4 + ] + }, + "south": { + "uv": [ + 38, + 27 + ], + "uv_size": [ + 1, + 4 + ] + }, + "west": { + "uv": [ + 0, + 28 + ], + "uv_size": [ + 4, + 4 + ] + }, + "up": { + "uv": [ + 38, + 31 + ], + "uv_size": [ + 1, + 4 + ] + }, + "down": { + "uv": [ + 38, + 39 + ], + "uv_size": [ + 1, + -4 + ] + } + } + }, + { + "origin": [ + -3.5, + -0.125, + -5.875 + ], + "size": [ + 1.5, + 0.75, + 4 + ], + "uv": { + "north": { + "uv": [ + 31, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 38, + 5 + ], + "uv_size": [ + 4, + 1 + ] + }, + "south": { + "uv": [ + 33, + 40 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 38, + 15 + ], + "uv_size": [ + 4, + 1 + ] + }, + "up": { + "uv": [ + 36, + 35 + ], + "uv_size": [ + 2, + 4 + ] + }, + "down": { + "uv": [ + 14, + 41 + ], + "uv_size": [ + 2, + -4 + ] + } + } + }, + { + "origin": [ + -0.75, + -0.875, + -7.5 + ], + "size": [ + 0.5, + 0.625, + 4 + ], + "uv": { + "north": { + "uv": [ + 33, + 21 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 38, + 16 + ], + "uv_size": [ + 4, + 1 + ] + }, + "south": { + "uv": [ + 34, + 9 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 38, + 17 + ], + "uv_size": [ + 4, + 1 + ] + }, + "up": { + "uv": [ + 39, + 11 + ], + "uv_size": [ + 1, + 4 + ] + }, + "down": { + "uv": [ + 20, + 43 + ], + "uv_size": [ + 1, + -4 + ] + } + } + }, + { + "origin": [ + -1.25, + 1.125, + 6.5 + ], + "size": [ + 1.5, + 2.875, + 0.75 + ], + "pivot": [ + -0.5, + 2.5625, + 6.875 + ], + "rotation": [ + 22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 25, + 37 + ], + "uv_size": [ + 2, + 3 + ] + }, + "east": { + "uv": [ + 21, + 39 + ], + "uv_size": [ + 1, + 3 + ] + }, + "south": { + "uv": [ + 38, + 2 + ], + "uv_size": [ + 2, + 3 + ] + }, + "west": { + "uv": [ + 40, + 12 + ], + "uv_size": [ + 1, + 3 + ] + }, + "up": { + "uv": [ + 40, + 39 + ], + "uv_size": [ + 2, + 1 + ] + }, + "down": { + "uv": [ + 40, + 41 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -0.625, + 1.40248, + 1.84024 + ], + "size": [ + 0.25, + 2.875, + 0.625 + ], + "pivot": [ + -0.5, + 3.08998, + 2.02774 + ], + "rotation": [ + -45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 16, + 40 + ], + "uv_size": [ + 1, + 3 + ] + }, + "east": { + "uv": [ + 17, + 40 + ], + "uv_size": [ + 1, + 3 + ] + }, + "south": { + "uv": [ + 18, + 40 + ], + "uv_size": [ + 1, + 3 + ] + }, + "west": { + "uv": [ + 40, + 18 + ], + "uv_size": [ + 1, + 3 + ] + }, + "up": { + "uv": [ + 39, + 8 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 42, + 24 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -0.75, + 2.52748, + 1.46524 + ], + "size": [ + 0.5, + 1.75, + 1 + ], + "pivot": [ + -0.5, + 3.08998, + 2.02774 + ], + "rotation": [ + -22.5, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 35, + 40 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 5, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 41, + 6 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 41, + 12 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 24, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 42, + 26 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -1.375, + 7.75, + 4.5 + ], + "size": [ + 1.75, + 0.375, + 1.875 + ], + "uv": { + "north": { + "uv": [ + 14, + 41 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 41, + 14 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 41, + 18 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 41, + 19 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 39, + 6 + ], + "uv_size": [ + 2, + 2 + ] + }, + "down": { + "uv": [ + 39, + 26 + ], + "uv_size": [ + 2, + -2 + ] + } + } + }, + { + "origin": [ + 0.125, + 8.125, + 4.5 + ], + "size": [ + 0.25, + 0.375, + 1.875 + ], + "uv": { + "north": { + "uv": [ + 42, + 26 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 41, + 20 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 27, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 41, + 24 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 25, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 41, + 27 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + 1.25, + 4.825, + 4 + ], + "size": [ + 0.25, + 0.875, + 1.5 + ], + "uv": { + "north": { + "uv": [ + 28, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 41, + 27 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 28 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 28, + 41 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 26, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 41, + 30 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + -2.5, + 4.825, + 4 + ], + "size": [ + 0.25, + 0.875, + 1.5 + ], + "uv": { + "north": { + "uv": [ + 29, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 41, + 30 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 42, + 29 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 31, + 41 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 41, + 31 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 33, + 43 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + 1.25, + 4.825, + 5.5 + ], + "size": [ + 0.625, + 0.875, + 0.875 + ], + "uv": { + "north": { + "uv": [ + 30, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 31, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 42, + 31 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 32, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 42, + 32 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 35, + 43 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -2.875, + 4.825, + 5.5 + ], + "size": [ + 0.625, + 0.875, + 0.875 + ], + "uv": { + "north": { + "uv": [ + 42, + 35 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 42, + 36 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 42, + 38 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 42, + 39 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 42, + 40 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 42, + 42 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + 0.125, + 8.5, + 5 + ], + "size": [ + 0.25, + 0.375, + 1.125 + ], + "uv": { + "north": { + "uv": [ + 42, + 42 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 43, + 2 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 43, + 3 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 43, + 4 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 5, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 6 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -1.375, + 8.125, + 4.5 + ], + "size": [ + 0.25, + 0.375, + 1.875 + ], + "uv": { + "north": { + "uv": [ + 6, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 41, + 33 + ], + "uv_size": [ + 2, + 1 + ] + }, + "south": { + "uv": [ + 43, + 6 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 41, + 34 + ], + "uv_size": [ + 2, + 1 + ] + }, + "up": { + "uv": [ + 34, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 41, + 37 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + -1.375, + 8.5, + 5 + ], + "size": [ + 0.25, + 0.375, + 1.125 + ], + "uv": { + "north": { + "uv": [ + 7, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 43, + 8 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 43, + 9 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 43, + 10 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 11, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 12 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -0.75, + 7.75, + -11 + ], + "size": [ + 0.5, + 0.375, + 1.375 + ], + "uv": { + "north": { + "uv": [ + 12, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 13, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 14, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 43, + 14 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 16, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 17, + 44 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + 1, + 3.375, + -14.625 + ], + "size": [ + 0.75, + 2, + 2 + ], + "pivot": [ + 13.5, + -5.25, + -14.5 + ], + "rotation": [ + -45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 36, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 39, + 26 + ], + "uv_size": [ + 2, + 2 + ] + }, + "south": { + "uv": [ + 37, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 39, + 28 + ], + "uv_size": [ + 2, + 2 + ] + }, + "up": { + "uv": [ + 38, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 39, + 43 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + -2.75, + 3.375, + -14.625 + ], + "size": [ + 0.75, + 2, + 2 + ], + "pivot": [ + -13.5, + -5.25, + -14.5 + ], + "rotation": [ + -45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 40, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 39, + 30 + ], + "uv_size": [ + 2, + 2 + ] + }, + "south": { + "uv": [ + 41, + 41 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 39, + 32 + ], + "uv_size": [ + 2, + 2 + ] + }, + "up": { + "uv": [ + 42, + 2 + ], + "uv_size": [ + 1, + 2 + ] + }, + "down": { + "uv": [ + 3, + 44 + ], + "uv_size": [ + 1, + -2 + ] + } + } + }, + { + "origin": [ + 1.75, + 3.875, + -14.125 + ], + "size": [ + 0.25, + 1, + 1 + ], + "pivot": [ + 13.5, + -5.25, + -14.5 + ], + "rotation": [ + -45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 18, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 43, + 18 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 43, + 19 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 20, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 43, + 20 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 21, + 44 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -3, + 3.875, + -14.125 + ], + "size": [ + 0.25, + 1, + 1 + ], + "pivot": [ + -13.5, + -5.25, + -14.5 + ], + "rotation": [ + -45, + 0, + 0 + ], + "uv": { + "north": { + "uv": [ + 43, + 21 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 22, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 43, + 22 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 43, + 23 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 24, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 25 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -1.5, + 4.25, + -13.5 + ], + "size": [ + 2, + 2, + 1.5 + ], + "pivot": [ + -0.5, + 5.25, + -12.75 + ], + "rotation": [ + 0, + 0, + -45 + ], + "uv": { + "north": { + "uv": [ + 39, + 34 + ], + "uv_size": [ + 2, + 2 + ] + }, + "east": { + "uv": [ + 36, + 39 + ], + "uv_size": [ + 2, + 2 + ] + }, + "south": { + "uv": [ + 39, + 36 + ], + "uv_size": [ + 2, + 2 + ] + }, + "west": { + "uv": [ + 38, + 39 + ], + "uv_size": [ + 2, + 2 + ] + }, + "up": { + "uv": [ + 40, + 2 + ], + "uv_size": [ + 2, + 2 + ] + }, + "down": { + "uv": [ + 3, + 42 + ], + "uv_size": [ + 2, + -2 + ] + } + } + }, + { + "origin": [ + -1.5, + 5.25, + 6.375 + ], + "size": [ + 2, + 2, + 0.25 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 8, + 40 + ], + "uv_size": [ + 2, + 2 + ] + }, + "east": { + "uv": [ + 4, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 40, + 8 + ], + "uv_size": [ + 2, + 2 + ] + }, + "west": { + "uv": [ + 42, + 5 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 41, + 37 + ], + "uv_size": [ + 2, + 1 + ] + }, + "down": { + "uv": [ + 42, + 8 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -0.75, + 6, + 6.625 + ], + "size": [ + 0.5, + 0.5, + 0.125 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 25, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "east": { + "uv": [ + 43, + 25 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 26, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "west": { + "uv": [ + 43, + 26 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 27, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 28 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + 0.25, + 5.375, + 6.625 + ], + "size": [ + 0.125, + 1.75, + 0.125 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 8, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 42, + 8 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 9, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 10, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 28, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 29 + ], + "uv_size": [ + 1, + -1 + ] + } + } + }, + { + "origin": [ + -1.25, + 7, + 6.625 + ], + "size": [ + 1.5, + 0.125, + 0.125 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 11, + 42 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 29, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 42, + 12 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 43, + 29 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 13, + 42 + ], + "uv_size": [ + 2, + 1 + ] + }, + "down": { + "uv": [ + 42, + 14 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -1.25, + 5.375, + 6.625 + ], + "size": [ + 1.5, + 0.125, + 0.125 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 42, + 15 + ], + "uv_size": [ + 2, + 1 + ] + }, + "east": { + "uv": [ + 30, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "south": { + "uv": [ + 42, + 16 + ], + "uv_size": [ + 2, + 1 + ] + }, + "west": { + "uv": [ + 43, + 30 + ], + "uv_size": [ + 1, + 1 + ] + }, + "up": { + "uv": [ + 42, + 17 + ], + "uv_size": [ + 2, + 1 + ] + }, + "down": { + "uv": [ + 21, + 43 + ], + "uv_size": [ + 2, + -1 + ] + } + } + }, + { + "origin": [ + -1.375, + 5.375, + 6.625 + ], + "size": [ + 0.125, + 1.75, + 0.125 + ], + "pivot": [ + -0.5, + 6.25, + 7.5 + ], + "rotation": [ + 0, + 0, + 45 + ], + "uv": { + "north": { + "uv": [ + 15, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "east": { + "uv": [ + 19, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "south": { + "uv": [ + 42, + 21 + ], + "uv_size": [ + 1, + 2 + ] + }, + "west": { + "uv": [ + 23, + 42 + ], + "uv_size": [ + 1, + 2 + ] + }, + "up": { + "uv": [ + 31, + 43 + ], + "uv_size": [ + 1, + 1 + ] + }, + "down": { + "uv": [ + 43, + 32 + ], + "uv_size": [ + 1, + -1 + ] + } + } + } + ] + }, + { + "name": "bone", + "parent": "group", + "pivot": [ + -0.49601, + 5.23502, + -13.29665 + ], + "cubes": [ + { + "origin": [ + -0.99601, + 4.73502, + -13.29665 + ], + "size": [ + 1, + 1, + 0 + ], + "uv": { + "north": { + "uv": [ + 128, + 0 + ], + "uv_size": [ + -64, + 64 + ] + }, + "east": { + "uv": [ + 128, + 0 + ], + "uv_size": [ + 0, + 1 + ] + }, + "south": { + "uv": [ + 64, + 0 + ], + "uv_size": [ + 64, + 64 + ] + }, + "west": { + "uv": [ + 128, + 0 + ], + "uv_size": [ + 0, + 1 + ] + }, + "up": { + "uv": [ + 128, + 1 + ], + "uv_size": [ + 0, + -1 + ] + }, + "down": { + "uv": [ + 128, + 1 + ], + "uv_size": [ + 0, + -1 + ] + } + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/models/block/stargate.json b/common/src/main/resources/assets/azurelib/models/block/stargate.json new file mode 100644 index 000000000..bc6977543 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/block/stargate.json @@ -0,0 +1,96 @@ +{ + "credit": "Made with Blockbench", + "parent": "builtin/entity", + "texture_size": [ + 256, + 256 + ], + "display": { + "thirdperson_righthand": { + "scale": [ + 0.1, + 0.1, + 0.1 + ] + }, + "thirdperson_lefthand": { + "scale": [ + 0.1, + 0.1, + 0.1 + ] + }, + "firstperson_righthand": { + "rotation": [ + 0, + -64, + 0 + ], + "scale": [ + 0.1, + 0.1, + 0.1 + ] + }, + "firstperson_lefthand": { + "rotation": [ + 0, + -64, + 0 + ], + "scale": [ + 0.1, + 0.1, + 0.1 + ] + }, + "ground": { + "translation": [ + 0, + 1.75, + 0 + ], + "scale": [ + 0.1, + 0.1, + 0.1 + ] + }, + "gui": { + "rotation": [ + 0, + -36, + 0 + ], + "translation": [ + 0, + -6, + 0 + ], + "scale": [ + 0.18, + 0.18, + 0.18 + ] + }, + "head": { + "scale": [ + 0, + 0, + 0 + ] + }, + "fixed": { + "translation": [ + 0, + -6, + 0 + ], + "scale": [ + 0.2, + 0.2, + 0.2 + ] + } + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_boots.json b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_boots.json new file mode 100644 index 000000000..befab1952 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_boots" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_chestplate.json b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_chestplate.json new file mode 100644 index 000000000..96425b55a --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_chestplate" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_helmet.json b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_helmet.json new file mode 100644 index 000000000..0229c662d --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_helmet.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_helmet" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_leggings.json b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_leggings.json new file mode 100644 index 000000000..1afbd089c --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/az_doomicorn_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_leggings" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/az_pistol.json b/common/src/main/resources/assets/azurelib/models/item/az_pistol.json new file mode 100644 index 000000000..4164a6ee9 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/az_pistol.json @@ -0,0 +1,96 @@ +{ + "credit": "Made with Blockbench", + "parent": "builtin/entity", + "texture_size": [ + 128, + 64 + ], + "display": { + "thirdperson_righthand": { + "translation": [ + 0, + -1.25, + -0.25 + ], + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "thirdperson_lefthand": { + "translation": [ + 0, + -1.25, + -0.25 + ], + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "firstperson_righthand": { + "translation": [ + -9.5, + -5.5, + -5.75 + ] + }, + "firstperson_lefthand": { + "translation": [ + -8.75, + -5.5, + -5.75 + ] + }, + "ground": { + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "gui": { + "rotation": [ + 40, + -38, + 0 + ], + "translation": [ + -1, + -1.25, + 0 + ], + "scale": [ + 0.7, + 0.7, + 0.7 + ] + }, + "head": { + "scale": [ + 0, + 0, + 0 + ] + }, + "fixed": { + "rotation": [ + 0, + -90, + 0 + ], + "translation": [ + -1.75, + -2.5, + -0.25 + ], + "scale": [ + 0.8, + 0.8, + 0.8 + ] + } + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/models/item/doomicorn_boots.json b/common/src/main/resources/assets/azurelib/models/item/doomicorn_boots.json new file mode 100644 index 000000000..befab1952 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/doomicorn_boots.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_boots" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/doomicorn_chestplate.json b/common/src/main/resources/assets/azurelib/models/item/doomicorn_chestplate.json new file mode 100644 index 000000000..96425b55a --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/doomicorn_chestplate.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_chestplate" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/doomicorn_helmet.json b/common/src/main/resources/assets/azurelib/models/item/doomicorn_helmet.json new file mode 100644 index 000000000..0229c662d --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/doomicorn_helmet.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_helmet" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/doomicorn_leggings.json b/common/src/main/resources/assets/azurelib/models/item/doomicorn_leggings.json new file mode 100644 index 000000000..1afbd089c --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/doomicorn_leggings.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/doomicorn_leggings" + } +} diff --git a/common/src/main/resources/assets/azurelib/models/item/pistol.json b/common/src/main/resources/assets/azurelib/models/item/pistol.json new file mode 100644 index 000000000..4164a6ee9 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/pistol.json @@ -0,0 +1,96 @@ +{ + "credit": "Made with Blockbench", + "parent": "builtin/entity", + "texture_size": [ + 128, + 64 + ], + "display": { + "thirdperson_righthand": { + "translation": [ + 0, + -1.25, + -0.25 + ], + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "thirdperson_lefthand": { + "translation": [ + 0, + -1.25, + -0.25 + ], + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "firstperson_righthand": { + "translation": [ + -9.5, + -5.5, + -5.75 + ] + }, + "firstperson_lefthand": { + "translation": [ + -8.75, + -5.5, + -5.75 + ] + }, + "ground": { + "scale": [ + 0.5, + 0.5, + 0.5 + ] + }, + "gui": { + "rotation": [ + 40, + -38, + 0 + ], + "translation": [ + -1, + -1.25, + 0 + ], + "scale": [ + 0.7, + 0.7, + 0.7 + ] + }, + "head": { + "scale": [ + 0, + 0, + 0 + ] + }, + "fixed": { + "rotation": [ + 0, + -90, + 0 + ], + "translation": [ + -1.75, + -2.5, + -0.25 + ], + "scale": [ + 0.8, + 0.8, + 0.8 + ] + } + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/models/item/stargate.json b/common/src/main/resources/assets/azurelib/models/item/stargate.json new file mode 100644 index 000000000..087c7af00 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/models/item/stargate.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "azurelib:item/stargate" + } +} \ No newline at end of file diff --git a/common/src/main/resources/assets/azurelib/textures/block/stargate.png b/common/src/main/resources/assets/azurelib/textures/block/stargate.png new file mode 100644 index 000000000..7ef23d629 Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/block/stargate.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png b/common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png new file mode 100644 index 000000000..b59ba8b11 Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png.mcmeta b/common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png.mcmeta new file mode 100644 index 000000000..3d481d190 --- /dev/null +++ b/common/src/main/resources/assets/azurelib/textures/entity/doomhunter.png.mcmeta @@ -0,0 +1,15 @@ +{ + "animation": { + "interpolate": false, + "frames": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 0 + ] + } +} diff --git a/common/src/main/resources/assets/azurelib/textures/entity/marauder.png b/common/src/main/resources/assets/azurelib/textures/entity/marauder.png new file mode 100644 index 000000000..0d1ba734d Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/entity/marauder.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/entity/marauder_glowmask.png b/common/src/main/resources/assets/azurelib/textures/entity/marauder_glowmask.png new file mode 100644 index 000000000..268e05431 Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/entity/marauder_glowmask.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/entity/ovamorph.png b/common/src/main/resources/assets/azurelib/textures/entity/ovamorph.png new file mode 100644 index 000000000..f561503ec Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/entity/ovamorph.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_boots.png b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_boots.png new file mode 100644 index 000000000..ccb401b3b Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_boots.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_chestplate.png b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_chestplate.png new file mode 100644 index 000000000..45562d971 Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_chestplate.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_helmet.png b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_helmet.png new file mode 100644 index 000000000..c969da146 Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_helmet.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_leggings.png b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_leggings.png new file mode 100644 index 000000000..5d252cff2 Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/item/az_doomicorn_leggings.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/item/doomicorn.png b/common/src/main/resources/assets/azurelib/textures/item/doomicorn.png new file mode 100644 index 000000000..a504ce681 Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/item/doomicorn.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/item/doomicorn_boots.png b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_boots.png new file mode 100644 index 000000000..ccb401b3b Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_boots.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/item/doomicorn_chestplate.png b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_chestplate.png new file mode 100644 index 000000000..45562d971 Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_chestplate.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/item/doomicorn_helmet.png b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_helmet.png new file mode 100644 index 000000000..c969da146 Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_helmet.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/item/doomicorn_leggings.png b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_leggings.png new file mode 100644 index 000000000..5d252cff2 Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/item/doomicorn_leggings.png differ diff --git a/common/src/main/resources/assets/azurelib/textures/item/pistol.png b/common/src/main/resources/assets/azurelib/textures/item/pistol.png new file mode 100644 index 000000000..290e21ba1 Binary files /dev/null and b/common/src/main/resources/assets/azurelib/textures/item/pistol.png differ diff --git a/common/src/main/resources/azurelib.accesswidener b/common/src/main/resources/azurelib.accesswidener index 4b9ef39ae..a5e636392 100644 --- a/common/src/main/resources/azurelib.accesswidener +++ b/common/src/main/resources/azurelib.accesswidener @@ -32,42 +32,6 @@ accessible method net/minecraft/client/renderer/RenderType create (Ljava/lang/St accessible field com/mojang/blaze3d/vertex/BufferBuilder building Z accessible class net/minecraft/world/level/block/entity/BlockEntityType$BlockEntitySupplier -# Brain -accessible field net/minecraft/world/entity/ai/Brain sensors Ljava/util/Map; -accessible method net/minecraft/world/entity/ai/Brain memories ()Ljava/util/stream/Stream; -accessible field net/minecraft/world/entity/ai/Brain memories Ljava/util/Map; -accessible field net/minecraft/world/entity/ai/Brain activityRequirements Ljava/util/Map; -accessible field net/minecraft/world/entity/ai/Brain activityMemoriesToEraseWhenStopped Ljava/util/Map; -accessible field net/minecraft/world/entity/ai/Brain availableBehaviorsByPriority Ljava/util/Map; -accessible field net/minecraft/world/entity/ai/behavior/Behavior entryCondition Ljava/util/Map; -accessible class net/minecraft/world/entity/ai/Brain$Provider -extendable class net/minecraft/world/entity/ai/Brain$Provider -accessible method net/minecraft/world/entity/ai/Brain$Provider (Ljava/util/Collection;Ljava/util/Collection;)V -accessible method net/minecraft/world/entity/ai/Brain setMemoryInternal (Lnet/minecraft/world/entity/ai/memory/MemoryModuleType;Ljava/util/Optional;)V -accessible method net/minecraft/world/entity/ai/Brain$MemoryValue setMemoryInternal (Lnet/minecraft/world/entity/ai/Brain;)V -accessible method net/minecraft/world/entity/ai/Brain forgetOutdatedMemories ()V -extendable method net/minecraft/world/entity/ai/Brain forgetOutdatedMemories ()V -accessible field net/minecraft/world/entity/ai/Brain coreActivities Ljava/util/Set; -accessible method net/minecraft/world/entity/ai/Brain setCoreActivities (Ljava/util/Set;)V -extendable method net/minecraft/world/entity/ai/Brain activityRequirementsAreMet (Lnet/minecraft/world/entity/schedule/Activity;)Z -extendable method net/minecraft/world/entity/ai/Brain setActiveActivity (Lnet/minecraft/world/entity/schedule/Activity;)V - -# Behaviour -accessible method net/minecraft/world/entity/ai/behavior/Behavior tryStart (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;J)Z -extendable method net/minecraft/world/entity/ai/behavior/Behavior tryStart (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;J)Z -accessible field net/minecraft/world/entity/ai/behavior/Behavior endTimestamp J -accessible field net/minecraft/world/entity/ai/behavior/Behavior status Lnet/minecraft/world/entity/ai/behavior/Behavior$Status; -accessible method net/minecraft/world/entity/ai/behavior/Behavior getStatus ()Lnet/minecraft/world/entity/ai/behavior/Behavior$Status; -accessible method net/minecraft/world/entity/ai/behavior/Behavior hasRequiredMemories (Lnet/minecraft/world/entity/LivingEntity;)Z -extendable method net/minecraft/world/entity/ai/behavior/Behavior hasRequiredMemories (Lnet/minecraft/world/entity/LivingEntity;)Z -accessible field net/minecraft/world/entity/ai/behavior/GateBehavior behaviors Lnet/minecraft/world/entity/ai/behavior/ShufflingList; - -# Sensor -accessible method net/minecraft/world/entity/ai/sensing/Sensor tick (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;)V -extendable method net/minecraft/world/entity/ai/sensing/Sensor tick (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;)V -accessible field net/minecraft/world/entity/ai/sensing/Sensor scanRate I -accessible field net/minecraft/world/entity/ai/sensing/Sensor RANDOM Lnet/minecraft/util/RandomSource; - # World accessible method net/minecraft/world/level/Level getEntities ()Lnet/minecraft/world/level/entity/LevelEntityGetter; accessible method net/minecraft/client/multiplayer/ClientLevel getEntities ()Lnet/minecraft/world/level/entity/LevelEntityGetter; diff --git a/fabric/build.gradle b/fabric/build.gradle index 83f2882b7..389cadf8f 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -2,6 +2,7 @@ plugins { id 'multiloader-loader' id 'fabric-loom' version "${fabric_loom_version}" id 'me.modmuss50.mod-publish-plugin' + id 'com.diffplug.spotless' version "7.0.0.BETA3" } dependencies { @@ -65,4 +66,4 @@ if (file('key.properties').exists()) { minecraftVersions.add(project.minecraft_version) } } -} \ No newline at end of file +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java index c4139b9e9..cacda4525 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/ClientListener.java @@ -1,49 +1,101 @@ package mod.azure.azurelib.fabric; import com.mojang.blaze3d.platform.InputConstants; -import mod.azure.azurelib.common.api.client.helper.ClientUtils; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.network.packet.*; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; +import mod.azure.azurelib.fabric.core2.example.entities.ovamorph.OvamorphRenderer; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; import net.minecraft.client.KeyMapping; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; import org.lwjgl.glfw.GLFW; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.network.packet.*; +import mod.azure.azurelib.core2.render.armor.AzArmorRendererRegistry; +import mod.azure.azurelib.core2.render.item.AzItemRendererRegistry; +import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; +import mod.azure.azurelib.fabric.core2.example.armors.AzDoomArmorRenderer; +import mod.azure.azurelib.fabric.core2.example.blocks.StargateRender; +import mod.azure.azurelib.fabric.core2.example.entities.doomhunter.DoomHunterRenderer; +import mod.azure.azurelib.fabric.core2.example.entities.marauder.MarauderRenderer; +import mod.azure.azurelib.fabric.core2.example.items.AzPistolRenderer; + public final class ClientListener implements ClientModInitializer { @Override public void onInitializeClient() { if (AzureLib.hasKeyBindsInitialized) { ClientUtils.RELOAD = new KeyMapping( - "key.azurelib.reload", - InputConstants.Type.KEYSYM, - GLFW.GLFW_KEY_R, - "category.azurelib.binds" + "key.azurelib.reload", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_R, + "category.azurelib.binds" ); KeyBindingHelper.registerKeyBinding(ClientUtils.RELOAD); ClientUtils.SCOPE = new KeyMapping( - "key.azurelib.scope", - InputConstants.Type.KEYSYM, - GLFW.GLFW_KEY_LEFT_ALT, - "category.azurelib.binds" + "key.azurelib.scope", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_LEFT_ALT, + "category.azurelib.binds" ); KeyBindingHelper.registerKeyBinding(ClientUtils.SCOPE); ClientUtils.FIRE_WEAPON = new KeyMapping( - "key.azurelib.fire", - InputConstants.Type.KEYSYM, - GLFW.GLFW_KEY_UNKNOWN, - "category.azurelib.binds" + "key.azurelib.fire", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_UNKNOWN, + "category.azurelib.binds" ); KeyBindingHelper.registerKeyBinding(ClientUtils.FIRE_WEAPON); } - ClientPlayNetworking.registerGlobalReceiver(BlockEntityAnimTriggerPacket.TYPE, (packet, context) -> packet.handle()); - ClientPlayNetworking.registerGlobalReceiver(BlockEntityAnimDataSyncPacket.TYPE, (packet, context) -> packet.handle()); + ClientPlayNetworking.registerGlobalReceiver( + BlockEntityAnimTriggerPacket.TYPE, + (packet, context) -> packet.handle() + ); + ClientPlayNetworking.registerGlobalReceiver( + BlockEntityAnimDataSyncPacket.TYPE, + (packet, context) -> packet.handle() + ); ClientPlayNetworking.registerGlobalReceiver(EntityAnimTriggerPacket.TYPE, (packet, context) -> packet.handle()); - ClientPlayNetworking.registerGlobalReceiver(EntityAnimDataSyncPacket.TYPE, (packet, context) -> packet.handle()); + ClientPlayNetworking.registerGlobalReceiver( + AzEntityDispatchCommandPacket.TYPE, + (packet, context) -> packet.handle() + ); + ClientPlayNetworking.registerGlobalReceiver( + AzItemStackDispatchCommandPacket.TYPE, + (packet, context) -> packet.handle() + ); + ClientPlayNetworking.registerGlobalReceiver( + AzBlockEntityDispatchCommandPacket.TYPE, + (packet, context) -> packet.handle() + ); + ClientPlayNetworking.registerGlobalReceiver( + EntityAnimDataSyncPacket.TYPE, + (packet, context) -> packet.handle() + ); ClientPlayNetworking.registerGlobalReceiver(AnimTriggerPacket.TYPE, (packet, context) -> packet.handle()); ClientPlayNetworking.registerGlobalReceiver(AnimDataSyncPacket.TYPE, (packet, context) -> packet.handle()); ClientPlayNetworking.registerGlobalReceiver(SendConfigDataPacket.TYPE, (packet, context) -> packet.handle()); + + AzItemRendererRegistry.register(FabricAzureLibMod.AZ_PISTOL, AzPistolRenderer::new); + AzArmorRendererRegistry.register( + AzDoomArmorRenderer::new, + FabricAzureLibMod.AZ_DOOM_HELMET, + FabricAzureLibMod.AZ_DOOM_CHESTPLATE, + FabricAzureLibMod.AZ_DOOM_LEGGINGS, + FabricAzureLibMod.AZ_DOOM_BOOTS + ); + EntityRendererRegistry.register(ExampleEntityTypes.DOOMHUNTER, DoomHunterRenderer::new); + EntityRendererRegistry.register(ExampleEntityTypes.MARAUDER, MarauderRenderer::new); + EntityRendererRegistry.register(ExampleEntityTypes.OVAMORPH, OvamorphRenderer::new); + BlockRenderLayerMap.INSTANCE.putBlock(FabricAzureLibMod.STARGATE, RenderType.translucent()); + BlockEntityRenderers.register( + ExampleEntityTypes.STARGATE, + (BlockEntityRendererProvider.Context rendererDispatcherIn) -> new StargateRender() + ); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java index 1b5c8c2f5..5e01975a4 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/FabricAzureLibMod.java @@ -1,31 +1,48 @@ package mod.azure.azurelib.fabric; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.AzureLibMod; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; -import mod.azure.azurelib.common.internal.common.config.AzureLibConfig; -import mod.azure.azurelib.common.internal.common.config.format.ConfigFormats; -import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import mod.azure.azurelib.common.internal.common.network.packet.*; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; -import mod.azure.azurelib.fabric.platform.FabricAzureLibNetwork; -import mod.azure.azurelib.sblforked.SBLConstants; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.material.PushReaction; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.AzureLibMod; +import mod.azure.azurelib.common.internal.common.config.AzureLibConfig; +import mod.azure.azurelib.common.internal.common.config.format.ConfigFormats; +import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; +import mod.azure.azurelib.common.internal.common.network.packet.*; +import mod.azure.azurelib.core2.animation.cache.AzIdentityRegistry; +import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; +import mod.azure.azurelib.fabric.core2.example.armors.AzDoomArmor; +import mod.azure.azurelib.fabric.core2.example.blocks.Stargate; +import mod.azure.azurelib.fabric.core2.example.items.AzPistol; +import mod.azure.azurelib.fabric.platform.FabricAzureLibNetwork; public final class FabricAzureLibMod implements ModInitializer { + public static final Block STARGATE = new Stargate( + BlockBehaviour.Properties.of().sound(SoundType.DRIPSTONE_BLOCK).strength(5.0f, 8.0f).noOcclusion() + ); + + public static final Item AZ_PISTOL = new AzPistol(); + + public static final Item AZ_DOOM_HELMET = new AzDoomArmor(ArmorItem.Type.HELMET); + + public static final Item AZ_DOOM_CHESTPLATE = new AzDoomArmor(ArmorItem.Type.CHESTPLATE); + + public static final Item AZ_DOOM_LEGGINGS = new AzDoomArmor(ArmorItem.Type.LEGGINGS); + + public static final Item AZ_DOOM_BOOTS = new AzDoomArmor(ArmorItem.Type.BOOTS); + @Override public void onInitialize() { - SBLConstants.SBL_LOADER.init(null); ConfigIO.FILE_WATCH_MANAGER.startService(); AzureLib.initialize(); AzureLibMod.initRegistry(); @@ -35,9 +52,47 @@ public void onInitialize() { PayloadTypeRegistry.playS2C().register(BlockEntityAnimTriggerPacket.TYPE, BlockEntityAnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(BlockEntityAnimDataSyncPacket.TYPE, BlockEntityAnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(EntityAnimTriggerPacket.TYPE, EntityAnimTriggerPacket.CODEC); + PayloadTypeRegistry.playS2C() + .register(AzBlockEntityDispatchCommandPacket.TYPE, AzBlockEntityDispatchCommandPacket.CODEC); + PayloadTypeRegistry.playS2C().register(AzEntityDispatchCommandPacket.TYPE, AzEntityDispatchCommandPacket.CODEC); + PayloadTypeRegistry.playS2C() + .register(AzItemStackDispatchCommandPacket.TYPE, AzItemStackDispatchCommandPacket.CODEC); PayloadTypeRegistry.playS2C().register(EntityAnimDataSyncPacket.TYPE, EntityAnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(AnimTriggerPacket.TYPE, AnimTriggerPacket.CODEC); PayloadTypeRegistry.playS2C().register(AnimDataSyncPacket.TYPE, AnimDataSyncPacket.CODEC); PayloadTypeRegistry.playS2C().register(SendConfigDataPacket.TYPE, SendConfigDataPacket.CODEC); + Registry.register(BuiltInRegistries.BLOCK, AzureLib.modResource("stargate"), STARGATE); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("stargate"), + new BlockItem(STARGATE, new Item.Properties()) + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("az_pistol"), + AZ_PISTOL + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("az_doomicorn_helmet"), + AZ_DOOM_HELMET + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("az_doomicorn_chestplate"), + AZ_DOOM_CHESTPLATE + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("az_doomicorn_leggings"), + AZ_DOOM_LEGGINGS + ); + Registry.register( + BuiltInRegistries.ITEM, + AzureLib.modResource("az_doomicorn_boots"), + AZ_DOOM_BOOTS + ); + ExampleEntityTypes.initialize(); + AzIdentityRegistry.register(AZ_DOOM_HELMET, AZ_DOOM_CHESTPLATE, AZ_DOOM_LEGGINGS, AZ_DOOM_BOOTS, AZ_PISTOL); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java new file mode 100644 index 000000000..1bf13797d --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/ExampleEntityTypes.java @@ -0,0 +1,54 @@ +package mod.azure.azurelib.fabric.core2.example; + +import mod.azure.azurelib.fabric.core2.example.entities.ovamorph.Ovamorph; +import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; +import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.block.entity.BlockEntityType; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.fabric.FabricAzureLibMod; +import mod.azure.azurelib.fabric.core2.example.blocks.StargateBlockEntity; +import mod.azure.azurelib.fabric.core2.example.entities.doomhunter.DoomHunter; +import mod.azure.azurelib.fabric.core2.example.entities.marauder.MarauderEntity; + +public class ExampleEntityTypes { + + public static final EntityType DOOMHUNTER = register( + "doomhunter", + EntityType.Builder.of(DoomHunter::new, MobCategory.MONSTER).sized(3.0f, 7.0f) + ); + + public static final EntityType MARAUDER = register( + "marauder", + EntityType.Builder.of(MarauderEntity::new, MobCategory.MONSTER).sized(1.5f, 2.6f) + ); + + public static final EntityType OVAMORPH = register( + "ovamorph", + EntityType.Builder.of(Ovamorph::new, MobCategory.MONSTER).sized(0.98f, 0.98f) + ); + + private static EntityType register(String name, EntityType.Builder builder) { + var entityType = builder.build(name); + var resourceLocation = AzureLib.modResource(name); + Registry.register(BuiltInRegistries.ENTITY_TYPE, resourceLocation, entityType); + return entityType; + } + + public static BlockEntityType STARGATE = Registry.register( + BuiltInRegistries.BLOCK_ENTITY_TYPE, + AzureLib.modResource("stargate"), + FabricBlockEntityTypeBuilder.create(StargateBlockEntity::new, FabricAzureLibMod.STARGATE).build(null) + );; + + public static void initialize() { + FabricDefaultAttributeRegistry.register(DOOMHUNTER, DoomHunter.createMonsterAttributes()); + FabricDefaultAttributeRegistry.register(MARAUDER, MarauderEntity.createMonsterAttributes()); + FabricDefaultAttributeRegistry.register(OVAMORPH, Ovamorph.createMonsterAttributes()); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/MoveAnalysis.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/MoveAnalysis.java new file mode 100644 index 000000000..30c51d2d0 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/MoveAnalysis.java @@ -0,0 +1,60 @@ +package mod.azure.azurelib.fabric.core2.example; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; + +public class MoveAnalysis { + + private final Entity entity; + + private int lastTick; + + private Vec3 lastPosition; + + private double deltaX; + + private double deltaY; + + private double deltaZ; + + public MoveAnalysis(Entity entity) { + this.entity = entity; + this.lastPosition = entity.position(); + } + + public void update() { + if (entity.tickCount == lastTick) { + // Only update on tick differences. + return; + } + + var prevPos = lastPosition; + var prevPosX = prevPos.x; + var prevPosY = prevPos.y; + var prevPosZ = prevPos.z; + + var pos = entity.position(); + var posX = pos.x; + var posY = pos.y; + var posZ = pos.z; + + this.deltaX = posX - prevPosX; + this.deltaY = posY - prevPosY; + this.deltaZ = posZ - prevPosZ; + + this.lastPosition = entity.position(); + this.lastTick = entity.tickCount; + } + + public boolean isMovingHorizontally() { + return deltaX != 0 || deltaZ != 0; + } + + public boolean isMovingVertically() { + return deltaY != 0; + } + + public boolean isMoving() { + return isMovingHorizontally() || isMovingVertically(); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmor.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmor.java new file mode 100644 index 000000000..aecd60461 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmor.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ArmorItem; +import net.minecraft.world.item.ArmorMaterials; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +public class AzDoomArmor extends ArmorItem { + + private final AzDoomArmorAnimationDispatcher dispatcher; + + public AzDoomArmor(Type type) { + super(ArmorMaterials.NETHERITE, type, new Properties()); + this.dispatcher = new AzDoomArmorAnimationDispatcher(); + } + + @Override + public @NotNull InteractionResultHolder swapWithEquipmentSlot( + Item item, + Level level, + Player player, + InteractionHand hand + ) { + var result = super.swapWithEquipmentSlot(item, level, player, hand); + + if (!level.isClientSide) { + var slot = getEquipmentSlot(); + var itemStack = player.getItemBySlot(slot); + dispatcher.equip(player, itemStack); + } + + return result; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimationDispatcher.java new file mode 100644 index 000000000..899d0649f --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimationDispatcher.java @@ -0,0 +1,15 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; + +import mod.azure.azurelib.core2.animation.dispatch.command.AzCommand; + +public class AzDoomArmorAnimationDispatcher { + + private static final AzCommand EQUIP = AzCommand.create("base_controller", "equipping"); + + public void equip(Entity entity, ItemStack itemStack) { + EQUIP.sendForItem(entity, itemStack); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimator.java new file mode 100644 index 000000000..d7a7dfa3e --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorAnimator.java @@ -0,0 +1,30 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; + +public class AzDoomArmorAnimator extends AzItemAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource( + "animations/item/doomicorn.animation.json" + ); + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + AzAnimationController.builder(this, "base_controller") + .build() + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(ItemStack animatable) { + return ANIMATIONS; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorBoneProvider.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorBoneProvider.java new file mode 100644 index 000000000..21d4542f7 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorBoneProvider.java @@ -0,0 +1,30 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import mod.azure.azurelib.core2.model.AzBakedModel; +import mod.azure.azurelib.core2.model.AzBone; +import mod.azure.azurelib.core2.render.armor.bone.AzDefaultArmorBoneProvider; + +public class AzDoomArmorBoneProvider extends AzDefaultArmorBoneProvider { + + // Only models I have on for armors with animations, the arm/legs are named wrong and i just didnt want to load it + // in bb again to rename, this should be a feature kept though + @Override + public AzBone getLeftBootBone(AzBakedModel model) { + return model.getBone("armorRightBoot").orElse(null); + } + + @Override + public AzBone getLeftLegBone(AzBakedModel model) { + return model.getBone("armorRightLeg").orElse(null); + } + + @Override + public AzBone getRightBootBone(AzBakedModel model) { + return model.getBone("armorLeftBoot").orElse(null); + } + + @Override + public AzBone getRightLegBone(AzBakedModel model) { + return model.getBone("armorLeftLeg").orElse(null); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorRenderer.java new file mode 100644 index 000000000..0dea20fb1 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/armors/AzDoomArmorRenderer.java @@ -0,0 +1,23 @@ +package mod.azure.azurelib.fabric.core2.example.armors; + +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.render.armor.AzArmorRenderer; +import mod.azure.azurelib.core2.render.armor.AzArmorRendererConfig; + +public class AzDoomArmorRenderer extends AzArmorRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/item/doomicorn.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/item/doomicorn.png"); + + public AzDoomArmorRenderer() { + super( + AzArmorRendererConfig.builder(MODEL, TEXTURE) + .setAnimatorProvider(AzDoomArmorAnimator::new) + .setBoneProvider(new AzDoomArmorBoneProvider()) + .build() + ); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java new file mode 100644 index 000000000..c48e6f8da --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/Stargate.java @@ -0,0 +1,43 @@ +package mod.azure.azurelib.fabric.core2.example.blocks; + +import com.mojang.serialization.MapCodec; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; + +public class Stargate extends BaseEntityBlock implements EntityBlock { + + public static final MapCodec CODEC = simpleCodec(Stargate::new); + + public Stargate(Properties properties) { + super(properties); + } + + @Override + protected @NotNull MapCodec codec() { + return CODEC; + } + + @Override + public @Nullable BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + return ExampleEntityTypes.STARGATE.create(pos, state); + } + + @Override + public BlockEntityTicker getTicker( + @NotNull Level level, + @NotNull BlockState state, + @NotNull BlockEntityType type + ) { + return createTickerHelper(type, ExampleEntityTypes.STARGATE, StargateBlockEntity::tick); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateAnimationDispatcher.java new file mode 100644 index 000000000..c8753d359 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateAnimationDispatcher.java @@ -0,0 +1,19 @@ +package mod.azure.azurelib.fabric.core2.example.blocks; + +import net.minecraft.world.level.block.entity.BlockEntity; + +import mod.azure.azurelib.core2.animation.dispatch.command.AzCommand; + +public class StargateAnimationDispatcher { + + private static final String SPIN_ANIMATION_NAME = "spinning"; + + private static final AzCommand SPINNING_COMMAND = AzCommand.create( + "base_controller", + SPIN_ANIMATION_NAME + ); + + public void spin(BlockEntity entity) { + SPINNING_COMMAND.sendForBlockEntity(entity); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java new file mode 100644 index 000000000..5799c833f --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntity.java @@ -0,0 +1,24 @@ +package mod.azure.azurelib.fabric.core2.example.blocks; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +import mod.azure.azurelib.fabric.core2.example.ExampleEntityTypes; + +public class StargateBlockEntity extends BlockEntity { + + public final StargateAnimationDispatcher animationDispatcher; + + public StargateBlockEntity(BlockPos pos, BlockState blockState) { + super(ExampleEntityTypes.STARGATE, pos, blockState); + this.animationDispatcher = new StargateAnimationDispatcher(); + } + + public static void tick(Level level, BlockPos pos, BlockState state, StargateBlockEntity blockEntity) { + if (blockEntity.level != null && level.isClientSide()) { + blockEntity.animationDispatcher.spin(blockEntity); + } + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntityAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntityAnimator.java new file mode 100644 index 000000000..984f445f1 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateBlockEntityAnimator.java @@ -0,0 +1,34 @@ +package mod.azure.azurelib.fabric.core2.example.blocks; + +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzBlockAnimator; + +public class StargateBlockEntityAnimator extends AzBlockAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource( + "animations/block/stargate.animation.json" + ); + + protected StargateBlockEntityAnimator() { + super(AzAnimatorConfig.defaultConfig()); + } + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + AzAnimationController.builder(this, "base_controller") + .build() + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(StargateBlockEntity animatable) { + return ANIMATIONS; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java new file mode 100644 index 000000000..5c6be5dd1 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/blocks/StargateRender.java @@ -0,0 +1,22 @@ +package mod.azure.azurelib.fabric.core2.example.blocks; + +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.render.block.AzBlockEntityRenderer; +import mod.azure.azurelib.core2.render.block.AzBlockEntityRendererConfig; + +public class StargateRender extends AzBlockEntityRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/block/stargate.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/block/stargate.png"); + + public StargateRender() { + super( + AzBlockEntityRendererConfig.builder(MODEL, TEXTURE) + .setAnimatorProvider(StargateBlockEntityAnimator::new) + .build() + ); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunter.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunter.java new file mode 100644 index 000000000..c17c6ff39 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunter.java @@ -0,0 +1,59 @@ +package mod.azure.azurelib.fabric.core2.example.entities.doomhunter; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.ai.goal.*; +import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; +import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; +import net.minecraft.world.entity.ai.navigation.PathNavigation; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.api.common.ai.pathing.AzureNavigation; + +public class DoomHunter extends Monster { + + private final DoomHunterAnimationDispatcher animationDispatcher; + + public DoomHunter(EntityType entityType, Level level) { + super(entityType, level); + this.animationDispatcher = new DoomHunterAnimationDispatcher(this); + } + + @Override + protected @NotNull PathNavigation createNavigation(@NotNull Level level) { + return new AzureNavigation(this, level); + } + + @Override + public float maxUpStep() { + return 2.0F; + } + + @Override + public void tick() { + super.tick(); + + if (this.level().isClientSide && !this.isAggressive()) { + animationDispatcher.chainsaw(); + } + } + + @Override + protected void registerGoals() { + super.registerGoals(); + this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 0.6F, true)); + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 0.5F)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true)); + this.targetSelector.addGoal(1, (new HurtByTargetGoal(this)).setAlertOthers(DoomHunter.class)); + } + + @Override + protected void playStepSound(BlockPos pos, BlockState state) {} +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimationDispatcher.java new file mode 100644 index 000000000..8d291aecc --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimationDispatcher.java @@ -0,0 +1,20 @@ +package mod.azure.azurelib.fabric.core2.example.entities.doomhunter; + +import mod.azure.azurelib.core2.animation.dispatch.command.AzCommand; +import mod.azure.azurelib.core2.animation.play_behavior.AzPlayBehaviors; + +public class DoomHunterAnimationDispatcher { + + private static final AzCommand CHAINSAW = AzCommand + .create("base_controller", "chainsaw", AzPlayBehaviors.LOOP); + + private final DoomHunter doomHunter; + + public DoomHunterAnimationDispatcher(DoomHunter doomHunter) { + this.doomHunter = doomHunter; + } + + public void chainsaw() { + CHAINSAW.sendForEntity(doomHunter); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimator.java new file mode 100644 index 000000000..f62f00bcb --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterAnimator.java @@ -0,0 +1,33 @@ +package mod.azure.azurelib.fabric.core2.example.entities.doomhunter; + +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; + +public class DoomHunterAnimator extends AzEntityAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource( + "animations/entity/doomhunter.animation.json" + ); + + public DoomHunterAnimator() { + super(); + } + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + AzAnimationController.builder(this, "base_controller") + .build() + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(DoomHunter drone) { + return ANIMATIONS; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java new file mode 100644 index 000000000..a98ac5b78 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/doomhunter/DoomHunterRenderer.java @@ -0,0 +1,24 @@ +package mod.azure.azurelib.fabric.core2.example.entities.doomhunter; + +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import mod.azure.azurelib.core2.render.entity.AzEntityRendererConfig; + +public class DoomHunterRenderer extends AzEntityRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/entity/doomhunter.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/doomhunter.png"); + + public DoomHunterRenderer(EntityRendererProvider.Context context) { + super( + AzEntityRendererConfig.builder(MODEL, TEXTURE) + .setAnimatorProvider(DoomHunterAnimator::new) + .build(), + context + ); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimationDispatcher.java new file mode 100644 index 000000000..9d98fb634 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimationDispatcher.java @@ -0,0 +1,61 @@ +package mod.azure.azurelib.fabric.core2.example.entities.marauder; + +import mod.azure.azurelib.core2.animation.dispatch.command.AzCommand; +import mod.azure.azurelib.core2.animation.play_behavior.AzPlayBehaviors; + +public class MarauderAnimationDispatcher { + + private static final AzCommand DEATH = AzCommand.create( + "base_controller", + "death", + AzPlayBehaviors.HOLD_ON_LAST_FRAME + ); + + private static final AzCommand IDLE = AzCommand.create("base_controller", "idle", AzPlayBehaviors.LOOP); + + private static final AzCommand RUN = AzCommand.create("base_controller", "run", AzPlayBehaviors.LOOP); + + private static final AzCommand SPAWN = AzCommand.create( + "base_controller", + "spawn", + AzPlayBehaviors.PLAY_ONCE + ); + + private static final AzCommand AXE_ATTACK = AzCommand.create( + "base_controller", + "axe_attack", + AzPlayBehaviors.PLAY_ONCE + ); + + private static final AzCommand WALK = AzCommand.create("base_controller", "walk", AzPlayBehaviors.LOOP); + + private final MarauderEntity marauder; + + public MarauderAnimationDispatcher(MarauderEntity marauder) { + this.marauder = marauder; + } + + public void death() { + DEATH.sendForEntity(marauder); + } + + public void idle() { + IDLE.sendForEntity(marauder); + } + + public void run() { + RUN.sendForEntity(marauder); + } + + public void spawn() { + SPAWN.sendForEntity(marauder); + } + + public void walk() { + WALK.sendForEntity(marauder); + } + + public void serverMelee() { + AXE_ATTACK.sendForEntity(marauder); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java new file mode 100644 index 000000000..4b19eb392 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderAnimator.java @@ -0,0 +1,101 @@ +package mod.azure.azurelib.fabric.core2.example.entities.marauder; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.controller.keyframe.AzKeyframeCallbacks; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; + +public class MarauderAnimator extends AzEntityAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource( + "animations/entity/marauder.animation.json" + ); + + public MarauderAnimator() { + super(); + } + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + AzAnimationController.builder(this, "base_controller") + .setTransitionLength(5) + .setKeyframeCallbacks( + AzKeyframeCallbacks.builder() + .setSoundKeyframeHandler( + event -> { + if (event.getKeyframeData().getSound().equals("walk")) { + event.getAnimatable() + .level() + .playLocalSound( + event.getAnimatable().getX(), + event.getAnimatable().getY(), + event.getAnimatable().getZ(), + SoundEvents.METAL_STEP, + SoundSource.HOSTILE, + 1.00F, + 1.0F, + true + ); + } + if (event.getKeyframeData().getSound().equals("run")) { + event.getAnimatable() + .level() + .playLocalSound( + event.getAnimatable().getX(), + event.getAnimatable().getY(), + event.getAnimatable().getZ(), + SoundEvents.SKELETON_STEP, + SoundSource.HOSTILE, + 1.00F, + 1.0F, + true + ); + } + if (event.getKeyframeData().getSound().equals("portal")) { + event.getAnimatable() + .level() + .playLocalSound( + event.getAnimatable().getX(), + event.getAnimatable().getY(), + event.getAnimatable().getZ(), + SoundEvents.PORTAL_AMBIENT, + SoundSource.HOSTILE, + 0.20F, + 1.0F, + true + ); + } + if (event.getKeyframeData().getSound().equals("axe")) { + event.getAnimatable() + .level() + .playLocalSound( + event.getAnimatable().getX(), + event.getAnimatable().getY(), + event.getAnimatable().getZ(), + SoundEvents.ENDER_EYE_LAUNCH, + SoundSource.HOSTILE, + 1.00F, + 1.0F, + true + ); + } + } + ) + .build() + ) + .build() + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(MarauderEntity drone) { + return ANIMATIONS; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java new file mode 100644 index 000000000..a921d5359 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderEntity.java @@ -0,0 +1,104 @@ +package mod.azure.azurelib.fabric.core2.example.entities.marauder; + +import mod.azure.azurelib.fabric.core2.example.entities.marauder.ai.DelayedMeleeAttackGoal; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.ai.goal.RandomStrollGoal; +import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; +import net.minecraft.world.entity.ai.navigation.PathNavigation; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.entity.npc.AbstractVillager; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.api.common.ai.pathing.AzureNavigation; +import mod.azure.azurelib.fabric.core2.example.MoveAnalysis; + +public class MarauderEntity extends Monster { + + public final MarauderAnimationDispatcher animationDispatcher; + + private final MoveAnalysis moveAnalysis; + + public MarauderEntity(EntityType entityType, Level level) { + super(entityType, level); + this.animationDispatcher = new MarauderAnimationDispatcher(this); + this.moveAnalysis = new MoveAnalysis(this); + } + + @Override + protected @NotNull PathNavigation createNavigation(@NotNull Level level) { + return new AzureNavigation(this, level); + } + + @Override + public float maxUpStep() { + return 2.0F; + } + + @Override + protected void tickDeath() { + ++this.deathTime; + if (this.deathTime >= 80 && !this.level().isClientSide() && !this.isRemoved()) { + this.level().broadcastEntityEvent(this, (byte) 60); + this.remove(RemovalReason.KILLED); + } + } + + @Override + public void tick() { + super.tick(); + moveAnalysis.update(); + + if (this.level().isClientSide) { + var isMovingOnGround = moveAnalysis.isMovingHorizontally() && onGround(); + Runnable animationRunner; + + if (!this.isAlive()) { + animationRunner = animationDispatcher::death; +// } else if (this.tickCount < 300) { +// animationRunner = animationDispatcher::spawn; + } else if (isMovingOnGround) { + animationRunner = this.isAggressive() + ? animationDispatcher::run + : animationDispatcher::walk; + } else { + animationRunner = animationDispatcher::idle; + } + + animationRunner.run(); + } else { + if (this.getTarget() != null && this.isWithinMeleeAttackRange(this.getTarget())) { + if (this.getNavigation() instanceof AzureNavigation azureNavigation) { + azureNavigation.hardStop(); + azureNavigation.stop(); + } + } +// if (this.tickCount < 300 && this.isAlive()) { +// if (this.getNavigation() instanceof AzureNavigation azureNavigation) { +// azureNavigation.hardStop(); +// azureNavigation.stop(); +// } +// this.setYBodyRot(0); +// this.setYHeadRot(0); +// this.getEyePosition(90); +// this.setXRot(0); +// this.setYRot(0); +// } + } + } + + /** + * TODO: Get longer Melee animations working + */ + @Override + protected void registerGoals() { + this.goalSelector.addGoal(7, new RandomStrollGoal(this, 0.3F)); + this.goalSelector.addGoal(2, new DelayedMeleeAttackGoal(this, 0.6F, true)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, true)); + } + + @Override + protected void playStepSound(BlockPos pos, BlockState state) {} +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java new file mode 100644 index 000000000..a47d06bcd --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/MarauderRenderer.java @@ -0,0 +1,27 @@ +package mod.azure.azurelib.fabric.core2.example.entities.marauder; + +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import mod.azure.azurelib.core2.render.entity.AzEntityRendererConfig; +import mod.azure.azurelib.core2.render.layer.AzAutoGlowingLayer; + +public class MarauderRenderer extends AzEntityRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/entity/marauder.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/marauder.png"); + + public MarauderRenderer(EntityRendererProvider.Context context) { + super( + AzEntityRendererConfig.builder(MODEL, TEXTURE) + .addRenderLayer(new AzAutoGlowingLayer<>()) + .setAnimatorProvider(MarauderAnimator::new) + .setDeathMaxRotation(0F) + .build(), + context + ); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/ai/DelayedMeleeAttackGoal.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/ai/DelayedMeleeAttackGoal.java new file mode 100644 index 000000000..c05ce3c71 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/marauder/ai/DelayedMeleeAttackGoal.java @@ -0,0 +1,153 @@ +package mod.azure.azurelib.fabric.core2.example.entities.marauder.ai; + +import mod.azure.azurelib.fabric.core2.example.entities.marauder.MarauderEntity; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.EntitySelector; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.PathfinderMob; +import net.minecraft.world.entity.ai.goal.Goal; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.pathfinder.Path; + +import java.util.EnumSet; + +public class DelayedMeleeAttackGoal extends Goal { + protected final PathfinderMob mob; + private final double speedModifier; + private final boolean followingTargetEvenIfNotSeen; + public Path path; + private double pathedTargetX; + private double pathedTargetY; + private double pathedTargetZ; + private int ticksUntilNextPathRecalculation; + private int ticksUntilNextAttack; + public long lastCanUseCheck; + private int delayCounter; + + public DelayedMeleeAttackGoal(PathfinderMob mob, double speedModifier, boolean followingTargetEvenIfNotSeen) { + this.mob = mob; + this.speedModifier = speedModifier; + this.followingTargetEvenIfNotSeen = followingTargetEvenIfNotSeen; + this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK)); + } + + public boolean canUse() { + long i = this.mob.level().getGameTime(); + if (i - this.lastCanUseCheck < 20L) { + return false; + } else { + this.lastCanUseCheck = i; + LivingEntity livingentity = this.mob.getTarget(); + if (livingentity == null) { + return false; + } else if (!livingentity.isAlive()) { + return false; + } else { + this.path = this.mob.getNavigation().createPath(livingentity, 0); + return this.path != null ? true : this.mob.isWithinMeleeAttackRange(livingentity); + } + } + } + + public boolean canContinueToUse() { + LivingEntity livingentity = this.mob.getTarget(); + if (livingentity == null) { + return false; + } else if (!livingentity.isAlive()) { + return false; + } else if (!this.followingTargetEvenIfNotSeen) { + return !this.mob.getNavigation().isDone(); + } else { + return !this.mob.isWithinRestriction(livingentity.blockPosition()) ? false : !(livingentity instanceof Player) || !livingentity.isSpectator() && !((Player)livingentity).isCreative(); + } + } + + public void start() { + this.mob.getNavigation().moveTo(this.path, this.speedModifier); + this.mob.setAggressive(true); + this.ticksUntilNextPathRecalculation = 0; + this.ticksUntilNextAttack = 0; + this.delayCounter = 0; + } + + public void stop() { + LivingEntity livingentity = this.mob.getTarget(); + if (!EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(livingentity)) { + this.mob.setTarget((LivingEntity)null); + } + + this.mob.setAggressive(false); + this.mob.getNavigation().stop(); + this.delayCounter = 0; + } + + public boolean requiresUpdateEveryTick() { + return true; + } + + public void tick() { + LivingEntity livingentity = this.mob.getTarget(); + if (livingentity != null) { + if (!this.mob.level().isClientSide()) { + this.delayCounter++; + } + this.mob.getLookControl().setLookAt(livingentity, 30.0F, 30.0F); + this.ticksUntilNextPathRecalculation = Math.max(this.ticksUntilNextPathRecalculation - 1, 0); + if ((this.followingTargetEvenIfNotSeen || this.mob.getSensing().hasLineOfSight(livingentity)) && this.ticksUntilNextPathRecalculation <= 0 && (this.pathedTargetX == (double)0.0F && this.pathedTargetY == (double)0.0F && this.pathedTargetZ == (double)0.0F || livingentity.distanceToSqr(this.pathedTargetX, this.pathedTargetY, this.pathedTargetZ) >= (double)1.0F || this.mob.getRandom().nextFloat() < 0.05F)) { + this.pathedTargetX = livingentity.getX(); + this.pathedTargetY = livingentity.getY(); + this.pathedTargetZ = livingentity.getZ(); + this.ticksUntilNextPathRecalculation = 4 + this.mob.getRandom().nextInt(7); + double d0 = this.mob.distanceToSqr(livingentity); + if (d0 > (double)1024.0F) { + this.ticksUntilNextPathRecalculation += 10; + } else if (d0 > (double)256.0F) { + this.ticksUntilNextPathRecalculation += 5; + } + + if (!this.mob.getNavigation().moveTo(livingentity, this.speedModifier)) { + this.ticksUntilNextPathRecalculation += 15; + } + + this.ticksUntilNextPathRecalculation = this.adjustedTickDelay(this.ticksUntilNextPathRecalculation); + } + + if (!this.mob.level().isClientSide() && this.mob.getTarget() != null && this.mob.isWithinMeleeAttackRange(this.mob.getTarget())) { + ((MarauderEntity) this.mob).animationDispatcher.serverMelee(); + } + this.ticksUntilNextAttack = Math.max(this.ticksUntilNextAttack - 1, 0); + this.checkAndPerformAttack(livingentity); + } + + } + + protected void checkAndPerformAttack(LivingEntity target) { + if (this.canPerformAttack(target)) { + this.resetAttackCooldown(); + this.mob.swing(InteractionHand.MAIN_HAND); + this.mob.doHurtTarget(target); + } + + } + + protected void resetAttackCooldown() { + this.ticksUntilNextAttack = this.adjustedTickDelay(80); + this.delayCounter = 0; + } + + protected boolean isTimeToAttack() { + return this.ticksUntilNextAttack <= 0; + } + + protected boolean canPerformAttack(LivingEntity entity) { + return this.delayCounter > 60 && this.isTimeToAttack() && this.mob.isWithinMeleeAttackRange(entity) && this.mob.getSensing().hasLineOfSight(entity); + } + + protected int getTicksUntilNextAttack() { + return this.ticksUntilNextAttack; + } + + protected int getAttackInterval() { + return this.adjustedTickDelay(80); + } +} \ No newline at end of file diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/HatchManager.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/HatchManager.java new file mode 100644 index 000000000..585876d42 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/HatchManager.java @@ -0,0 +1,124 @@ +package mod.azure.azurelib.fabric.core2.example.entities.ovamorph; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.world.entity.LivingEntity; + +public class HatchManager { + + private static final String HATCH_DURATION_IN_TICKS_KEY = "hatchDurationInTicks"; + + private static final String HATCHED_KEY = "hatched"; + + private static final String MAXIMUM_SPAWN_COUNT_KEY = "maximumSpawnCount"; + + private static final String REMAINING_SPAWN_DELAY_IN_TICKS_KEY = "remainingSpawnDelayInTicks"; + + private static final String SPAWN_COUNT_KEY = "spawnCount"; + + private final LivingEntity entity; + + private final EntityDataAccessor hatchedEDA; + + private final EntityDataAccessor maximumSpawnCountEDA; + + private final int spawnDelayInTicks; + + private int hatchDurationInTicks; + + private int remainingSpawnDelayInTicks; + + private int spawnCount; + + public HatchManager(LivingEntity entity, EntityDataAccessor hatchedEDA, EntityDataAccessor maximumSpawnCountEDA, int hatchDurationInTicks, int spawnDelayInTicks) { + this.entity = entity; + this.hatchedEDA = hatchedEDA; + this.maximumSpawnCountEDA = maximumSpawnCountEDA; + this.hatchDurationInTicks = hatchDurationInTicks; + this.spawnDelayInTicks = spawnDelayInTicks; + this.remainingSpawnDelayInTicks = spawnDelayInTicks; + this.spawnCount = 0; + } + + public void tick() { + if (hatched()) { + hatchDurationInTicks = Math.max(hatchDurationInTicks - 1, 0); + } + + var level = entity.level(); + + if (level.isClientSide) { + return; + } + + var hasFullyHatched = hatchDurationInTicks <= 0; + var canSpawn = spawnCount < maximumSpawnCount(); + + if (!hasFullyHatched || !canSpawn) { + return; + } + + remainingSpawnDelayInTicks = Math.max(remainingSpawnDelayInTicks - 1, 0); + + if (remainingSpawnDelayInTicks == 0) { +// spawnFacehugger(level); + // Reset spawn delay. + remainingSpawnDelayInTicks = spawnDelayInTicks; + // Increment the spawns created. + spawnCount++; + } + } + + public boolean hatched() { + return entity.getEntityData().get(hatchedEDA); + } + + public void hatch() { + entity.getEntityData().set(hatchedEDA, true); + } + + public byte maximumSpawnCount() { + return entity.getEntityData().get(maximumSpawnCountEDA); + } + + public void load(CompoundTag compoundTag) { + this.hatchDurationInTicks = compoundTag.getInt(HATCH_DURATION_IN_TICKS_KEY); + this.remainingSpawnDelayInTicks = compoundTag.getInt(REMAINING_SPAWN_DELAY_IN_TICKS_KEY); + this.spawnCount = compoundTag.getInt(SPAWN_COUNT_KEY); + + entity.getEntityData().set(hatchedEDA, compoundTag.getBoolean(HATCHED_KEY)); + entity.getEntityData().set(maximumSpawnCountEDA, compoundTag.getByte(MAXIMUM_SPAWN_COUNT_KEY)); + } + + public void save(CompoundTag compoundTag) { + compoundTag.putInt(HATCH_DURATION_IN_TICKS_KEY, hatchDurationInTicks); + compoundTag.putInt(REMAINING_SPAWN_DELAY_IN_TICKS_KEY, remainingSpawnDelayInTicks); + compoundTag.putInt(SPAWN_COUNT_KEY, spawnCount); + + compoundTag.putBoolean(HATCHED_KEY, entity.getEntityData().get(hatchedEDA)); + compoundTag.putByte(MAXIMUM_SPAWN_COUNT_KEY, entity.getEntityData().get(maximumSpawnCountEDA)); + } + +// private void spawnFacehugger(Level level) { +// var facehugger = AVPREntityTypes.FACEHUGGER.create(level); +// +// if (facehugger == null) { +// // TODO: Log. +// return; +// } +// +// // TODO: We need to transfer the ovamorph genes to the spawned facehugger(s). +// +// facehugger.moveTo(entity.blockPosition(), entity.getYRot(), entity.getXRot()); +// +// // Explicitly set the yaw and pitch to ensure accurate orientation +// facehugger.setYRot(entity.getYRot()); +// facehugger.setXRot(entity.getXRot()); +// +// // Synchronize the visual body rotation (if applicable for mobs) +// facehugger.yBodyRot = entity.yBodyRot; // Body rotation +// facehugger.yHeadRot = entity.yHeadRot; // Head rotation +// +// level.addFreshEntity(facehugger); +// } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/Ovamorph.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/Ovamorph.java new file mode 100644 index 000000000..ad7ed27ef --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/Ovamorph.java @@ -0,0 +1,85 @@ +package mod.azure.azurelib.fabric.core2.example.entities.ovamorph; + +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.world.damagesource.DamageSource; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.ai.attributes.AttributeSupplier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.level.Level; + +public class Ovamorph extends Monster { + + private static final EntityDataAccessor HATCHED = SynchedEntityData.defineId(Ovamorph.class, EntityDataSerializers.BOOLEAN); + + private static final EntityDataAccessor MAX_SPAWN_COUNT = SynchedEntityData.defineId(Ovamorph.class, EntityDataSerializers.BYTE); + + public static AttributeSupplier.Builder createOvamorphAttributes() { + return Monster.createMonsterAttributes() + .add(Attributes.ATTACK_DAMAGE, 0) + .add(Attributes.MOVEMENT_SPEED, 0); + } + + private final OvamorphAnimationDispatcher animationDispatcher; + + private final HatchManager hatchManager; + + public Ovamorph(EntityType entityType, Level level) { + super(entityType, level); + this.animationDispatcher = new OvamorphAnimationDispatcher(this); + this.hatchManager = new HatchManager(this, HATCHED, MAX_SPAWN_COUNT, 3* 20, 3 * 20); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + builder.define(HATCHED, false); + builder.define(MAX_SPAWN_COUNT, (byte) (random.nextInt(3) + 1)); + } + + @Override + public void tick() { + super.tick(); + hatchManager.tick(); + } + + @Override + public boolean hurt(DamageSource damageSource, float damage) { + if (!level().isClientSide) { + hatchManager.hatch(); + animationDispatcher.open(); + } + + return super.hurt(damageSource, damage); + } + + // Prevent the ovamorph from drowning or otherwise running out of air. + @Override + public int getAirSupply() { + return Integer.MAX_VALUE; + } + + @Override + public boolean dampensVibrations() { + return true; + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + super.readAdditionalSaveData(compoundTag); + hatchManager.load(compoundTag); + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + super.addAdditionalSaveData(compoundTag); + hatchManager.save(compoundTag); + } + + public HatchManager hatchManager() { + return hatchManager; + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphAnimationDispatcher.java new file mode 100644 index 000000000..40d12c931 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphAnimationDispatcher.java @@ -0,0 +1,21 @@ +package mod.azure.azurelib.fabric.core2.example.entities.ovamorph; + +import mod.azure.azurelib.core2.animation.dispatch.command.AzCommand; +import mod.azure.azurelib.core2.animation.play_behavior.AzPlayBehaviors; + +public class OvamorphAnimationDispatcher { + + private static final AzCommand OPEN = AzCommand.create( + OvamorphAnimationRefs.BASE_CONTROLLER_NAME, OvamorphAnimationRefs.OPEN_ANIMATION_NAME, AzPlayBehaviors.HOLD_ON_LAST_FRAME + ); + + private final Ovamorph ovamorph; + + public OvamorphAnimationDispatcher(Ovamorph ovamorph) { + this.ovamorph = ovamorph; + } + + public void open() { + OPEN.sendForEntity(ovamorph); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphAnimationRefs.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphAnimationRefs.java new file mode 100644 index 000000000..6a95e045b --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphAnimationRefs.java @@ -0,0 +1,9 @@ +package mod.azure.azurelib.fabric.core2.example.entities.ovamorph; + +public class OvamorphAnimationRefs { + + public static final String BASE_CONTROLLER_NAME = "base"; + + public static final String OPEN_ANIMATION_NAME = "animation.eggopen"; + +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphAnimator.java new file mode 100644 index 000000000..b27e401da --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphAnimator.java @@ -0,0 +1,35 @@ +package mod.azure.azurelib.fabric.core2.example.entities.ovamorph; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzEntityAnimator; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +public class OvamorphAnimator extends AzEntityAnimator { + + private static final ResourceLocation ANIMATION = AzureLib.modResource( + "animations/entity/ovamorph.animation.json" + ); + + public OvamorphAnimator() { + super(AzAnimatorConfig.defaultConfig()); + } + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + AzAnimationController.builder(this, OvamorphAnimationRefs.BASE_CONTROLLER_NAME) + .setTransitionLength(5) + .build() + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(Ovamorph animatable) { + return ANIMATION; + } + +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphRenderer.java new file mode 100644 index 000000000..0ef98ea30 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/entities/ovamorph/OvamorphRenderer.java @@ -0,0 +1,46 @@ +package mod.azure.azurelib.fabric.core2.example.entities.ovamorph; + +import com.mojang.blaze3d.vertex.PoseStack; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.render.entity.AzEntityRenderer; +import mod.azure.azurelib.core2.render.entity.AzEntityRendererConfig; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +public class OvamorphRenderer extends AzEntityRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/entity/ovamorph.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/entity/ovamorph.png"); + + public OvamorphRenderer(EntityRendererProvider.Context context) { + super(AzEntityRendererConfig.builder(MODEL, TEXTURE).setAnimatorProvider(OvamorphAnimator::new).build(), context); + this.shadowRadius = 0.4F; + } + + @Override + public void render( + @NotNull Ovamorph entity, + float entityYaw, + float partialTick, + @NotNull PoseStack poseStack, + @NotNull MultiBufferSource bufferSource, + int packedLight + ) { + var maxSpawnCount = entity.hatchManager().maximumSpawnCount(); + var additiveScale = 0.35F * (maxSpawnCount - 1); + var scale = 1.4F + Math.max(additiveScale, 0); + + poseStack.scale(scale, scale, scale); + + super.render(entity, entityYaw, partialTick, poseStack, bufferSource, packedLight); + } + + // TODO: +// @Override +// public RenderType getRenderType(Ovamorph animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) { +// return RenderType.entityTranslucent(texture); +// } +} \ No newline at end of file diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java new file mode 100644 index 000000000..ddbc0a370 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistol.java @@ -0,0 +1,39 @@ +package mod.azure.azurelib.fabric.core2.example.items; + +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +public class AzPistol extends Item { + + private final AzPistolAnimationDispatcher dispatcher; + + public AzPistol() { + super(new Properties().stacksTo(1)); + this.dispatcher = new AzPistolAnimationDispatcher(); + } + + @Override + public void onUseTick(Level level, LivingEntity livingEntity, ItemStack stack, int remainingUseDuration) { + super.onUseTick(level, livingEntity, stack, remainingUseDuration); + if (livingEntity instanceof Player player && !level.isClientSide()) { + dispatcher.firing(player, stack); + } + } + + @Override + public @NotNull InteractionResultHolder use( + @NotNull Level world, + Player user, + @NotNull InteractionHand hand + ) { + final var itemStack = user.getItemInHand(hand); + user.startUsingItem(hand); + return InteractionResultHolder.consume(itemStack); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimationDispatcher.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimationDispatcher.java new file mode 100644 index 000000000..f9242b800 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimationDispatcher.java @@ -0,0 +1,22 @@ +package mod.azure.azurelib.fabric.core2.example.items; + +import mod.azure.azurelib.core2.animation.play_behavior.AzPlayBehaviors; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; + +import mod.azure.azurelib.core2.animation.dispatch.command.AzCommand; + +public class AzPistolAnimationDispatcher { + + private static final String FIRING_ANIMATION_NAME = "firing"; + + private static final AzCommand FIRING_COMMAND = AzCommand.create( + "base_controller", + FIRING_ANIMATION_NAME, + AzPlayBehaviors.PLAY_ONCE + ); + + public void firing(Entity entity, ItemStack itemStack) { + FIRING_COMMAND.sendForItem(entity, itemStack); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimator.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimator.java new file mode 100644 index 000000000..82bca1b48 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolAnimator.java @@ -0,0 +1,34 @@ +package mod.azure.azurelib.fabric.core2.example.items; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.NotNull; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.animation.AzAnimatorConfig; +import mod.azure.azurelib.core2.animation.controller.AzAnimationController; +import mod.azure.azurelib.core2.animation.controller.AzAnimationControllerContainer; +import mod.azure.azurelib.core2.animation.impl.AzItemAnimator; + +public class AzPistolAnimator extends AzItemAnimator { + + private static final ResourceLocation ANIMATIONS = AzureLib.modResource("animations/item/pistol.animation.json"); + + public AzPistolAnimator() { + super(AzAnimatorConfig.defaultConfig()); + } + + @Override + public void registerControllers(AzAnimationControllerContainer animationControllerContainer) { + animationControllerContainer.add( + AzAnimationController.builder(this, "base_controller") + .build() + ); + } + + @Override + public @NotNull ResourceLocation getAnimationLocation(ItemStack animatable) { + return ANIMATIONS; + } + +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java new file mode 100644 index 000000000..2a00d63a5 --- /dev/null +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/core2/example/items/AzPistolRenderer.java @@ -0,0 +1,20 @@ +package mod.azure.azurelib.fabric.core2.example.items; + +import net.minecraft.resources.ResourceLocation; + +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.core2.render.item.AzItemRenderer; +import mod.azure.azurelib.core2.render.item.AzItemRendererConfig; + +public class AzPistolRenderer extends AzItemRenderer { + + private static final ResourceLocation MODEL = AzureLib.modResource("geo/item/pistol.geo.json"); + + private static final ResourceLocation TEXTURE = AzureLib.modResource("textures/item/pistol.png"); + + public AzPistolRenderer() { + super( + AzItemRendererConfig.builder(MODEL, TEXTURE).setAnimatorProvider(AzPistolAnimator::new).build() + ); + } +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java b/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java index 175daa4f9..f52577eb5 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/event/GeoRenderEvent.java @@ -1,20 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.fabric.event; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.common.api.client.renderer.*; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.client.renderer.MultiBufferSource; @@ -23,8 +14,16 @@ import net.minecraft.world.level.block.entity.BlockEntity; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.api.client.renderer.*; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + public interface GeoRenderEvent { - + /** * Returns the renderer for this event * @@ -41,6 +40,7 @@ public interface GeoRenderEvent { * Renderer events for armor pieces being rendered by {@link GeoArmorRenderer} */ abstract class Armor implements GeoRenderEvent { + private final GeoArmorRenderer renderer; public Armor(GeoArmorRenderer renderer) { @@ -85,25 +85,42 @@ public EquipmentSlot getEquipmentSlot() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the armor piece will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the armor piece will not be rendered + * and the corresponding {@link Post} event will not be fired. */ public static class Pre extends Armor { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -140,6 +157,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -150,19 +168,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Armor { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -197,6 +231,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -207,11 +242,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Armor { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoArmorRenderer renderer) { super(renderer); @@ -220,7 +260,8 @@ public CompileRenderLayers(GeoArmorRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -231,6 +272,7 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } @@ -240,6 +282,7 @@ public interface Listener { * Renderer events for {@link BlockEntity BlockEntities} being rendered by {@link GeoBlockRenderer} */ abstract class Block implements GeoRenderEvent { + private final GeoBlockRenderer renderer; public Block(GeoBlockRenderer renderer) { @@ -267,25 +310,42 @@ public BlockEntity getBlockEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the block entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the block entity will not be rendered + * and the corresponding {@link Post} event will not be fired. */ public static class Pre extends Block { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -322,6 +382,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -332,19 +393,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Block { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -379,6 +456,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -389,11 +467,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Block { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoBlockRenderer renderer) { super(renderer); @@ -402,7 +485,8 @@ public CompileRenderLayers(GeoBlockRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -413,15 +497,18 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } } /** - * Renderer events for {@link net.minecraft.world.entity.Entity Entities} being rendered by {@link GeoEntityRenderer} + * Renderer events for {@link net.minecraft.world.entity.Entity Entities} being rendered by + * {@link GeoEntityRenderer} */ abstract class Entity implements GeoRenderEvent { + private final GeoEntityRenderer renderer; public Entity(GeoEntityRenderer renderer) { @@ -449,25 +536,42 @@ public net.minecraft.world.entity.Entity getEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the entity will not be rendered and the + * corresponding {@link Post} event will not be fired. */ public static class Pre extends Entity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -504,6 +608,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -514,19 +619,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Entity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -561,6 +682,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -571,11 +693,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Entity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoEntityRenderer renderer) { super(renderer); @@ -584,7 +711,8 @@ public CompileRenderLayers(GeoEntityRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -595,6 +723,7 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } @@ -604,6 +733,7 @@ public interface Listener { * Renderer events for {@link ItemStack Items} being rendered by {@link GeoItemRenderer} */ abstract class Item implements GeoRenderEvent { + private final GeoItemRenderer renderer; public Item(GeoItemRenderer renderer) { @@ -631,25 +761,42 @@ public ItemStack getItemStack() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the ItemStack will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the ItemStack will not be rendered and + * the corresponding {@link Post} event will not be fired. */ public static class Pre extends Item { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -686,6 +833,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -696,19 +844,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Item { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -743,6 +907,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -753,11 +918,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Item { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoItemRenderer renderer) { super(renderer); @@ -766,7 +936,8 @@ public CompileRenderLayers(GeoItemRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -777,6 +948,7 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } @@ -786,6 +958,7 @@ public interface Listener { * Renderer events for miscellaneous {@link GeoAnimatable animatables} being rendered by {@link GeoObjectRenderer} */ abstract class Object implements GeoRenderEvent { + private final GeoObjectRenderer renderer; public Object(GeoObjectRenderer renderer) { @@ -806,25 +979,42 @@ public GeoObjectRenderer getRenderer() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the object will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the object will not be rendered and the + * corresponding {@link Post} event will not be fired. */ public static class Pre extends Object { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -861,6 +1051,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -871,19 +1062,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Object { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -918,6 +1125,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -928,11 +1136,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Object { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoObjectRenderer renderer) { super(renderer); @@ -941,7 +1154,8 @@ public CompileRenderLayers(GeoObjectRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -952,15 +1166,21 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } } /** - * Renderer events for miscellaneous {@link GeoReplacedEntity replaced entities} being rendered by {@link GeoReplacedEntityRenderer} + * Renderer events for miscellaneous {@link GeoReplacedEntity replaced entities} being rendered by + * {@link GeoReplacedEntityRenderer} + * + * @deprecated */ + @Deprecated(forRemoval = true) abstract class ReplacedEntity implements GeoRenderEvent { + private final GeoReplacedEntityRenderer renderer; public ReplacedEntity(GeoReplacedEntityRenderer renderer) { @@ -988,25 +1208,42 @@ public net.minecraft.world.entity.Entity getReplacedEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is cancellable
    - * If the event is cancelled by returning false in the {@link Listener}, the entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled by returning false in the {@link Listener}, the entity will not be rendered and the + * corresponding {@link Post} event will not be fired. */ public static class Pre extends ReplacedEntity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, event -> true, listeners -> event -> { - for (Listener listener : listeners) { - if (!listener.handle(event)) - return false; - } - return true; - }); + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + event -> true, + listeners -> event -> { + for (Listener listener : listeners) { + if (!listener.handle(event)) + return false; + } + + return true; + } + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -1043,6 +1280,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + boolean handle(Pre event); } } @@ -1053,19 +1291,35 @@ public interface Listener { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends ReplacedEntity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -1100,6 +1354,7 @@ public int getPackedLight() { */ @FunctionalInterface public interface Listener { + void handle(Post event); } } @@ -1110,11 +1365,16 @@ public interface Listener { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends ReplacedEntity { - public static final Event EVENT = EventFactory.createArrayBacked(Listener.class, post -> {}, listeners -> event -> { - for (Listener listener : listeners) { - listener.handle(event); + + public static final Event EVENT = EventFactory.createArrayBacked( + Listener.class, + post -> {}, + listeners -> event -> { + for (Listener listener : listeners) { + listener.handle(event); + } } - }); + ); public CompileRenderLayers(GeoReplacedEntityRenderer renderer) { super(renderer); @@ -1123,7 +1383,8 @@ public CompileRenderLayers(GeoReplacedEntityRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -1134,6 +1395,7 @@ public void addLayer(GeoRenderLayer renderLayer) { */ @FunctionalInterface public interface Listener { + void handle(CompileRenderLayers event); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/integration/ModMenuIntegration.java b/fabric/src/main/java/mod/azure/azurelib/fabric/integration/ModMenuIntegration.java index 0e27889fe..b59ed48eb 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/integration/ModMenuIntegration.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/integration/ModMenuIntegration.java @@ -2,15 +2,16 @@ import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ModMenuApi; -import mod.azure.azurelib.common.internal.client.AzureLibClient; -import mod.azure.azurelib.common.internal.common.config.ConfigHolder; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; -import mod.azure.azurelib.common.platform.Services; import java.util.HashMap; import java.util.List; import java.util.Map; +import mod.azure.azurelib.common.internal.client.AzureLibClient; +import mod.azure.azurelib.common.internal.common.config.ConfigHolder; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; +import mod.azure.azurelib.common.platform.Services; + public class ModMenuIntegration implements ModMenuApi { @Override diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/AzureLibEventsFabric.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/AzureLibEventsFabric.java index 587c72349..2e2e114f5 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/AzureLibEventsFabric.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/AzureLibEventsFabric.java @@ -1,35 +1,54 @@ package mod.azure.azurelib.fabric.platform; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; + import mod.azure.azurelib.common.api.client.renderer.*; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; import mod.azure.azurelib.common.platform.services.AzureEvents; import mod.azure.azurelib.fabric.event.GeoRenderEvent; -import net.minecraft.client.renderer.MultiBufferSource; public class AzureLibEventsFabric implements AzureEvents { + /** * Fire the {@link GeoRenderEvent.Block.CompileRenderLayers} event */ @Override public void fireCompileBlockRenderLayers(GeoBlockRenderer renderer) { - GeoRenderEvent.Block.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.Block.CompileRenderLayers(renderer)); + GeoRenderEvent.Block.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.Block.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.Block.Pre} event */ @Override - public boolean fireBlockPreRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.Block.Pre.EVENT.invoker().handle(new GeoRenderEvent.Block.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireBlockPreRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.Block.Pre.EVENT.invoker() + .handle(new GeoRenderEvent.Block.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** * Fire the {@link GeoRenderEvent.Block.Post} event */ @Override - public void fireBlockPostRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.Block.Post.EVENT.invoker().handle(new GeoRenderEvent.Block.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireBlockPostRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.Block.Post.EVENT.invoker() + .handle(new GeoRenderEvent.Block.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** @@ -37,23 +56,40 @@ public void fireBlockPostRender(GeoBlockRenderer renderer, PoseStack poseStac */ @Override public void fireCompileArmorRenderLayers(GeoArmorRenderer renderer) { - GeoRenderEvent.Armor.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.Armor.CompileRenderLayers(renderer)); + GeoRenderEvent.Armor.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.Armor.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.Armor.Pre} event */ @Override - public boolean fireArmorPreRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.Armor.Pre.EVENT.invoker().handle(new GeoRenderEvent.Armor.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireArmorPreRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.Armor.Pre.EVENT.invoker() + .handle(new GeoRenderEvent.Armor.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** * Fire the {@link GeoRenderEvent.Armor.Post} event */ @Override - public void fireArmorPostRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.Armor.Post.EVENT.invoker().handle(new GeoRenderEvent.Armor.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireArmorPostRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.Armor.Post.EVENT.invoker() + .handle(new GeoRenderEvent.Armor.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** @@ -61,23 +97,40 @@ public void fireArmorPostRender(GeoArmorRenderer renderer, PoseStack poseStac */ @Override public void fireCompileEntityRenderLayers(GeoEntityRenderer renderer) { - GeoRenderEvent.Entity.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.Entity.CompileRenderLayers(renderer)); + GeoRenderEvent.Entity.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.Entity.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.Entity.Pre} event */ @Override - public boolean fireEntityPreRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.Entity.Pre.EVENT.invoker().handle(new GeoRenderEvent.Entity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireEntityPreRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.Entity.Pre.EVENT.invoker() + .handle(new GeoRenderEvent.Entity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** * Fire the {@link GeoRenderEvent.Entity.Post} event */ @Override - public void fireEntityPostRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.Entity.Post.EVENT.invoker().handle(new GeoRenderEvent.Entity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireEntityPostRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.Entity.Post.EVENT.invoker() + .handle(new GeoRenderEvent.Entity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** @@ -85,23 +138,58 @@ public void fireEntityPostRender(GeoEntityRenderer renderer, PoseStack poseSt */ @Override public void fireCompileReplacedEntityRenderLayers(GeoReplacedEntityRenderer renderer) { - GeoRenderEvent.ReplacedEntity.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.ReplacedEntity.CompileRenderLayers(renderer)); + GeoRenderEvent.ReplacedEntity.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.ReplacedEntity.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.ReplacedEntity.Pre} event */ @Override - public boolean fireReplacedEntityPreRender(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.ReplacedEntity.Pre.EVENT.invoker().handle(new GeoRenderEvent.ReplacedEntity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireReplacedEntityPreRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.ReplacedEntity.Pre.EVENT.invoker() + .handle( + new GeoRenderEvent.ReplacedEntity.Pre( + renderer, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ) + ); } /** * Fire the {@link GeoRenderEvent.ReplacedEntity.Post} event */ @Override - public void fireReplacedEntityPostRender(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.ReplacedEntity.Post.EVENT.invoker().handle(new GeoRenderEvent.ReplacedEntity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireReplacedEntityPostRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.ReplacedEntity.Post.EVENT.invoker() + .handle( + new GeoRenderEvent.ReplacedEntity.Post( + renderer, + poseStack, + model, + bufferSource, + partialTick, + packedLight + ) + ); } /** @@ -109,23 +197,40 @@ public void fireReplacedEntityPostRender(GeoReplacedEntityRenderer rendere */ @Override public void fireCompileItemRenderLayers(GeoItemRenderer renderer) { - GeoRenderEvent.Item.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.Item.CompileRenderLayers(renderer)); + GeoRenderEvent.Item.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.Item.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.Item.Pre} event */ @Override - public boolean fireItemPreRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.Item.Pre.EVENT.invoker().handle(new GeoRenderEvent.Item.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireItemPreRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.Item.Pre.EVENT.invoker() + .handle(new GeoRenderEvent.Item.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** * Fire the {@link GeoRenderEvent.Item.Post} event */ @Override - public void fireItemPostRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.Item.Post.EVENT.invoker().handle(new GeoRenderEvent.Item.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireItemPostRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.Item.Post.EVENT.invoker() + .handle(new GeoRenderEvent.Item.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** @@ -133,22 +238,39 @@ public void fireItemPostRender(GeoItemRenderer renderer, PoseStack poseStack, */ @Override public void fireCompileObjectRenderLayers(GeoObjectRenderer renderer) { - GeoRenderEvent.Object.CompileRenderLayers.EVENT.invoker().handle(new GeoRenderEvent.Object.CompileRenderLayers(renderer)); + GeoRenderEvent.Object.CompileRenderLayers.EVENT.invoker() + .handle(new GeoRenderEvent.Object.CompileRenderLayers(renderer)); } /** * Fire the {@link GeoRenderEvent.Object.Pre} event */ @Override - public boolean fireObjectPreRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return GeoRenderEvent.Object.Pre.EVENT.invoker().handle(new GeoRenderEvent.Object.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public boolean fireObjectPreRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return GeoRenderEvent.Object.Pre.EVENT.invoker() + .handle(new GeoRenderEvent.Object.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } /** * Fire the {@link GeoRenderEvent.Object.Post} event */ @Override - public void fireObjectPostRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - GeoRenderEvent.Object.Post.EVENT.invoker().handle(new GeoRenderEvent.Object.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireObjectPostRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + GeoRenderEvent.Object.Post.EVENT.invoker() + .handle(new GeoRenderEvent.Object.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); } -} \ No newline at end of file +} diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibInitializer.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibInitializer.java index 70bec4d0d..54e8c3ada 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibInitializer.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibInitializer.java @@ -1,8 +1,5 @@ package mod.azure.azurelib.fabric.platform; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.cache.AzureLibCache; -import mod.azure.azurelib.common.platform.services.AzureLibInitializer; import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.minecraft.resources.ResourceLocation; @@ -15,36 +12,40 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.cache.AzureLibCache; +import mod.azure.azurelib.common.platform.services.AzureLibInitializer; + public class FabricAzureLibInitializer implements AzureLibInitializer { @Override public void initialize() { ResourceManagerHelper.get(PackType.CLIENT_RESOURCES) - .registerReloadListener(new IdentifiableResourceReloadListener() { + .registerReloadListener(new IdentifiableResourceReloadListener() { - @Override - public ResourceLocation getFabricId() { - return AzureLib.modResource("models"); - } + @Override + public ResourceLocation getFabricId() { + return AzureLib.modResource("models"); + } - @Override - public @NotNull CompletableFuture reload( - PreparableReloadListener.PreparationBarrier synchronizer, - ResourceManager manager, - ProfilerFiller prepareProfiler, - ProfilerFiller applyProfiler, - Executor prepareExecutor, - Executor applyExecutor - ) { - return AzureLibCache.reload( - synchronizer, - manager, - prepareProfiler, - applyProfiler, - prepareExecutor, - applyExecutor - ); - } - }); + @Override + public @NotNull CompletableFuture reload( + PreparableReloadListener.PreparationBarrier synchronizer, + ResourceManager manager, + ProfilerFiller prepareProfiler, + ProfilerFiller applyProfiler, + Executor prepareExecutor, + Executor applyExecutor + ) { + return AzureLibCache.reload( + synchronizer, + manager, + prepareProfiler, + applyProfiler, + prepareExecutor, + applyExecutor + ); + } + }); } } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibNetwork.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibNetwork.java index 47c4ca7a5..64f233fd8 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibNetwork.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricAzureLibNetwork.java @@ -1,9 +1,5 @@ package mod.azure.azurelib.fabric.platform; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; -import mod.azure.azurelib.common.platform.Services; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; @@ -12,24 +8,35 @@ import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; -import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; +import mod.azure.azurelib.common.platform.Services; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + public class FabricAzureLibNetwork implements AzureLibNetwork { - public static void registerPacket(CustomPacketPayload.Type

    packetType, StreamCodec codec) { + public static void registerPacket( + CustomPacketPayload.Type

    packetType, + StreamCodec codec + ) { PayloadTypeRegistry.playS2C().register(packetType, (StreamCodec) codec); ClientPlayNetworking.registerGlobalReceiver(packetType, (packet, context) -> packet.handle()); } @Override - public void registerPacketInternal(CustomPacketPayload.Type

    payloadType, StreamCodec codec, boolean isClientBound) { + public void registerPacketInternal( + CustomPacketPayload.Type

    payloadType, + StreamCodec codec, + boolean isClientBound + ) { if (isClientBound) { - if (Services.PLATFORM.isEnvironmentClient()) FabricAzureLibNetwork.registerPacket(payloadType, codec); + if (Services.PLATFORM.isEnvironmentClient()) + FabricAzureLibNetwork.registerPacket(payloadType, codec); } else { PayloadTypeRegistry.playC2S().register(payloadType, (StreamCodec) codec); ServerPlayNetworking.registerGlobalReceiver(payloadType, (packet, context) -> packet.handle()); @@ -42,7 +49,8 @@ public FriendlyByteBuf createFriendlyByteBuf() { @Override public void sendToTrackingEntityAndSelf(AbstractPacket packet, Entity entityToTrack) { - if (entityToTrack instanceof ServerPlayer pl) sendToPlayer(packet, pl); + if (entityToTrack instanceof ServerPlayer pl) + sendToPlayer(packet, pl); for (ServerPlayer player : PlayerLookup.tracking(entityToTrack)) { sendToPlayer(packet, player); diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricCommonRegistry.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricCommonRegistry.java index a131334e7..4121926a6 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricCommonRegistry.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricCommonRegistry.java @@ -1,7 +1,6 @@ package mod.azure.azurelib.fabric.platform; import com.mojang.serialization.MapCodec; -import mod.azure.azurelib.common.platform.services.CommonRegistry; import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -27,22 +26,44 @@ import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.services.CommonRegistry; + public class FabricCommonRegistry implements CommonRegistry { - private static > Supplier registerSupplier(R registry, String modID, String id, Supplier object) { - final T registeredObject = Registry.register((Registry) registry, - ResourceLocation.fromNamespaceAndPath(modID, id), object.get()); + private static > Supplier registerSupplier( + R registry, + String modID, + String id, + Supplier object + ) { + final T registeredObject = Registry.register( + (Registry) registry, + ResourceLocation.fromNamespaceAndPath(modID, id), + object.get() + ); return () -> registeredObject; } - private static > Holder registerHolder(R registry, String modID, String id, Supplier object) { - return Registry.registerForHolder((Registry) registry, ResourceLocation.fromNamespaceAndPath(modID, id), - object.get()); + private static > Holder registerHolder( + R registry, + String modID, + String id, + Supplier object + ) { + return Registry.registerForHolder( + (Registry) registry, + ResourceLocation.fromNamespaceAndPath(modID, id), + object.get() + ); } @Override - public Supplier> registerBlockEntity(String modID, String blockEntityName, Supplier> blockEntityType) { + public Supplier> registerBlockEntity( + String modID, + String blockEntityName, + Supplier> blockEntityType + ) { return registerSupplier(BuiltInRegistries.BLOCK_ENTITY_TYPE, modID, blockEntityName, blockEntityType); } @@ -52,12 +73,20 @@ public Supplier registerBlock(String modID, String blockNam } @Override - public Supplier> registerEntity(String modID, String entityName, Supplier> entity) { + public Supplier> registerEntity( + String modID, + String entityName, + Supplier> entity + ) { return registerSupplier(BuiltInRegistries.ENTITY_TYPE, modID, entityName, entity); } @Override - public Holder registerArmorMaterial(String modID, String matName, Supplier armorMaterial) { + public Holder registerArmorMaterial( + String modID, + String matName, + Supplier armorMaterial + ) { return registerHolder(BuiltInRegistries.ARMOR_MATERIAL, modID, matName, armorMaterial); } @@ -77,7 +106,11 @@ public > Supplier registerScreen(String modID, String s } @Override - public Supplier> registerStructure(String modID, String structureName, MapCodec structure) { + public Supplier> registerStructure( + String modID, + String structureName, + MapCodec structure + ) { return registerSupplier(BuiltInRegistries.STRUCTURE_TYPE, modID, structureName, () -> typeConvert(structure)); } @@ -86,17 +119,29 @@ private static StructureType typeConvert(MapCodec co } @Override - public > Supplier registerParticle(String modID, String particleName, Supplier particle) { + public > Supplier registerParticle( + String modID, + String particleName, + Supplier particle + ) { return registerSupplier(BuiltInRegistries.PARTICLE_TYPE, modID, particleName, particle); } @Override - public Supplier registerCreativeModeTab(String modID, String tabName, Supplier tab) { + public Supplier registerCreativeModeTab( + String modID, + String tabName, + Supplier tab + ) { return registerSupplier(BuiltInRegistries.CREATIVE_MODE_TAB, modID, tabName, tab); } @Override - public Holder registerStatusEffect(String modID, String effectName, Supplier statusEffect) { + public Holder registerStatusEffect( + String modID, + String effectName, + Supplier statusEffect + ) { return registerHolder(BuiltInRegistries.MOB_EFFECT, modID, effectName, statusEffect); } @@ -106,7 +151,12 @@ public Supplier registerFluid(String modID, String fluidNam } @Override - public Supplier makeSpawnEggFor(Supplier> entityType, int primaryEggColour, int secondaryEggColour, Item.Properties itemProperties) { + public Supplier makeSpawnEggFor( + Supplier> entityType, + int primaryEggColour, + int secondaryEggColour, + Item.Properties itemProperties + ) { return () -> new SpawnEggItem(entityType.get(), primaryEggColour, secondaryEggColour, itemProperties); } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricPlatformHelper.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricPlatformHelper.java index 69ac973a4..259d21420 100644 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricPlatformHelper.java +++ b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricPlatformHelper.java @@ -1,22 +1,18 @@ package mod.azure.azurelib.fabric.platform; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; -import mod.azure.azurelib.common.platform.services.IPlatformHelper; -import mod.azure.azurelib.fabric.FabricAzureLibMod; import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponentType; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.level.block.entity.BlockEntityType; import java.nio.file.Path; import java.util.function.Supplier; import java.util.function.UnaryOperator; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.platform.services.IPlatformHelper; + public class FabricPlatformHelper implements IPlatformHelper { @Override @@ -40,9 +36,15 @@ public boolean isServerEnvironment() { } @Override - public Supplier> registerDataComponent(String id, UnaryOperator> builder) { - final DataComponentType componentType = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, - AzureLib.modResource(id).toString(), builder.apply(DataComponentType.builder()).build()); + public Supplier> registerDataComponent( + String id, + UnaryOperator> builder + ) { + final DataComponentType componentType = Registry.register( + BuiltInRegistries.DATA_COMPONENT_TYPE, + AzureLib.modResource(id).toString(), + builder.apply(DataComponentType.builder()).build() + ); return () -> componentType; } diff --git a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricSBLForked.java b/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricSBLForked.java deleted file mode 100644 index 48c57f389..000000000 --- a/fabric/src/main/java/mod/azure/azurelib/fabric/platform/FabricSBLForked.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.fabric.platform; - -import com.mojang.serialization.Codec; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.sblforked.SBLLoader; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; - -import java.util.Optional; -import java.util.function.Supplier; - -public class FabricSBLForked implements SBLLoader { - - public void init(Object eventBus) { - SBLMemoryTypes.init(); - SBLSensors.init(); - } - - @Override - public boolean isDevEnv() { - return FabricLoader.getInstance().isDevelopmentEnvironment(); - } - - @Override - public Supplier> registerMemoryType(String id) { - return registerMemoryType(id, Optional.empty()); - } - - @Override - public Supplier> registerMemoryType(String id, Optional> codec) { - MemoryModuleType memoryType = Registry.register(BuiltInRegistries.MEMORY_MODULE_TYPE, ResourceLocation.fromNamespaceAndPath(AzureLib.MOD_ID, id), new MemoryModuleType<>(codec)); - - return () -> memoryType; - } - - @Override - public > Supplier> registerSensorType(String id, Supplier sensor) { - SensorType sensorType = Registry.register( - BuiltInRegistries.SENSOR_TYPE, ResourceLocation.fromNamespaceAndPath(AzureLib.MOD_ID, id), new SensorType<>(sensor)); - - return () -> sensorType; - } -} diff --git a/fabric/src/main/resources/azurelib.fabric.mixins.json b/fabric/src/main/resources/azurelib.fabric.mixins.json index 0d6449856..4d8b39d8b 100644 --- a/fabric/src/main/resources/azurelib.fabric.mixins.json +++ b/fabric/src/main/resources/azurelib.fabric.mixins.json @@ -6,10 +6,14 @@ "defaultRequire": 1 }, "mixins": [ + "ItemStackMixin_AzItemStackIdentityRegistry", "PlayerListMixin" ], "client": [ + "BlockEntityMixin_AzBlockEntityAnimatorCache", + "EntityMixin_AzEntityAnimatorCache", "ItemRendererAccessor", + "ItemStackMixin_AzItemAnimatorCache", "MinecraftMixin", "MixinHumanoidArmorLayer", "MixinItemRenderer", diff --git a/gradle.properties b/gradle.properties index 8c640c6b2..e0b691c1a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -27,7 +27,7 @@ neo_loader_version_range = [3,) mapping_channel = official mapping_version = 1.21.1 minecraft_version_range = [1.21.1, 1.21.2) -neo_moddev = 2.0.1-beta +neo_moddev = 2.0.58-beta neo_version = 21.1.62 neo_version_range = [21,) @@ -51,5 +51,5 @@ mod_logo = azurelib.png mod_name = AzureLib mod_sources = https://github.com/AzureDoom/AzureLib mod_url = https://modrinth.com/mod/azurelib -version = 2.3.27 +version = 3.0.0-alpha22 modrinth_id = 7zlUOZvb diff --git a/neo/build.gradle b/neo/build.gradle index 6077cc786..d1a139d67 100644 --- a/neo/build.gradle +++ b/neo/build.gradle @@ -2,6 +2,7 @@ id 'multiloader-loader' id 'net.neoforged.moddev' id 'me.modmuss50.mod-publish-plugin' + id 'com.diffplug.spotless' version "7.0.0.BETA3" } neoForge { @@ -62,4 +63,4 @@ if (file('key.properties').exists()) { minecraftVersions.add(project.minecraft_version) } } -} \ No newline at end of file +} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/ClientModListener.java b/neo/src/main/java/mod/azure/azurelib/neoforge/ClientModListener.java index 4c17fe9c9..a119a05df 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/ClientModListener.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/ClientModListener.java @@ -1,22 +1,15 @@ package mod.azure.azurelib.neoforge; import com.mojang.blaze3d.platform.InputConstants; -import mod.azure.azurelib.common.api.client.helper.ClientUtils; -import mod.azure.azurelib.common.internal.client.AzureLibClient; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.config.ConfigHolder; -import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; import net.minecraft.client.KeyMapping; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.ModContainer; import net.neoforged.fml.ModList; -import net.neoforged.fml.ModLoadingContext; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; import net.neoforged.neoforge.client.gui.IConfigScreenFactory; -import net.neoforged.neoforge.common.NeoForge; import org.lwjgl.glfw.GLFW; import java.util.List; @@ -24,21 +17,38 @@ import java.util.Optional; import java.util.function.Supplier; +import mod.azure.azurelib.common.api.client.helper.ClientUtils; +import mod.azure.azurelib.common.internal.client.AzureLibClient; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.config.ConfigHolder; +import mod.azure.azurelib.common.internal.common.config.ConfigHolderRegistry; + @EventBusSubscriber(modid = AzureLib.MOD_ID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public class ClientModListener { @SubscribeEvent public static void registerKeys(final RegisterKeyMappingsEvent event) { if (AzureLib.hasKeyBindsInitialized) { - ClientUtils.RELOAD = new KeyMapping("key.azurelib.reload", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_R, - "category.azurelib.binds"); + ClientUtils.RELOAD = new KeyMapping( + "key.azurelib.reload", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_R, + "category.azurelib.binds" + ); event.register(ClientUtils.RELOAD); - ClientUtils.SCOPE = new KeyMapping("key.azurelib.scope", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_LEFT_ALT, - "category.azurelib.binds"); + ClientUtils.SCOPE = new KeyMapping( + "key.azurelib.scope", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_LEFT_ALT, + "category.azurelib.binds" + ); event.register(ClientUtils.SCOPE); - ClientUtils.FIRE_WEAPON = new KeyMapping("key.azurelib.fire", InputConstants.Type.KEYSYM, - GLFW.GLFW_KEY_UNKNOWN, - "category.azurelib.binds"); + ClientUtils.FIRE_WEAPON = new KeyMapping( + "key.azurelib.fire", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_UNKNOWN, + "category.azurelib.binds" + ); event.register(ClientUtils.FIRE_WEAPON); } } @@ -52,14 +62,16 @@ public static void clientInit(final FMLClientSetupEvent event) { Optional optional = modList.getModContainerById(modId); optional.ifPresent(modContainer -> { List> list = entry.getValue(); - modContainer.registerExtensionPoint(IConfigScreenFactory.class, (Supplier) () -> (container, screen) -> { - if (list.size() == 1) { - return AzureLibClient.getConfigScreen(list.get(0).getConfigId(), screen); + modContainer.registerExtensionPoint( + IConfigScreenFactory.class, + (Supplier) () -> (container, screen) -> { + if (list.size() == 1) { + return AzureLibClient.getConfigScreen(list.get(0).getConfigId(), screen); + } + return AzureLibClient.getConfigScreenByGroup(list, modId, screen); } - return AzureLibClient.getConfigScreenByGroup(list, modId, screen); - }); + ); }); } - } } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java index 27cc9dbdb..8f51fb9d2 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/NeoForgeAzureLibMod.java @@ -1,22 +1,5 @@ package mod.azure.azurelib.neoforge; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.common.internal.common.AzureLibMod; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; -import mod.azure.azurelib.common.internal.common.config.AzureLibConfig; -import mod.azure.azurelib.common.internal.common.config.format.ConfigFormats; -import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; -import mod.azure.azurelib.common.internal.common.network.packet.*; -import mod.azure.azurelib.neoforge.platform.NeoForgeAzureLibNetwork; -import mod.azure.azurelib.neoforge.platform.NeoForgeCommonRegistry; -import mod.azure.azurelib.sblforked.SBLConstants; -import net.minecraft.core.registries.Registries; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.material.PushReaction; import net.neoforged.bus.api.IEventBus; import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; @@ -24,13 +7,21 @@ import net.neoforged.neoforge.network.registration.PayloadRegistrar; import net.neoforged.neoforge.registries.DeferredRegister; -import java.util.function.Supplier; +import mod.azure.azurelib.common.internal.common.AzureLib; +import mod.azure.azurelib.common.internal.common.AzureLibMod; +import mod.azure.azurelib.common.internal.common.config.AzureLibConfig; +import mod.azure.azurelib.common.internal.common.config.format.ConfigFormats; +import mod.azure.azurelib.common.internal.common.config.io.ConfigIO; +import mod.azure.azurelib.common.internal.common.network.packet.*; +import mod.azure.azurelib.neoforge.platform.NeoForgeCommonRegistry; @Mod(AzureLib.MOD_ID) public final class NeoForgeAzureLibMod { - public static final DeferredRegister.DataComponents DATA_COMPONENTS_REGISTER = DeferredRegister.createDataComponents( - AzureLib.MOD_ID); + public static final DeferredRegister.DataComponents DATA_COMPONENTS_REGISTER = DeferredRegister + .createDataComponents( + AzureLib.MOD_ID + ); public NeoForgeAzureLibMod(IEventBus modEventBus) { AzureLib.initialize(); @@ -43,7 +34,6 @@ public NeoForgeAzureLibMod(IEventBus modEventBus) { AzureLibMod.config = AzureLibMod.registerConfig(AzureLibConfig.class, ConfigFormats.json()).getConfigInstance(); modEventBus.addListener(this::init); modEventBus.addListener(this::registerMessages); - SBLConstants.SBL_LOADER.init(modEventBus); } private void init(FMLCommonSetupEvent event) { @@ -53,10 +43,41 @@ private void init(FMLCommonSetupEvent event) { public void registerMessages(RegisterPayloadHandlersEvent event) { PayloadRegistrar registrar = event.registrar(AzureLib.MOD_ID); - registrar.playBidirectional(BlockEntityAnimTriggerPacket.TYPE, BlockEntityAnimTriggerPacket.CODEC, (msg, ctx) -> msg.handle()); - registrar.playBidirectional(BlockEntityAnimDataSyncPacket.TYPE, BlockEntityAnimDataSyncPacket.CODEC, (msg, ctx) -> msg.handle()); - registrar.playBidirectional(EntityAnimTriggerPacket.TYPE, EntityAnimTriggerPacket.CODEC, (msg, ctx) -> msg.handle()); - registrar.playBidirectional(EntityAnimDataSyncPacket.TYPE, EntityAnimDataSyncPacket.CODEC, (msg, ctx) -> msg.handle()); + registrar.playBidirectional( + BlockEntityAnimTriggerPacket.TYPE, + BlockEntityAnimTriggerPacket.CODEC, + (msg, ctx) -> msg.handle() + ); + registrar.playBidirectional( + BlockEntityAnimDataSyncPacket.TYPE, + BlockEntityAnimDataSyncPacket.CODEC, + (msg, ctx) -> msg.handle() + ); + registrar.playBidirectional( + EntityAnimTriggerPacket.TYPE, + EntityAnimTriggerPacket.CODEC, + (msg, ctx) -> msg.handle() + ); + registrar.playBidirectional( + AzEntityDispatchCommandPacket.TYPE, + AzEntityDispatchCommandPacket.CODEC, + (msg, ctx) -> msg.handle() + ); + registrar.playBidirectional( + AzItemStackDispatchCommandPacket.TYPE, + AzItemStackDispatchCommandPacket.CODEC, + (msg, ctx) -> msg.handle() + ); + registrar.playBidirectional( + AzBlockEntityDispatchCommandPacket.TYPE, + AzBlockEntityDispatchCommandPacket.CODEC, + (msg, ctx) -> msg.handle() + ); + registrar.playBidirectional( + EntityAnimDataSyncPacket.TYPE, + EntityAnimDataSyncPacket.CODEC, + (msg, ctx) -> msg.handle() + ); registrar.playBidirectional(AnimTriggerPacket.TYPE, AnimTriggerPacket.CODEC, (msg, ctx) -> msg.handle()); registrar.playBidirectional(AnimDataSyncPacket.TYPE, AnimDataSyncPacket.CODEC, (msg, ctx) -> msg.handle()); registrar.playBidirectional(SendConfigDataPacket.TYPE, SendConfigDataPacket.CODEC, (msg, ctx) -> msg.handle()); diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidNavigationElement.java b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidNavigationElement.java deleted file mode 100644 index c35b06632..000000000 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidNavigationElement.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under the MIT License. - */ -package mod.azure.azurelib.neoforge.api.core.navigation; - -import net.minecraft.world.entity.Mob; -import net.neoforged.neoforge.fluids.FluidType; - -/** - * Extracted interface to act as a helper utility for extensible implementations of (Neo)Forge's fluid API overhaul into pathfinding - */ -public interface MultiFluidNavigationElement { - /** - * Determine whether a given fluidType is one that the given entity can actively navigate through - *

    - * Note that the provided entity may not necessarily be in the given fluid at the time of this call - * - * @param mob The entity to check the pathing capabilities for - * @param fluidType The FluidType to check - */ - default boolean canSwimInFluid(Mob mob, FluidType fluidType) { - return canSwimInFluid(mob, fluidType, 1); - } - - /** - * Determine whether a given fluidType is one that the given entity can actively navigate through - *

    - * Note that the provided entity may not necessarily be in the given fluid at the time of this call - * - * @param mob The entity to check the pathing capabilities for - * @param fluidType The FluidType to check - * @param fluidHeight The depth of the given fluid in the block. I.E. the percentage of the block the fluid is deep - */ - default boolean canSwimInFluid(Mob mob, FluidType fluidType, double fluidHeight) { - return fluidType.canSwim(mob); - } -} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidSmoothGroundNavigation.java b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidSmoothGroundNavigation.java deleted file mode 100644 index e8a8474ab..000000000 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/MultiFluidSmoothGroundNavigation.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under the MIT License. - */ -package mod.azure.azurelib.neoforge.api.core.navigation; - -import mod.azure.azurelib.neoforge.api.core.navigation.nodeevaluator.MultiFluidWalkNodeEvaluator; -import mod.azure.azurelib.sblforked.api.core.navigation.SmoothGroundNavigation; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.level.pathfinder.PathFinder; - -/** - * An extension of {@link SmoothGroundNavigation} to allow for fluid-agnostic pathfinding based on (Neo)Forge's fluid API overhaul - *

    - * This allows for entities to pathfind in fluids other than water as necessary - * - * @see MultiFluidNavigationElement - */ -public class MultiFluidSmoothGroundNavigation extends SmoothGroundNavigation implements MultiFluidNavigationElement { - public MultiFluidSmoothGroundNavigation(Mob mob, Level level) { - super(mob, level); - } - - /** - * Patch {@link Path#getEntityPosAtNode} to use a proper rounding check - */ - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new MultiFluidWalkNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); - - return createSmoothPathFinder(this.nodeEvaluator, maxVisitedNodes); - } - - /** - * Whether the navigator should consider the entity's current state valid for navigating through a path - *

    - * Note that this does not specifically apply to any given path (and the entity's path may even be null at times when this is called) - */ - @Override - protected boolean canUpdatePath() { - return this.mob.onGround() || this.mob.isInFluidType((fluidType, height) -> canSwimInFluid(this.mob, fluidType, height), true) || this.mob.isPassenger(); - } - - /** - * Helper override to allow end-users to modify the fluids an entity can swim in, extensibly patching in (Neo)Forge's fluid API - *

    - * Don't use this method to adjust which fluids are 'swimmable', use {@link MultiFluidNavigationElement#canSwimInFluid} - * - * @return The nearest safe surface height for the entity - */ - @Override - public int getSurfaceY() { - if (this.mob.isInFluidType((fluidType, height) -> canSwimInFluid(this.mob, fluidType, height), true) && canFloat()) { - final int basePos = this.mob.getBlockY(); - BlockPos.MutableBlockPos pos = BlockPos.containing(this.mob.getX(), basePos, this.mob.getZ()).mutable(); - BlockState state = this.level.getBlockState(pos); - FluidState fluidState = state.getFluidState(); - - while (canSwimInFluid(this.mob, fluidState.getFluidType(), fluidState.getHeight(this.level, pos))) { - state = this.level.getBlockState(pos.move(Direction.UP)); - fluidState = state.getFluidState(); - - if (pos.getY() - basePos > 16) - return basePos; - } - - return pos.getY(); - } - - return Mth.floor(this.mob.getY() + 0.5); - } -} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/nodeevaluator/MultiFluidWalkNodeEvaluator.java b/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/nodeevaluator/MultiFluidWalkNodeEvaluator.java deleted file mode 100644 index ebaf7a3cf..000000000 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/api/core/navigation/nodeevaluator/MultiFluidWalkNodeEvaluator.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under the MIT License. - */ -package mod.azure.azurelib.neoforge.api.core.navigation.nodeevaluator; - -import mod.azure.azurelib.neoforge.api.core.navigation.MultiFluidNavigationElement; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.pathfinder.Node; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; -import net.minecraft.world.phys.AABB; -import org.jetbrains.annotations.NotNull; - -/** - * An extension of {@link WalkNodeEvaluator} to allow for fluid-agnostic pathfinding based on (Neo)Forge's fluid API overhaul - *

    - * This allows for entities to pathfind in fluids other than water as necessary - * - * @see MultiFluidNavigationElement - */ -public class MultiFluidWalkNodeEvaluator extends WalkNodeEvaluator implements MultiFluidNavigationElement { - /** - * Determine and create a path node for the current starting position based on the surrounding environment - */ - @Override - public @NotNull Node getStart() { - int groundY = this.mob.getBlockY(); - final BlockPos.MutableBlockPos testPos = new BlockPos.MutableBlockPos(this.mob.getX(), groundY, this.mob.getZ()); - BlockState groundState = this.currentContext.getBlockState(testPos); - - if (!this.mob.canStandOnFluid(groundState.getFluidState())) { - if (canFloat() && this.mob.isInFluidType((fluidType, height) -> canSwimInFluid(this.mob, fluidType, height))) { - while (true) { - if (groundState.getFluidState().isEmpty() || !canSwimInFluid(this.mob, groundState.getFluidState().getFluidType())) { - groundY--; - - break; - } - - groundState = this.currentContext.getBlockState(testPos.setY(++groundY)); - } - } - else if (this.mob.onGround()) { - groundY = Mth.floor(this.mob.getY() + 0.5d); - } - else { - testPos.setY(Mth.floor(this.mob.getY() + 1)); - - while (testPos.getY() > this.currentContext.level().getMinBuildHeight()) { - groundY = testPos.getY(); - testPos.setY(testPos.getY() - 1); - groundState = this.currentContext.getBlockState(testPos); - - if (!groundState.isAir() && !groundState.isPathfindable(PathComputationType.LAND)) - break; - } - } - } - else { - while (this.mob.canStandOnFluid(groundState.getFluidState())) { - groundState = this.currentContext.getBlockState(testPos.setY(++groundY)); - } - - groundY--; - } - - if (!canStartAt(testPos.setY(groundY))) { - AABB entityBounds = this.mob.getBoundingBox(); - - if (canStartAt(testPos.set(entityBounds.minX, groundY, entityBounds.minZ)) - || canStartAt(testPos.set(entityBounds.minX, groundY, entityBounds.maxZ)) - || canStartAt(testPos.set(entityBounds.maxX, groundY, entityBounds.minZ)) - || canStartAt(testPos.set(entityBounds.maxX, groundY, entityBounds.maxZ))) { - return getStartNode(testPos); - } - } - - return getStartNode(testPos.set(this.mob.getX(), groundY, this.mob.getZ())); - } - - /** - * Get the position the mob would stand on if it were standing at the given position - */ - @Override - protected double getFloorLevel(@NotNull BlockPos pos) { - final BlockGetter blockGetter = this.currentContext.level(); - FluidState fluidState = blockGetter.getFluidState(pos); - - return (canFloat() || isAmphibious()) && canSwimInFluid(this.mob, fluidState.getFluidType(), fluidState.getHeight(blockGetter, pos)) - ? pos.getY() + 0.5d - : getFloorLevel(blockGetter, pos); - } -} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/event/GeoRenderEvent.java b/neo/src/main/java/mod/azure/azurelib/neoforge/event/GeoRenderEvent.java index f9c798b19..e5f953ce2 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/event/GeoRenderEvent.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/event/GeoRenderEvent.java @@ -1,20 +1,11 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.neoforge.event; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.common.api.client.renderer.*; -import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; -import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; -import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; -import mod.azure.azurelib.core.animatable.GeoAnimatable; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.item.ItemStack; @@ -23,7 +14,16 @@ import net.neoforged.bus.api.ICancellableEvent; import org.jetbrains.annotations.Nullable; +import mod.azure.azurelib.common.api.client.renderer.*; +import mod.azure.azurelib.common.api.client.renderer.layer.GeoRenderLayer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.api.common.animatable.GeoReplacedEntity; +import mod.azure.azurelib.common.internal.client.renderer.GeoRenderer; +import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; +import mod.azure.azurelib.core.animatable.GeoAnimatable; + public interface GeoRenderEvent { + /** * Returns the renderer for this event * @@ -40,6 +40,7 @@ public interface GeoRenderEvent { * Renderer events for armor pieces being rendered by {@link GeoArmorRenderer} */ abstract class Armor extends Event implements GeoRenderEvent { + private final GeoArmorRenderer renderer; public Armor(GeoArmorRenderer renderer) { @@ -84,16 +85,29 @@ public EquipmentSlot getEquipmentSlot() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the armor piece will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the armor piece will not be rendered and the corresponding {@link Post} event will + * not be fired. */ - public static class Pre extends Armor implements ICancellableEvent { + public static class Pre extends Armor implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -130,13 +144,25 @@ public int getPackedLight() { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Armor { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -173,6 +199,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Armor { + public CompileRenderLayers(GeoArmorRenderer renderer) { super(renderer); } @@ -180,7 +207,8 @@ public CompileRenderLayers(GeoArmorRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -192,6 +220,7 @@ public void addLayer(GeoRenderLayer renderLayer) { * Renderer events for {@link BlockEntity BlockEntities} being rendered by {@link GeoBlockRenderer} */ abstract class Block extends Event implements GeoRenderEvent { + private final GeoBlockRenderer renderer; public Block(GeoBlockRenderer renderer) { @@ -219,16 +248,29 @@ public BlockEntity getBlockEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the block entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the block entity will not be rendered and the corresponding {@link Post} event + * will not be fired. */ - public static class Pre extends Block implements ICancellableEvent { + public static class Pre extends Block implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -265,13 +307,25 @@ public int getPackedLight() { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Block { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -308,6 +362,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Block { + public CompileRenderLayers(GeoBlockRenderer renderer) { super(renderer); } @@ -315,7 +370,8 @@ public CompileRenderLayers(GeoBlockRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -324,9 +380,11 @@ public void addLayer(GeoRenderLayer renderLayer) { } /** - * Renderer events for {@link net.minecraft.world.entity.Entity Entities} being rendered by {@link GeoEntityRenderer}, as well as + * Renderer events for {@link net.minecraft.world.entity.Entity Entities} being rendered by + * {@link GeoEntityRenderer}, as well as */ abstract class Entity extends Event implements GeoRenderEvent { + private final GeoEntityRenderer renderer; public Entity(GeoEntityRenderer renderer) { @@ -354,16 +412,29 @@ public net.minecraft.world.entity.Entity getEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the entity will not be rendered and the corresponding {@link Post} event will not + * be fired. */ - public static class Pre extends Entity implements ICancellableEvent { + public static class Pre extends Entity implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -400,13 +471,25 @@ public int getPackedLight() { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Entity { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -443,6 +526,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Entity { + public CompileRenderLayers(GeoEntityRenderer renderer) { super(renderer); } @@ -450,7 +534,8 @@ public CompileRenderLayers(GeoEntityRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -462,6 +547,7 @@ public void addLayer(GeoRenderLayer renderLayer) { * Renderer events for {@link ItemStack Items} being rendered by {@link GeoItemRenderer} */ abstract class Item extends Event implements GeoRenderEvent { + private final GeoItemRenderer renderer; public Item(GeoItemRenderer renderer) { @@ -489,16 +575,29 @@ public ItemStack getItemStack() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the ItemStack will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the ItemStack will not be rendered and the corresponding {@link Post} event will + * not be fired. */ - public static class Pre extends Item implements ICancellableEvent { + public static class Pre extends Item implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -535,13 +634,25 @@ public int getPackedLight() { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Item { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -578,6 +689,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Item { + public CompileRenderLayers(GeoItemRenderer renderer) { super(renderer); } @@ -585,7 +697,8 @@ public CompileRenderLayers(GeoItemRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -597,6 +710,7 @@ public void addLayer(GeoRenderLayer renderLayer) { * Renderer events for miscellaneous {@link GeoAnimatable animatables} being rendered by {@link GeoObjectRenderer} */ abstract class Object extends Event implements GeoRenderEvent { + private final GeoObjectRenderer renderer; public Object(GeoObjectRenderer renderer) { @@ -617,16 +731,29 @@ public GeoObjectRenderer getRenderer() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the object will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the object will not be rendered and the corresponding {@link Post} event will not + * be fired. */ - public static class Pre extends Object implements ICancellableEvent { + public static class Pre extends Object implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -659,17 +786,29 @@ public int getPackedLight() { /** * Post-render event for miscellaneous animatables being rendered by {@link GeoObjectRenderer} -

    + *

    * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends Object { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -706,6 +845,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends Object { + public CompileRenderLayers(GeoObjectRenderer renderer) { super(renderer); } @@ -713,7 +853,8 @@ public CompileRenderLayers(GeoObjectRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); @@ -722,9 +863,11 @@ public void addLayer(GeoRenderLayer renderLayer) { } /** - * Renderer events for miscellaneous {@link GeoReplacedEntity replaced entities} being rendered by {@link GeoReplacedEntityRenderer} + * Renderer events for miscellaneous {@link GeoReplacedEntity replaced entities} being rendered by + * {@link GeoReplacedEntityRenderer} */ abstract class ReplacedEntity extends Event implements GeoRenderEvent { + private final GeoReplacedEntityRenderer renderer; public ReplacedEntity(GeoReplacedEntityRenderer renderer) { @@ -752,16 +895,29 @@ public net.minecraft.world.entity.Entity getReplacedEntity() { * This event is called before rendering, but after {@link GeoRenderer#preRender} *

    * This event is Cancelable
    - * If the event is cancelled, the entity will not be rendered and the corresponding {@link Post} event will not be fired. + * If the event is cancelled, the entity will not be rendered and the corresponding {@link Post} event will not + * be fired. */ public static class Pre extends ReplacedEntity implements ICancellableEvent { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Pre(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Pre( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -798,13 +954,25 @@ public int getPackedLight() { * This event is called after {@link GeoRenderer#postRender} */ public static class Post extends ReplacedEntity { + private final PoseStack poseStack; + private final BakedGeoModel model; + private final MultiBufferSource bufferSource; + private final float partialTick; + private final int packedLight; - public Post(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { + public Post( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { super(renderer); this.poseStack = poseStack; @@ -841,6 +1009,7 @@ public int getPackedLight() { * Use this event to add render layers to the renderer as needed */ public static class CompileRenderLayers extends ReplacedEntity { + public CompileRenderLayers(GeoReplacedEntityRenderer renderer) { super(renderer); } @@ -848,11 +1017,12 @@ public CompileRenderLayers(GeoReplacedEntityRenderer renderer) { /** * Adds a {@link GeoRenderLayer} to the renderer *

    - * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and renderer + * Type-safety is not checked here, so ensure that your layer is compatible with this animatable and + * renderer */ public void addLayer(GeoRenderLayer renderLayer) { getRenderer().addRenderLayer(renderLayer); } } } -} \ No newline at end of file +} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/ClientHooksMixin.java b/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/ClientHooksMixin.java index 710e2e494..71ef1a7d3 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/ClientHooksMixin.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/ClientHooksMixin.java @@ -1,14 +1,10 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.neoforge.mixins; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.Model; import net.minecraft.world.entity.EquipmentSlot; @@ -20,21 +16,24 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; + @Mixin(ClientHooks.class) public class ClientHooksMixin { @Inject(method = "getArmorModel", at = @At("RETURN"), remap = false, cancellable = true) private static void injectAzureArmors( - LivingEntity entityLiving, - ItemStack itemStack, - EquipmentSlot slot, - HumanoidModel _default, - CallbackInfoReturnable cir + LivingEntity entityLiving, + ItemStack itemStack, + EquipmentSlot slot, + HumanoidModel _default, + CallbackInfoReturnable cir ) { if (itemStack.getItem() instanceof GeoItem) cir.setReturnValue( - RenderProvider.of(itemStack) - .getGenericArmorModel(entityLiving, itemStack, slot, (HumanoidModel) _default) + RenderProvider.of(itemStack) + .getGenericArmorModel(entityLiving, itemStack, slot, (HumanoidModel) _default) ); } } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java b/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java index de0bb193c..9fb2e2a8b 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/mixins/MixinHumanoidArmorLayer.java @@ -1,8 +1,6 @@ /** - * This class is a fork of the matching class found in the Geckolib repository. - * Original source: https://github.com/bernie-g/geckolib - * Copyright © 2024 Bernie-G. - * Licensed under the MIT License. + * This class is a fork of the matching class found in the Geckolib repository. Original source: + * https://github.com/bernie-g/geckolib Copyright © 2024 Bernie-G. Licensed under the MIT License. * https://github.com/bernie-g/geckolib/blob/main/LICENSE */ package mod.azure.azurelib.neoforge.mixins; @@ -11,11 +9,7 @@ import com.llamalad7.mixinextras.sugar.Share; import com.llamalad7.mixinextras.sugar.ref.LocalRef; import com.mojang.blaze3d.vertex.PoseStack; -import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; -import mod.azure.azurelib.common.api.common.animatable.GeoItem; -import mod.azure.azurelib.common.internal.client.RenderProvider; import net.minecraft.client.model.HumanoidModel; -import net.minecraft.client.model.Model; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.layers.HumanoidArmorLayer; import net.minecraft.client.renderer.texture.OverlayTexture; @@ -30,35 +24,90 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import mod.azure.azurelib.common.api.client.renderer.GeoArmorRenderer; +import mod.azure.azurelib.common.api.common.animatable.GeoItem; +import mod.azure.azurelib.common.internal.client.RenderProvider; +import mod.azure.azurelib.core2.render.armor.AzArmorRendererRegistry; + @Mixin(HumanoidArmorLayer.class) public abstract class MixinHumanoidArmorLayer> { @ModifyExpressionValue( - method = "renderArmorPiece(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/EquipmentSlot;ILnet/minecraft/client/model/HumanoidModel;FFFFFF)V", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/entity/LivingEntity;getItemBySlot(Lnet/minecraft/world/entity/EquipmentSlot;)Lnet/minecraft/world/item/ItemStack;" - ) + method = "renderArmorPiece(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/EquipmentSlot;ILnet/minecraft/client/model/HumanoidModel;FFFFFF)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;getItemBySlot(Lnet/minecraft/world/entity/EquipmentSlot;)Lnet/minecraft/world/item/ItemStack;" + ) ) - private ItemStack azurelib$captureItemBySlot(ItemStack original, @Share("item_by_slot") LocalRef itemBySlotRef) { + private ItemStack azurelib$captureItemBySlot( + ItemStack original, + @Share("item_by_slot") LocalRef itemBySlotRef + ) { itemBySlotRef.set(original); return original; } - @Inject(method = "renderArmorPiece(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/EquipmentSlot;ILnet/minecraft/client/model/HumanoidModel;FFFFFF)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;usesInnerModel(Lnet/minecraft/world/entity/EquipmentSlot;)Z"), cancellable = true) - public void azurelib$renderAzurelibModel(PoseStack poseStack, MultiBufferSource bufferSource, LivingEntity entity, EquipmentSlot equipmentSlot, int packedLight, HumanoidModel baseModel, float limbSwing, float limbSwingAmount, float partialTick, float ageInTicks, float netHeadYaw, float headPitch, CallbackInfo ci, @Share("item_by_slot") LocalRef itemBySlotRef) { - final ItemStack stack = itemBySlotRef.get(); - final Model azurelibModel = RenderProvider.of(stack).getGenericArmorModel(entity, stack, equipmentSlot, - (HumanoidModel) baseModel); + @Inject( + method = "renderArmorPiece(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/EquipmentSlot;ILnet/minecraft/client/model/HumanoidModel;FFFFFF)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;usesInnerModel(Lnet/minecraft/world/entity/EquipmentSlot;)Z" + ), cancellable = true + ) + public void azurelib$renderAzurelibModel( + PoseStack poseStack, + MultiBufferSource bufferSource, + LivingEntity entity, + EquipmentSlot equipmentSlot, + int packedLight, + HumanoidModel baseModel, + float limbSwing, + float limbSwingAmount, + float partialTick, + float ageInTicks, + float netHeadYaw, + float headPitch, + CallbackInfo ci, + @Share("item_by_slot") LocalRef itemBySlotRef + ) { + var stack = itemBySlotRef.get(); + var renderProvider = RenderProvider.of(stack); + @SuppressWarnings("unchecked") + var humanoidModel = (HumanoidModel) baseModel; + var azurelibModel = renderProvider + .getGenericArmorModel(entity, stack, equipmentSlot, humanoidModel); + var i2 = stack.is( + ItemTags.DYEABLE + ) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(stack, -6265536)) : -1; if (azurelibModel != null && stack.getItem() instanceof GeoItem) { - if (azurelibModel instanceof GeoArmorRenderer geoArmorRenderer) + if (azurelibModel instanceof GeoArmorRenderer geoArmorRenderer) { geoArmorRenderer.prepForRender(entity, stack, equipmentSlot, baseModel); + } baseModel.copyPropertiesTo((A) azurelibModel); - azurelibModel.renderToBuffer(poseStack, null, packedLight, OverlayTexture.NO_OVERLAY, stack.is( - ItemTags.DYEABLE) ? FastColor.ARGB32.opaque(DyedItemColor.getOrDefault(stack, -6265536)) : -1); + azurelibModel.renderToBuffer( + poseStack, + null, + packedLight, + OverlayTexture.NO_OVERLAY, + i2 + ); + ci.cancel(); + } + + var renderer = AzArmorRendererRegistry.getOrNull(stack.getItem()); + + if (renderer != null) { + var rendererPipeline = renderer.rendererPipeline(); + var armorModel = rendererPipeline.armorModel(); + @SuppressWarnings("unchecked") + var typedHumanoidModel = (HumanoidModel) armorModel; + + renderer.prepForRender(entity, stack, equipmentSlot, baseModel); + baseModel.copyPropertiesTo(typedHumanoidModel); + armorModel.renderToBuffer(poseStack, null, packedLight, OverlayTexture.NO_OVERLAY, i2); ci.cancel(); } } -} \ No newline at end of file +} diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/AzureLibEventsNeoForge.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/AzureLibEventsNeoForge.java index 6d996e468..1d996151d 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/AzureLibEventsNeoForge.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/AzureLibEventsNeoForge.java @@ -1,14 +1,16 @@ package mod.azure.azurelib.neoforge.platform; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.renderer.MultiBufferSource; +import net.neoforged.neoforge.common.NeoForge; + import mod.azure.azurelib.common.api.client.renderer.*; import mod.azure.azurelib.common.internal.common.cache.object.BakedGeoModel; import mod.azure.azurelib.common.platform.services.AzureEvents; import mod.azure.azurelib.neoforge.event.GeoRenderEvent; -import net.minecraft.client.renderer.MultiBufferSource; -import net.neoforged.neoforge.common.NeoForge; public class AzureLibEventsNeoForge implements AzureEvents { + /** * Fire the {@link GeoRenderEvent.Block.CompileRenderLayers} event */ @@ -21,16 +23,34 @@ public void fireCompileBlockRenderLayers(GeoBlockRenderer renderer) { * Fire the {@link GeoRenderEvent.Block.Pre} event */ @Override - public boolean fireBlockPreRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.Block.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireBlockPreRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Block.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.Block.Post} event */ @Override - public void fireBlockPostRender(GeoBlockRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.Block.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireBlockPostRender( + GeoBlockRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Block.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } /** @@ -45,16 +65,34 @@ public void fireCompileArmorRenderLayers(GeoArmorRenderer renderer) { * Fire the {@link GeoRenderEvent.Armor.Pre} event */ @Override - public boolean fireArmorPreRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.Armor.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireArmorPreRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Armor.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.Armor.Post} event */ @Override - public void fireArmorPostRender(GeoArmorRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.Armor.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireArmorPostRender( + GeoArmorRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Armor.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } /** @@ -69,16 +107,34 @@ public void fireCompileEntityRenderLayers(GeoEntityRenderer renderer) { * Fire the {@link GeoRenderEvent.Entity.Pre} event */ @Override - public boolean fireEntityPreRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.Entity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireEntityPreRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Entity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.Entity.Post} event */ @Override - public void fireEntityPostRender(GeoEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.Entity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireEntityPostRender( + GeoEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Entity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } /** @@ -93,16 +149,34 @@ public void fireCompileReplacedEntityRenderLayers(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.ReplacedEntity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireReplacedEntityPreRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.ReplacedEntity.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.ReplacedEntity.Post} event */ @Override - public void fireReplacedEntityPostRender(GeoReplacedEntityRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.ReplacedEntity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireReplacedEntityPostRender( + GeoReplacedEntityRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.ReplacedEntity.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } /** @@ -117,16 +191,34 @@ public void fireCompileItemRenderLayers(GeoItemRenderer renderer) { * Fire the {@link GeoRenderEvent.Item.Pre} event */ @Override - public boolean fireItemPreRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.Item.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireItemPreRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Item.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.Item.Post} event */ @Override - public void fireItemPostRender(GeoItemRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.Item.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireItemPostRender( + GeoItemRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Item.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } /** @@ -141,15 +233,33 @@ public void fireCompileObjectRenderLayers(GeoObjectRenderer renderer) { * Fire the {@link GeoRenderEvent.Object.Pre} event */ @Override - public boolean fireObjectPreRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - return !NeoForge.EVENT_BUS.post(new GeoRenderEvent.Object.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight)).isCanceled(); + public boolean fireObjectPreRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + return !NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Object.Pre(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ).isCanceled(); } /** * Fire the {@link GeoRenderEvent.Object.Post} event */ @Override - public void fireObjectPostRender(GeoObjectRenderer renderer, PoseStack poseStack, BakedGeoModel model, MultiBufferSource bufferSource, float partialTick, int packedLight) { - NeoForge.EVENT_BUS.post(new GeoRenderEvent.Object.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight)); + public void fireObjectPostRender( + GeoObjectRenderer renderer, + PoseStack poseStack, + BakedGeoModel model, + MultiBufferSource bufferSource, + float partialTick, + int packedLight + ) { + NeoForge.EVENT_BUS.post( + new GeoRenderEvent.Object.Post(renderer, poseStack, model, bufferSource, partialTick, packedLight) + ); } } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibInitializer.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibInitializer.java index 727bef300..96eaeec05 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibInitializer.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibInitializer.java @@ -1,10 +1,11 @@ package mod.azure.azurelib.neoforge.platform; -import mod.azure.azurelib.common.internal.common.cache.AzureLibCache; -import mod.azure.azurelib.common.platform.services.AzureLibInitializer; import net.neoforged.api.distmarker.Dist; import net.neoforged.fml.loading.FMLEnvironment; +import mod.azure.azurelib.common.internal.common.cache.AzureLibCache; +import mod.azure.azurelib.common.platform.services.AzureLibInitializer; + public class NeoForgeAzureLibInitializer implements AzureLibInitializer { @Override diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibNetwork.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibNetwork.java index cf2945537..e4d008e7d 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibNetwork.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeAzureLibNetwork.java @@ -1,8 +1,5 @@ package mod.azure.azurelib.neoforge.platform; -import mod.azure.azurelib.common.internal.common.network.AbstractPacket; -import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; -import mod.azure.azurelib.common.platform.services.AzureLibNetwork; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; @@ -14,18 +11,32 @@ import net.neoforged.neoforge.network.PacketDistributor; import net.neoforged.neoforge.network.registration.PayloadRegistrar; +import mod.azure.azurelib.common.internal.common.network.AbstractPacket; +import mod.azure.azurelib.common.internal.common.network.packet.SendConfigDataPacket; +import mod.azure.azurelib.common.platform.services.AzureLibNetwork; + public class NeoForgeAzureLibNetwork implements AzureLibNetwork { private static PayloadRegistrar registrar = null; @Override - public void registerPacketInternal(CustomPacketPayload.Type

    payloadType, StreamCodec codec, boolean isClientBound) { + public void registerPacketInternal( + CustomPacketPayload.Type

    payloadType, + StreamCodec codec, + boolean isClientBound + ) { if (isClientBound) { - registrar.playToClient(payloadType, (StreamCodec) codec, - (packet, context) -> packet.handle()); + registrar.playToClient( + payloadType, + (StreamCodec) codec, + (packet, context) -> packet.handle() + ); } else { - registrar.playToServer(payloadType, (StreamCodec) codec, - (packet, context) -> packet.handle()); + registrar.playToServer( + payloadType, + (StreamCodec) codec, + (packet, context) -> packet.handle() + ); } } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeCommonRegistry.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeCommonRegistry.java index 328f4090c..47fbd3697 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeCommonRegistry.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeCommonRegistry.java @@ -1,7 +1,6 @@ package mod.azure.azurelib.neoforge.platform; import com.mojang.serialization.MapCodec; -import mod.azure.azurelib.common.platform.services.CommonRegistry; import net.minecraft.core.Holder; import net.minecraft.core.particles.ParticleType; import net.minecraft.core.registries.Registries; @@ -26,79 +25,111 @@ import java.util.function.Supplier; +import mod.azure.azurelib.common.platform.services.CommonRegistry; + public class NeoForgeCommonRegistry implements CommonRegistry { + public static DeferredRegister> blockEntityTypeDeferredRegister; + public static DeferredRegister blockDeferredRegister; + public static DeferredRegister> entityTypeDeferredRegister; + public static DeferredRegister armorMaterialDeferredRegister; + public static DeferredRegister itemDeferredRegister; + public static DeferredRegister soundEventDeferredRegister; + public static DeferredRegister> menuTypeDeferredRegister; + public static DeferredRegister> structureTypeDeferredRegister; + public static DeferredRegister> particleTypeDeferredRegister; + public static DeferredRegister creativeModeTabDeferredRegister; + public static DeferredRegister statusEffectDeferredRegister; + public static DeferredRegister fluidDeferredRegister; @Override - public Supplier> registerBlockEntity(String modID, String blockEntityName, Supplier> blockEntityType) { - if (modID.isEmpty()) modID = "minecraft"; + public Supplier> registerBlockEntity( + String modID, + String blockEntityName, + Supplier> blockEntityType + ) { + if (modID.isEmpty()) + modID = "minecraft"; blockEntityTypeDeferredRegister = DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, modID); return blockEntityTypeDeferredRegister.register(blockEntityName, blockEntityType); } @Override public Supplier registerBlock(String modID, String blockName, Supplier block) { - if (modID.isEmpty()) modID = "minecraft"; + if (modID.isEmpty()) + modID = "minecraft"; blockDeferredRegister = DeferredRegister.create(Registries.BLOCK, modID); return blockDeferredRegister.register(blockName, block); } @Override - public Supplier> registerEntity(String modID, String entityName, Supplier> entity) { -// if (modID.isEmpty()) modID = "minecraft"; -// entityTypeDeferredRegister = DeferredRegister.create(Registries.ENTITY_TYPE, modID); -// return entityTypeDeferredRegister.register(entityName, entity); + public Supplier> registerEntity( + String modID, + String entityName, + Supplier> entity + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // entityTypeDeferredRegister = DeferredRegister.create(Registries.ENTITY_TYPE, modID); + // return entityTypeDeferredRegister.register(entityName, entity); return null; } @Override - public Holder registerArmorMaterial(String modID, String matName, Supplier armorMaterial) { -// if (modID.isEmpty()) modID = "minecraft"; -// armorMaterialDeferredRegister = DeferredRegister.create(Registries.ARMOR_MATERIAL, modID); -// return (Holder) armorMaterialDeferredRegister.register(matName, armorMaterial); + public Holder registerArmorMaterial( + String modID, + String matName, + Supplier armorMaterial + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // armorMaterialDeferredRegister = DeferredRegister.create(Registries.ARMOR_MATERIAL, modID); + // return (Holder) armorMaterialDeferredRegister.register(matName, armorMaterial); return null; } @Override public Supplier registerItem(String modID, String itemName, Supplier item) { -// if (modID.isEmpty()) modID = "minecraft"; -// itemDeferredRegister = DeferredRegister.create(Registries.ITEM, modID); -// return itemDeferredRegister.register(itemName, item); + // if (modID.isEmpty()) modID = "minecraft"; + // itemDeferredRegister = DeferredRegister.create(Registries.ITEM, modID); + // return itemDeferredRegister.register(itemName, item); return null; } @Override public Supplier registerSound(String modID, String soundName, Supplier sound) { -// if (modID.isEmpty()) modID = "minecraft"; -// soundEventDeferredRegister = DeferredRegister.create(Registries.SOUND_EVENT, modID); -// return soundEventDeferredRegister.register(soundName, sound); + // if (modID.isEmpty()) modID = "minecraft"; + // soundEventDeferredRegister = DeferredRegister.create(Registries.SOUND_EVENT, modID); + // return soundEventDeferredRegister.register(soundName, sound); return null; } @Override public > Supplier registerScreen(String modID, String screenName, Supplier menuType) { -// if (modID.isEmpty()) modID = "minecraft"; -// menuTypeDeferredRegister = DeferredRegister.create(Registries.MENU, modID); -// return menuTypeDeferredRegister.register(screenName, menuType); + // if (modID.isEmpty()) modID = "minecraft"; + // menuTypeDeferredRegister = DeferredRegister.create(Registries.MENU, modID); + // return menuTypeDeferredRegister.register(screenName, menuType); return null; } @Override - public Supplier> registerStructure(String modID, String structureName, MapCodec structure) { -// if (modID.isEmpty()) modID = "minecraft"; -// structureTypeDeferredRegister = DeferredRegister.create(Registries.STRUCTURE_TYPE, modID); -// return structureTypeDeferredRegister.register(structureName, () -> typeConvert(structure)); + public Supplier> registerStructure( + String modID, + String structureName, + MapCodec structure + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // structureTypeDeferredRegister = DeferredRegister.create(Registries.STRUCTURE_TYPE, modID); + // return structureTypeDeferredRegister.register(structureName, () -> typeConvert(structure)); return null; } @@ -107,39 +138,56 @@ private static StructureType typeConvert(MapCodec co } @Override - public > Supplier registerParticle(String modID, String particleName, Supplier particle) { -// if (modID.isEmpty()) modID = "minecraft"; -// particleTypeDeferredRegister = DeferredRegister.create(Registries.PARTICLE_TYPE, modID); -// return particleTypeDeferredRegister.register(particleName, particle); + public > Supplier registerParticle( + String modID, + String particleName, + Supplier particle + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // particleTypeDeferredRegister = DeferredRegister.create(Registries.PARTICLE_TYPE, modID); + // return particleTypeDeferredRegister.register(particleName, particle); return null; } @Override - public Supplier registerCreativeModeTab(String modID, String tabName, Supplier tab) { -// if (modID.isEmpty()) modID = "minecraft"; -// creativeModeTabDeferredRegister = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, modID); -// return creativeModeTabDeferredRegister.register(tabName, tab); + public Supplier registerCreativeModeTab( + String modID, + String tabName, + Supplier tab + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // creativeModeTabDeferredRegister = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, modID); + // return creativeModeTabDeferredRegister.register(tabName, tab); return null; } @Override - public Holder registerStatusEffect(String modID, String effectName, Supplier statusEffect) { -// if (modID.isEmpty()) modID = "minecraft"; -// statusEffectDeferredRegister = DeferredRegister.create(Registries.MOB_EFFECT, modID); -// return (Holder) statusEffectDeferredRegister.register(effectName, statusEffect); + public Holder registerStatusEffect( + String modID, + String effectName, + Supplier statusEffect + ) { + // if (modID.isEmpty()) modID = "minecraft"; + // statusEffectDeferredRegister = DeferredRegister.create(Registries.MOB_EFFECT, modID); + // return (Holder) statusEffectDeferredRegister.register(effectName, statusEffect); return null; } @Override public Supplier registerFluid(String modID, String fluidName, Supplier fluid) { -// if (modID.isEmpty()) modID = "minecraft"; -// fluidDeferredRegister = DeferredRegister.create(Registries.FLUID, modID); -// return fluidDeferredRegister.register(fluidName, fluid); + // if (modID.isEmpty()) modID = "minecraft"; + // fluidDeferredRegister = DeferredRegister.create(Registries.FLUID, modID); + // return fluidDeferredRegister.register(fluidName, fluid); return null; } @Override - public Supplier makeSpawnEggFor(Supplier> entityType, int primaryEggColour, int secondaryEggColour, Item.Properties itemProperties) { + public Supplier makeSpawnEggFor( + Supplier> entityType, + int primaryEggColour, + int secondaryEggColour, + Item.Properties itemProperties + ) { return () -> new DeferredSpawnEggItem(entityType, primaryEggColour, secondaryEggColour, itemProperties); } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgePlatformHelper.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgePlatformHelper.java index b14a412d6..adcbc913c 100644 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgePlatformHelper.java +++ b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgePlatformHelper.java @@ -1,11 +1,6 @@ package mod.azure.azurelib.neoforge.platform; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightBlock; -import mod.azure.azurelib.common.internal.common.blocks.TickingLightEntity; -import mod.azure.azurelib.common.platform.services.IPlatformHelper; -import mod.azure.azurelib.neoforge.NeoForgeAzureLibMod; import net.minecraft.core.component.DataComponentType; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.neoforged.fml.loading.FMLEnvironment; import net.neoforged.fml.loading.FMLLoader; @@ -13,6 +8,9 @@ import java.util.function.Supplier; import java.util.function.UnaryOperator; +import mod.azure.azurelib.common.platform.services.IPlatformHelper; +import mod.azure.azurelib.neoforge.NeoForgeAzureLibMod; + public class NeoForgePlatformHelper implements IPlatformHelper { @Override @@ -36,7 +34,10 @@ public boolean isServerEnvironment() { } @Override - public Supplier> registerDataComponent(String id, UnaryOperator> builder) { + public Supplier> registerDataComponent( + String id, + UnaryOperator> builder + ) { return NeoForgeAzureLibMod.DATA_COMPONENTS_REGISTER.registerComponentType(id, builder); } diff --git a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeSBLForked.java b/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeSBLForked.java deleted file mode 100644 index 1eeb07718..000000000 --- a/neo/src/main/java/mod/azure/azurelib/neoforge/platform/NeoForgeSBLForked.java +++ /dev/null @@ -1,60 +0,0 @@ -/** - * This class is a fork of the matching class found in the SmartBrainLib repository. - * Original source: https://github.com/Tslat/SmartBrainLib - * Copyright © 2024 Tslat. - * Licensed under Mozilla Public License 2.0: https://github.com/Tslat/SmartBrainLib/blob/1.21/LICENSE. - */ -package mod.azure.azurelib.neoforge.platform; - -import com.mojang.serialization.Codec; -import mod.azure.azurelib.common.internal.common.AzureLib; -import mod.azure.azurelib.sblforked.SBLLoader; -import mod.azure.azurelib.sblforked.api.core.sensor.ExtendedSensor; -import mod.azure.azurelib.sblforked.registry.SBLMemoryTypes; -import mod.azure.azurelib.sblforked.registry.SBLSensors; -import net.minecraft.core.registries.Registries; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.ai.memory.MemoryModuleType; -import net.minecraft.world.entity.ai.sensing.SensorType; -import net.neoforged.bus.api.IEventBus; -import net.neoforged.fml.loading.FMLLoader; -import net.neoforged.neoforge.registries.DeferredRegister; - -import java.util.Optional; -import java.util.function.Supplier; - -public class NeoForgeSBLForked implements SBLLoader { - public static final DeferredRegister> MEMORY_TYPES = DeferredRegister.create(Registries.MEMORY_MODULE_TYPE, AzureLib.MOD_ID); - public static final DeferredRegister> SENSORS = DeferredRegister.create(Registries.SENSOR_TYPE, AzureLib.MOD_ID); - public static final DeferredRegister> ENTITY_TYPES = DeferredRegister.create(Registries.ENTITY_TYPE, AzureLib.MOD_ID); - - public void init(Object eventBus) { - final IEventBus modEventBus = (IEventBus)eventBus; - - MEMORY_TYPES.register(modEventBus); - SENSORS.register(modEventBus); - - SBLMemoryTypes.init(); - SBLSensors.init(); - } - - @Override - public boolean isDevEnv() { - return !FMLLoader.isProduction(); - } - - @Override - public Supplier> registerMemoryType(String id) { - return registerMemoryType(id, Optional.empty()); - } - - @Override - public Supplier> registerMemoryType(String id, Optional> codec) { - return MEMORY_TYPES.register(id, () -> new MemoryModuleType<>(codec)); - } - - @Override - public > Supplier> registerSensorType(String id, Supplier sensor) { - return SENSORS.register(id, () -> new SensorType<>(sensor)); - } -} diff --git a/neo/src/main/resources/META-INF/accesstransformer.cfg b/neo/src/main/resources/META-INF/accesstransformer.cfg index c53fb8529..1a8bff0c4 100644 --- a/neo/src/main/resources/META-INF/accesstransformer.cfg +++ b/neo/src/main/resources/META-INF/accesstransformer.cfg @@ -31,35 +31,6 @@ public com.mojang.blaze3d.vertex.BufferBuilder building # building public net.minecraft.world.level.block.entity.BlockEntityType$BlockEntitySupplier public net.minecraft.client.renderer.RenderStateShard$OverlayStateShard -# Brain -public net.minecraft.world.entity.ai.Brain sensors -public net.minecraft.world.entity.ai.Brain memories -public net.minecraft.world.entity.ai.Brain activityRequirements -public net.minecraft.world.entity.ai.Brain activityMemoriesToEraseWhenStopped -public net.minecraft.world.entity.ai.behavior.Behavior entryCondition -public-f net.minecraft.world.entity.ai.Brain$Provider -public net.minecraft.world.entity.ai.Brain$Provider (Ljava/util/Collection;Ljava/util/Collection;)V -public net.minecraft.world.entity.ai.Brain setMemoryInternal(Lnet/minecraft/world/entity/ai/memory/MemoryModuleType;Ljava/util/Optional;)V -public net.minecraft.world.entity.ai.Brain$MemoryValue setMemoryInternal(Lnet/minecraft/world/entity/ai/Brain;)V -public net.minecraft.world.entity.ai.Brain forgetOutdatedMemories()V -public net.minecraft.world.entity.ai.Brain coreActivities -public net.minecraft.world.entity.ai.Brain activeActivities -public net.minecraft.world.entity.ai.Brain availableBehaviorsByPriority -public net.minecraft.world.entity.ai.Brain activityRequirementsAreMet(Lnet/minecraft/world/entity/schedule/Activity;)Z -public net.minecraft.world.entity.ai.Brain setActiveActivity(Lnet/minecraft/world/entity/schedule/Activity;)V - -# Behaviour -public-f net.minecraft.world.entity.ai.behavior.Behavior tryStart(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;J)Z -public net.minecraft.world.entity.ai.behavior.Behavior endTimestamp -public net.minecraft.world.entity.ai.behavior.Behavior status -public net.minecraft.world.entity.ai.behavior.Behavior hasRequiredMemories(Lnet/minecraft/world/entity/LivingEntity;)Z -public net.minecraft.world.entity.ai.behavior.GateBehavior behaviors - -# Sensor -public-f net.minecraft.world.entity.ai.sensing.Sensor tick(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/LivingEntity;)V -public net.minecraft.world.entity.ai.sensing.Sensor scanRate -public net.minecraft.world.entity.ai.sensing.Sensor RANDOM - # World public net.minecraft.world.level.Level getEntities()Lnet/minecraft/world/level/entity/LevelEntityGetter; public net.minecraft.client.multiplayer.ClientLevel getEntities()Lnet/minecraft/world/level/entity/LevelEntityGetter; diff --git a/neo/src/main/resources/azurelib.neo.mixins.json b/neo/src/main/resources/azurelib.neo.mixins.json index f01cb3d8a..0b8d7b137 100644 --- a/neo/src/main/resources/azurelib.neo.mixins.json +++ b/neo/src/main/resources/azurelib.neo.mixins.json @@ -6,10 +6,14 @@ "defaultRequire": 1 }, "mixins": [ + "ItemStackMixin_AzItemStackIdentityRegistry", "PlayerListMixin" ], "client": [ + "BlockEntityMixin_AzBlockEntityAnimatorCache", + "EntityMixin_AzEntityAnimatorCache", "ItemRendererAccessor", + "ItemStackMixin_AzItemAnimatorCache", "MinecraftMixin", "MixinItemRenderer", "TextureManagerMixin"