From 28e43f21b05e6aad8adba5dd61fdb45d96279852 Mon Sep 17 00:00:00 2001 From: Kli Kli Date: Mon, 11 Mar 2024 14:43:44 +0100 Subject: [PATCH] feat: generalize job models for client (#1074) - thanks @GaeaKat * feat: move job models to generic system * fix: copy glowtexture in addition to normal texture for afrit * fix: removed debug line and extraneous override * refactor: move second generic into addition of first --- .../client/entities/SpiritJobClient.java | 29 + .../client/model/entity/AfritModel.java | 12 +- .../model/entity/DefaultedJobEntityModel.java | 80 +++ .../client/model/entity/DjinniModel.java | 54 +- .../client/model/entity/FoliotModel.java | 77 +-- .../client/model/entity/MaridModel.java | 11 +- .../common/entity/job/SpiritJobFactory.java | 10 +- .../registry/OccultismSpiritJobs.java | 33 +- .../entity/afrit_worker.animation.json | 502 ++++++++++++++++++ .../entity/foliot_worker.animation.json | 245 +++++++++ ...ation.json => marid_worker.animation.json} | 0 .../occultism/geo/entity/afrit.geo.json | 2 +- .../geo/entity/afrit_worker.geo.json | 133 +++++ .../geo/entity/foliot_worker.geo.json | 95 ++++ .../{marid.geo.json => marid_worker.geo.json} | 2 +- .../textures/entity/afrit_worker.png | Bin 0 -> 5479 bytes .../textures/entity/afrit_worker_glowmask.png | Bin 0 -> 2357 bytes .../textures/entity/foliot_worker.png | Bin 0 -> 1615 bytes .../textures/entity/marid_worker.png | Bin 0 -> 7522 bytes 19 files changed, 1124 insertions(+), 161 deletions(-) create mode 100644 src/main/java/com/klikli_dev/occultism/client/entities/SpiritJobClient.java create mode 100644 src/main/java/com/klikli_dev/occultism/client/model/entity/DefaultedJobEntityModel.java create mode 100644 src/main/resources/assets/occultism/animations/entity/afrit_worker.animation.json create mode 100644 src/main/resources/assets/occultism/animations/entity/foliot_worker.animation.json rename src/main/resources/assets/occultism/animations/entity/{marid.animation.json => marid_worker.animation.json} (100%) create mode 100644 src/main/resources/assets/occultism/geo/entity/afrit_worker.geo.json create mode 100644 src/main/resources/assets/occultism/geo/entity/foliot_worker.geo.json rename src/main/resources/assets/occultism/geo/entity/{marid.geo.json => marid_worker.geo.json} (99%) create mode 100644 src/main/resources/assets/occultism/textures/entity/afrit_worker.png create mode 100644 src/main/resources/assets/occultism/textures/entity/afrit_worker_glowmask.png create mode 100644 src/main/resources/assets/occultism/textures/entity/foliot_worker.png create mode 100644 src/main/resources/assets/occultism/textures/entity/marid_worker.png diff --git a/src/main/java/com/klikli_dev/occultism/client/entities/SpiritJobClient.java b/src/main/java/com/klikli_dev/occultism/client/entities/SpiritJobClient.java new file mode 100644 index 000000000..e0e5d736a --- /dev/null +++ b/src/main/java/com/klikli_dev/occultism/client/entities/SpiritJobClient.java @@ -0,0 +1,29 @@ +package com.klikli_dev.occultism.client.entities; + +import com.klikli_dev.occultism.Occultism; +import net.minecraft.resources.ResourceLocation; + + +public class SpiritJobClient { + protected ResourceLocation modelID; + + public SpiritJobClient(ResourceLocation modelID) { + this.modelID = modelID; + } + + public ResourceLocation modelID() { + return modelID; + } + + public static SpiritJobClient create(ResourceLocation modelID) { + return new SpiritJobClient(modelID); + } + + public static SpiritJobClient create(String modelId) { + return create(new ResourceLocation(Occultism.MODID,modelId)); + } + + public static SpiritJobClient create() { + return create("worker"); + } +} diff --git a/src/main/java/com/klikli_dev/occultism/client/model/entity/AfritModel.java b/src/main/java/com/klikli_dev/occultism/client/model/entity/AfritModel.java index 76726d45a..b55811626 100644 --- a/src/main/java/com/klikli_dev/occultism/client/model/entity/AfritModel.java +++ b/src/main/java/com/klikli_dev/occultism/client/model/entity/AfritModel.java @@ -31,15 +31,9 @@ import software.bernie.geckolib.model.DefaultedGeoModel; -public class AfritModel extends DefaultedEntityGeoModel { - +public class AfritModel extends DefaultedJobEntityModel { + public final static String ASSET_SUBPATH = "afrit"; public AfritModel() { - super(new ResourceLocation(Occultism.MODID, "afrit"), true); - } - - @Override - public RenderType getRenderType(AfritEntity animatable, ResourceLocation texture) { - return RenderType.entityTranslucent(this.getTextureResource(animatable)); + super(new ResourceLocation(Occultism.MODID, "afrit"), true,ASSET_SUBPATH); } - } diff --git a/src/main/java/com/klikli_dev/occultism/client/model/entity/DefaultedJobEntityModel.java b/src/main/java/com/klikli_dev/occultism/client/model/entity/DefaultedJobEntityModel.java new file mode 100644 index 000000000..09382d22c --- /dev/null +++ b/src/main/java/com/klikli_dev/occultism/client/model/entity/DefaultedJobEntityModel.java @@ -0,0 +1,80 @@ +package com.klikli_dev.occultism.client.model.entity; + +import com.klikli_dev.occultism.Occultism; +import com.klikli_dev.occultism.common.entity.job.SpiritJobFactory; +import com.klikli_dev.occultism.common.entity.spirit.DjinniEntity; +import com.klikli_dev.occultism.common.entity.spirit.SpiritEntity; +import com.klikli_dev.occultism.registry.OccultismSpiritJobs; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.GeckoLibCache; +import software.bernie.geckolib.core.animatable.GeoAnimatable; +import software.bernie.geckolib.model.DefaultedEntityGeoModel; + +import java.util.HashMap; +import java.util.Map; + +public abstract class DefaultedJobEntityModel extends DefaultedEntityGeoModel { + private final String entity_subpath; + protected final Map jobModels; + protected final ModelData worker; + + public DefaultedJobEntityModel(ResourceLocation assetSubpath, boolean turnsHead, String entity_subpath) { + super(assetSubpath, turnsHead); + this.entity_subpath = entity_subpath; + jobModels = new HashMap<>(); + this.worker = this.buildModelData("worker"); + for(var job: OccultismSpiritJobs.JOBS.getEntries()) { + SpiritJobFactory factory = job.get(); + jobModels.put(job.getId().toString(), this.buildModelData(factory.client().modelID(),"_")); + } + } + + public ModelData getModelData(T animatable) { + var job = animatable.getJobID(); + var model = jobModels.getOrDefault(job, this.worker); + if(!GeckoLibCache.getBakedModels().containsKey(model.model())) + model=this.worker; + return model; + } + public ModelData buildModelData(String job) { + return this.buildModelData(job, "_"); + } + + public ModelData buildModelData(ResourceLocation basePath) { + return new ModelData( + this.buildFormattedModelPath(basePath), + this.buildFormattedTexturePath(basePath), + this.buildFormattedAnimationPath(basePath) + ); + } + public ModelData buildModelData(ResourceLocation location, String separator) { + return this.buildModelData(new ResourceLocation(location.getNamespace(), entity_subpath + separator + location.getPath())); + } + public ModelData buildModelData(String job, String separator) { + return this.buildModelData(new ResourceLocation(Occultism.MODID, job),separator); + } + + public record ModelData(ResourceLocation model, ResourceLocation texture, ResourceLocation animation) { + } + + @Override + public RenderType getRenderType(T animatable, ResourceLocation texture) { + return RenderType.entityTranslucent(this.getTextureResource(animatable)); + } + + @Override + public ResourceLocation getModelResource(T animatable) { + return this.getModelData(animatable).model(); + } + + @Override + public ResourceLocation getTextureResource(T animatable) { + return this.getModelData(animatable).texture(); + } + + @Override + public ResourceLocation getAnimationResource(T animatable) { + return this.getModelData(animatable).animation(); + } +} diff --git a/src/main/java/com/klikli_dev/occultism/client/model/entity/DjinniModel.java b/src/main/java/com/klikli_dev/occultism/client/model/entity/DjinniModel.java index 3c91d86f5..72ac7a25d 100644 --- a/src/main/java/com/klikli_dev/occultism/client/model/entity/DjinniModel.java +++ b/src/main/java/com/klikli_dev/occultism/client/model/entity/DjinniModel.java @@ -33,62 +33,12 @@ import java.util.Objects; -public class DjinniModel extends DefaultedEntityGeoModel { +public class DjinniModel extends DefaultedJobEntityModel { public final static String ASSET_SUBPATH = "djinni"; - public final ModelData worker; - public final ModelData machineManager; public DjinniModel() { - super(new ResourceLocation(Occultism.MODID, ASSET_SUBPATH), false); - - this.worker = this.buildModelData("worker"); - this.machineManager = this.buildModelData("machine_manager"); - } - - public ModelData getModelData(DjinniEntity animatable) { - var job = animatable.getJobID(); - - if (Objects.equals(job, OccultismSpiritJobs.MANAGE_MACHINE.getId().toString())) { - return this.machineManager; - } - - return this.worker; - } - - @Override - public RenderType getRenderType(DjinniEntity animatable, ResourceLocation texture) { - return RenderType.entityTranslucent(this.getTextureResource(animatable)); - } - - @Override - public ResourceLocation getModelResource(DjinniEntity animatable) { - return this.getModelData(animatable).model(); - } - - @Override - public ResourceLocation getTextureResource(DjinniEntity animatable) { - return this.getModelData(animatable).texture(); - } - - @Override - public ResourceLocation getAnimationResource(DjinniEntity animatable) { - return this.getModelData(animatable).animation(); - } - - public ModelData buildModelData(String job) { - return this.buildModelData(job, "_"); - } - - public ModelData buildModelData(String job, String separator) { - return new ModelData( - this.buildFormattedModelPath(new ResourceLocation(Occultism.MODID, ASSET_SUBPATH + separator + job)), - this.buildFormattedTexturePath(new ResourceLocation(Occultism.MODID, ASSET_SUBPATH + separator + job)), - this.buildFormattedAnimationPath(new ResourceLocation(Occultism.MODID, ASSET_SUBPATH + separator + job)) - ); - } - - public record ModelData(ResourceLocation model, ResourceLocation texture, ResourceLocation animation) { + super(new ResourceLocation(Occultism.MODID, ASSET_SUBPATH), false,ASSET_SUBPATH); } } diff --git a/src/main/java/com/klikli_dev/occultism/client/model/entity/FoliotModel.java b/src/main/java/com/klikli_dev/occultism/client/model/entity/FoliotModel.java index 2c2b5bc98..7c31b7fb6 100644 --- a/src/main/java/com/klikli_dev/occultism/client/model/entity/FoliotModel.java +++ b/src/main/java/com/klikli_dev/occultism/client/model/entity/FoliotModel.java @@ -23,90 +23,23 @@ package com.klikli_dev.occultism.client.model.entity; import com.klikli_dev.occultism.Occultism; +import com.klikli_dev.occultism.common.entity.job.SpiritJobFactory; import com.klikli_dev.occultism.common.entity.spirit.FoliotEntity; import com.klikli_dev.occultism.registry.OccultismSpiritJobs; import net.minecraft.resources.ResourceLocation; import software.bernie.geckolib.model.DefaultedEntityGeoModel; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; -public class FoliotModel extends DefaultedEntityGeoModel { +public class FoliotModel extends DefaultedJobEntityModel { public final static String ASSET_SUBPATH = "foliot"; - public final ModelData crusher; - public final ModelData transporter; - public final ModelData janitor; - public final ModelData lumberjack; - public final ModelData saplingTrader; - public final ModelData otherstoneTrader; - public FoliotModel() { - super(new ResourceLocation(Occultism.MODID, ASSET_SUBPATH), false); - - this.crusher = this.buildModelData("crusher"); - this.transporter = this.buildModelData("transporter"); - this.janitor = this.buildModelData("janitor"); - this.lumberjack = this.buildModelData("lumberjack"); - this.otherstoneTrader = this.buildModelData("otherstone_trader"); - this.saplingTrader = this.buildModelData("sapling_trader"); - } - - public ModelData getModelData(FoliotEntity animatable) { - var job = animatable.getJobID(); - - if (Objects.equals(job, OccultismSpiritJobs.TRANSPORT_ITEMS.getId().toString())) { - return this.transporter; - } - - if (Objects.equals(job, OccultismSpiritJobs.CLEANER.getId().toString())) { - return this.janitor; - } - - if (Objects.equals(job, OccultismSpiritJobs.LUMBERJACK.getId().toString())) { - return this.lumberjack; - } - - if (Objects.equals(job, OccultismSpiritJobs.TRADE_OTHERSTONE_T1.getId().toString())) { - return this.otherstoneTrader; - } - - if (Objects.equals(job, OccultismSpiritJobs.TRADE_OTHERWORLD_SAPLINGS_T2.getId().toString())) { - return this.saplingTrader; - } - - return this.crusher; - } - - @Override - public ResourceLocation getModelResource(FoliotEntity animatable) { - return this.getModelData(animatable).model(); - } - - @Override - public ResourceLocation getTextureResource(FoliotEntity animatable) { - return this.getModelData(animatable).texture(); - } - - @Override - public ResourceLocation getAnimationResource(FoliotEntity animatable) { - return this.getModelData(animatable).animation(); - } - - public ModelData buildModelData(String job) { - return this.buildModelData(job, "_"); - } - - public ModelData buildModelData(String job, String separator) { - return new ModelData( - this.buildFormattedModelPath(new ResourceLocation(Occultism.MODID, ASSET_SUBPATH + separator + job)), - this.buildFormattedTexturePath(new ResourceLocation(Occultism.MODID, ASSET_SUBPATH + separator + job)), - this.buildFormattedAnimationPath(new ResourceLocation(Occultism.MODID, ASSET_SUBPATH + separator + job)) - ); - } - - public record ModelData(ResourceLocation model, ResourceLocation texture, ResourceLocation animation) { + super(new ResourceLocation(Occultism.MODID, ASSET_SUBPATH), false,ASSET_SUBPATH); } } diff --git a/src/main/java/com/klikli_dev/occultism/client/model/entity/MaridModel.java b/src/main/java/com/klikli_dev/occultism/client/model/entity/MaridModel.java index 306b7f69b..d633f3cc1 100644 --- a/src/main/java/com/klikli_dev/occultism/client/model/entity/MaridModel.java +++ b/src/main/java/com/klikli_dev/occultism/client/model/entity/MaridModel.java @@ -39,15 +39,10 @@ import software.bernie.geckolib.model.DefaultedGeoModel; -public class MaridModel extends DefaultedEntityGeoModel { - +public class MaridModel extends DefaultedJobEntityModel { + public final static String ASSET_SUBPATH = "marid"; public MaridModel() { - super(new ResourceLocation(Occultism.MODID, "marid"), true); - } - - @Override - public RenderType getRenderType(MaridEntity animatable, ResourceLocation texture) { - return RenderType.entityTranslucent(this.getTextureResource(animatable)); + super(new ResourceLocation(Occultism.MODID, "marid"), true,ASSET_SUBPATH); } } diff --git a/src/main/java/com/klikli_dev/occultism/common/entity/job/SpiritJobFactory.java b/src/main/java/com/klikli_dev/occultism/common/entity/job/SpiritJobFactory.java index 8c4fcaa33..1a7c500be 100644 --- a/src/main/java/com/klikli_dev/occultism/common/entity/job/SpiritJobFactory.java +++ b/src/main/java/com/klikli_dev/occultism/common/entity/job/SpiritJobFactory.java @@ -22,17 +22,21 @@ package com.klikli_dev.occultism.common.entity.job; +import com.klikli_dev.occultism.client.entities.SpiritJobClient; import com.klikli_dev.occultism.common.entity.spirit.SpiritEntity; import com.klikli_dev.occultism.registry.OccultismSpiritJobs; +import net.minecraft.resources.ResourceLocation; import java.util.function.Function; public class SpiritJobFactory { Function constructor; + SpiritJobClient client; - public SpiritJobFactory(Function constructor) { + public SpiritJobFactory(Function constructor, SpiritJobClient client) { this.constructor = constructor; + this.client = client; } public SpiritJob create(SpiritEntity entity) { @@ -41,4 +45,8 @@ public SpiritJob create(SpiritEntity entity) { return job; } + public SpiritJobClient client() { + return this.client; + } + } diff --git a/src/main/java/com/klikli_dev/occultism/registry/OccultismSpiritJobs.java b/src/main/java/com/klikli_dev/occultism/registry/OccultismSpiritJobs.java index 6d6b3b0eb..6ccd7390f 100644 --- a/src/main/java/com/klikli_dev/occultism/registry/OccultismSpiritJobs.java +++ b/src/main/java/com/klikli_dev/occultism/registry/OccultismSpiritJobs.java @@ -23,6 +23,7 @@ package com.klikli_dev.occultism.registry; import com.klikli_dev.occultism.Occultism; +import com.klikli_dev.occultism.client.entities.SpiritJobClient; import com.klikli_dev.occultism.common.entity.job.*; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; @@ -30,8 +31,6 @@ import net.neoforged.neoforge.registries.DeferredHolder; import net.neoforged.neoforge.registries.DeferredRegister; -import java.util.function.Supplier; - public class OccultismSpiritJobs { public static final ResourceKey> JOBS_KEY = ResourceKey.createRegistryKey(new ResourceLocation(Occultism.MODID, "spirit_job_factories")); @@ -41,13 +40,13 @@ public class OccultismSpiritJobs { }); public static final DeferredHolder LUMBERJACK = JOBS.register("lumberjack", - () -> new SpiritJobFactory(LumberjackJob::new)); + () -> new SpiritJobFactory(LumberjackJob::new, SpiritJobClient.create("lumberjack"))); public static final DeferredHolder MANAGE_MACHINE = JOBS.register("manage_machine", - () -> new SpiritJobFactory(ManageMachineJob::new)); + () -> new SpiritJobFactory(ManageMachineJob::new, SpiritJobClient.create("machine_manager"))); public static final DeferredHolder TRANSPORT_ITEMS = JOBS.register("transport_items", - () -> new SpiritJobFactory(TransportItemsJob::new)); + () -> new SpiritJobFactory(TransportItemsJob::new, SpiritJobClient.create("transporter"))); public static final DeferredHolder CLEANER = JOBS.register("cleaner", - () -> new SpiritJobFactory(CleanerJob::new)); + () -> new SpiritJobFactory(CleanerJob::new, SpiritJobClient.create("janitor"))); //Trade jobs public static final DeferredHolder TRADE_OTHERSTONE_T1 = JOBS.register("trade_otherstone_t1", @@ -56,14 +55,14 @@ public class OccultismSpiritJobs { job.setTimeToConvert(15); job.setMaxTradesPerRound(4); return job; - })); + }, SpiritJobClient.create("sapling_trader"))); public static final DeferredHolder TRADE_OTHERWORLD_SAPLINGS_T2 = JOBS.register("trade_otherworld_saplings_t1", () -> new SpiritJobFactory((entity) -> { TraderJob job = new TraderJob(entity, new ResourceLocation(Occultism.MODID, "spirit_trade/otherworld_sapling")); job.setTimeToConvert(20); job.setMaxTradesPerRound(1); return job; - })); + }, SpiritJobClient.create("otherstone_trader"))); //Crushing jobs public static final DeferredHolder CRUSH_TIER1 = JOBS.register("crush_tier1", @@ -71,38 +70,38 @@ public class OccultismSpiritJobs { () -> Occultism.SERVER_CONFIG.spiritJobs.tier1CrusherTimeMultiplier.get().floatValue(), () -> Occultism.SERVER_CONFIG.spiritJobs.tier1CrusherOutputMultiplier.get().floatValue(), () -> 1 - ))); + ), SpiritJobClient.create("crusher"))); public static final DeferredHolder CRUSH_TIER2 = JOBS.register("crush_tier2", () -> new SpiritJobFactory((entity) -> new CrusherJob(entity, () -> Occultism.SERVER_CONFIG.spiritJobs.tier2CrusherTimeMultiplier.get().floatValue(), () -> Occultism.SERVER_CONFIG.spiritJobs.tier2CrusherOutputMultiplier.get().floatValue(), () -> 2 - ))); + ), SpiritJobClient.create("crusher"))); public static final DeferredHolder CRUSH_TIER3 = JOBS.register("crush_tier3", () -> new SpiritJobFactory((entity) -> new CrusherJob(entity, () -> Occultism.SERVER_CONFIG.spiritJobs.tier3CrusherTimeMultiplier.get().floatValue(), () -> Occultism.SERVER_CONFIG.spiritJobs.tier3CrusherOutputMultiplier.get().floatValue(), () -> 3 - ))); + ), SpiritJobClient.create("crusher"))); public static final DeferredHolder CRUSH_TIER4 = JOBS.register("crush_tier4", () -> new SpiritJobFactory((entity) -> new CrusherJob(entity, () -> Occultism.SERVER_CONFIG.spiritJobs.tier4CrusherTimeMultiplier.get().floatValue(), () -> Occultism.SERVER_CONFIG.spiritJobs.tier4CrusherOutputMultiplier.get().floatValue(), () -> 4 - ))); + ), SpiritJobClient.create("crusher"))); //Weather Jobs public static final DeferredHolder CLEAR_WEATHER = JOBS.register("clear_weather", - () -> new SpiritJobFactory((entity) -> new ClearWeatherJob(entity, 20 * 15))); + () -> new SpiritJobFactory((entity) -> new ClearWeatherJob(entity, 20 * 15), SpiritJobClient.create())); public static final DeferredHolder RAIN_WEATHER = JOBS.register("rain_weather", - () -> new SpiritJobFactory((entity) -> new RainWeatherJob(entity, 20 * 30))); + () -> new SpiritJobFactory((entity) -> new RainWeatherJob(entity, 20 * 30), SpiritJobClient.create())); public static final DeferredHolder THUNDER_WEATHER = JOBS.register("thunder_weather", - () -> new SpiritJobFactory((entity) -> new ThunderWeatherJob(entity, 20 * 60))); + () -> new SpiritJobFactory((entity) -> new ThunderWeatherJob(entity, 20 * 60), SpiritJobClient.create())); //Time Jobs public static final DeferredHolder DAY_TIME = JOBS.register("day_time", - () -> new SpiritJobFactory((entity) -> new DayTimeJob(entity, 20 * 5))); + () -> new SpiritJobFactory((entity) -> new DayTimeJob(entity, 20 * 5), SpiritJobClient.create())); public static final DeferredHolder NIGHT_TIME = JOBS.register("night_time", - () -> new SpiritJobFactory((entity) -> new NightTimeJob(entity, 20 * 5))); + () -> new SpiritJobFactory((entity) -> new NightTimeJob(entity, 20 * 5), SpiritJobClient.create())); } diff --git a/src/main/resources/assets/occultism/animations/entity/afrit_worker.animation.json b/src/main/resources/assets/occultism/animations/entity/afrit_worker.animation.json new file mode 100644 index 000000000..0ab6ed691 --- /dev/null +++ b/src/main/resources/assets/occultism/animations/entity/afrit_worker.animation.json @@ -0,0 +1,502 @@ +{ + "format_version": "1.8.0", + "animations": { + "idle": { + "loop": true, + "animation_length": 2, + "bones": { + "1": { + "rotation": { + "0.0": { + "vector": [0, 0, 2.5] + }, + "1.0": { + "vector": [0, 0, -5] + }, + "2.0": { + "vector": [0, 0, 2.5] + } + } + }, + "2": { + "rotation": { + "0.0": { + "vector": [-9.99067, -0.43399, -2.46207] + }, + "1.0": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "2.0": { + "vector": [-9.99067, -0.43399, -2.46207] + } + } + }, + "3": { + "rotation": { + "0.0": { + "vector": [7.49294, -0.32621, 2.47864] + }, + "1.0": { + "vector": [7.43656, 0.9762, -7.43656] + }, + "2.0": { + "vector": [7.49294, -0.32621, 2.47864] + } + } + }, + "Torso": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0.5, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + }, + "scale": { + "vector": [1, 1, 1] + } + }, + "Lhand": { + "rotation": { + "0.0": { + "vector": [7.5, 0, -10] + }, + "1.0": { + "vector": [7.49294, 0.32621, -12.47864] + }, + "2.0": { + "vector": [7.5, 0, -10] + } + } + }, + "bone": { + "rotation": { + "vector": [-27.5, 0, 0] + } + }, + "Rhand": { + "rotation": { + "0.0": { + "vector": [-10, 0, 12.5] + }, + "1.0": { + "vector": [-9.99403, 0.34723, 14.46964] + }, + "2.0": { + "vector": [-10, 0, 12.5] + } + } + }, + "bone2": { + "rotation": { + "vector": [-12, -17.5, 0] + } + }, + "Tail": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "bone3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, -180, 0] + }, + "2.0": { + "vector": [0, -357.5, 0] + } + } + }, + "bone4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 180, 0] + }, + "2.0": { + "vector": [0, 360, 0] + } + } + }, + "bone5": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, -180, 0] + }, + "2.0": { + "vector": [0, -357.5, 0] + } + } + }, + "chest": { + "scale": { + "0.0": { + "vector": [1, 1, 1] + }, + "1.0": { + "vector": [1.07, 1, 1] + }, + "2.0": { + "vector": [1, 1, 1] + } + } + } + } + }, + "attack": { + "loop": "hold_on_last_frame", + "animation_length": 0.5, + "bones": { + "1": { + "rotation": { + "0.0": { + "vector": [0, 0, 2.5] + }, + "0.25": { + "vector": [0, 0, -5] + }, + "0.5": { + "vector": [0, 0, 2.5] + } + } + }, + "2": { + "rotation": { + "0.0": { + "vector": [-9.99067, -0.43399, -2.46207] + }, + "0.25": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "0.5": { + "vector": [-9.99067, -0.43399, -2.46207] + } + } + }, + "3": { + "rotation": { + "0.0": { + "vector": [7.49294, -0.32621, 2.47864] + }, + "0.25": { + "vector": [7.43656, 0.9762, -7.43656] + }, + "0.5": { + "vector": [7.49294, -0.32621, 2.47864] + } + } + }, + "Torso": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -45, 0] + }, + "0.2917": { + "vector": [0, -2, 0] + }, + "0.5": { + "vector": [0, 0, 0] + } + }, + "position": { + "vector": [0, 0, 0] + }, + "scale": { + "vector": [1, 1, 1] + } + }, + "Lhand": { + "rotation": { + "vector": [7.5, 0, -10] + } + }, + "bone": { + "rotation": { + "vector": [-27.5, 0, 0] + } + }, + "Rhand": { + "rotation": { + "0.0": { + "vector": [-10, 0, 12.5] + }, + "0.2083": { + "vector": [-55.11756, -17.98449, 37.66083] + }, + "0.25": { + "vector": [-43.96521, 11.10344, 43.241] + }, + "0.2917": { + "vector": [-4.05266, -5.23211, 27.36235] + }, + "0.375": { + "vector": [-13.12996, 0.13083, 34.13127] + }, + "0.5": { + "vector": [-10, 0, 12.5] + } + } + }, + "bone2": { + "rotation": { + "0.0": { + "vector": [-12, -17.5, 0] + }, + "0.25": { + "vector": [-32, -17.5, 0] + }, + "0.2917": { + "vector": [10.20951, -5.54343, -1.04318] + }, + "0.5": { + "vector": [-12, -17.5, 0] + } + } + }, + "Tail": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "bone3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -180, 0] + }, + "0.5": { + "vector": [0, -357.5, 0] + } + } + }, + "bone4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 180, 0] + }, + "0.5": { + "vector": [0, 360, 0] + } + } + }, + "bone5": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, -180, 0] + }, + "0.5": { + "vector": [0, -357.5, 0] + } + } + }, + "chest": { + "scale": { + "vector": [1, 1, 1] + } + }, + "Head": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "0.25": { + "vector": [0, 45, 0] + }, + "0.2917": { + "vector": [0, 5.75, 0] + }, + "0.4167": { + "vector": [0, 0, 0] + } + } + } + } + }, + "walk": { + "loop": true, + "animation_length": 2, + "bones": { + "1": { + "rotation": { + "0.0": { + "vector": [0, 0, 2.5] + }, + "1.0": { + "vector": [0, 0, -5] + }, + "2.0": { + "vector": [0, 0, 2.5] + } + } + }, + "2": { + "rotation": { + "0.0": { + "vector": [-9.99067, -0.43399, -2.46207] + }, + "1.0": { + "vector": [-9.96271, 0.86717, 4.92442] + }, + "2.0": { + "vector": [-9.99067, -0.43399, -2.46207] + } + } + }, + "3": { + "rotation": { + "0.0": { + "vector": [7.49294, -0.32621, 2.47864] + }, + "1.0": { + "vector": [7.43656, 0.9762, -7.43656] + }, + "2.0": { + "vector": [7.49294, -0.32621, 2.47864] + } + } + }, + "Torso": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 0.5, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + }, + "scale": { + "vector": [1, 1, 1] + } + }, + "Lhand": { + "rotation": { + "0.0": { + "vector": [28.5, 0, -10] + }, + "1.0": { + "vector": [28.5, 0, -10] + }, + "2.0": { + "vector": [28.5, 0, -10] + } + } + }, + "bone": { + "rotation": { + "vector": [-27.5, 0, 0] + } + }, + "Rhand": { + "rotation": { + "0.0": { + "vector": [-44, 0, 12.5] + }, + "1.0": { + "vector": [-44, 0, 12.5] + }, + "2.0": { + "vector": [-44, 0, 12.5] + } + } + }, + "bone2": { + "rotation": { + "vector": [-26.69094, -36.01788, 4.80057] + }, + "position": { + "vector": [0, 0.5, -0.4] + } + }, + "Tail": { + "rotation": { + "vector": [0, 0, 0] + } + }, + "bone3": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, -180, 0] + }, + "2.0": { + "vector": [0, -357.5, 0] + } + } + }, + "bone4": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, 180, 0] + }, + "2.0": { + "vector": [0, 360, 0] + } + } + }, + "bone5": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, -180, 0] + }, + "2.0": { + "vector": [0, -357.5, 0] + } + } + }, + "chest": { + "scale": { + "0.0": { + "vector": [1, 1, 1] + }, + "1.0": { + "vector": [1.07, 1, 1] + }, + "2.0": { + "vector": [1, 1, 1] + } + } + }, + "All": { + "rotation": { + "vector": [8, 0, 0] + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/src/main/resources/assets/occultism/animations/entity/foliot_worker.animation.json b/src/main/resources/assets/occultism/animations/entity/foliot_worker.animation.json new file mode 100644 index 000000000..48908c5f4 --- /dev/null +++ b/src/main/resources/assets/occultism/animations/entity/foliot_worker.animation.json @@ -0,0 +1,245 @@ +{ + "format_version": "1.8.0", + "animations": { + "idle": { + "loop": true, + "animation_length": 2, + "bones": { + "Torso": { + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, -0.1, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "RARM": { + "rotation": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [4, 0, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "LARM": { + "rotation": { + "0.0": { + "vector": [1, 0, 0] + }, + "1.0": { + "vector": [-2, 0, 0] + }, + "2.0": { + "vector": [1, 0, 0] + } + } + } + } + }, + "walk": { + "loop": true, + "animation_length": 2, + "bones": { + "Torso": { + "rotation": { + "0.0": { + "vector": [0, 0, -1] + }, + "0.5": { + "vector": [0, 0, 2] + }, + "1.0": { + "vector": [0, 0, -1] + }, + "1.5": { + "vector": [0, 0, 2] + }, + "2.0": { + "vector": [0, 0, -1] + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0] + }, + "1.0": { + "vector": [0, -0.1, 0] + }, + "2.0": { + "vector": [0, 0, 0] + } + } + }, + "RARM": { + "rotation": { + "0.0": { + "vector": [31, 0, 0] + }, + "0.25": { + "vector": [-25.75, 0, 0] + }, + "0.5": { + "vector": [31, 0, 0] + }, + "0.75": { + "vector": [-25.75, 0, 0] + }, + "1.0": { + "vector": [31, 0, 0] + }, + "1.25": { + "vector": [-25.75, 0, 0] + }, + "1.5": { + "vector": [31, 0, 0] + }, + "1.75": { + "vector": [-25.75, 0, 0] + }, + "2.0": { + "vector": [31, 0, 0] + } + } + }, + "bone2": { + "rotation": { + "0.0": { + "vector": [27.5, 0, 0] + }, + "0.25": { + "vector": [-32.5, 0, 0] + }, + "0.5": { + "vector": [27.5, 0, 0] + }, + "0.75": { + "vector": [-32.5, 0, 0] + }, + "1.0": { + "vector": [27.5, 0, 0] + }, + "1.25": { + "vector": [-32.5, 0, 0] + }, + "1.5": { + "vector": [27.5, 0, 0] + }, + "1.75": { + "vector": [-32.5, 0, 0] + }, + "2.0": { + "vector": [27.5, 0, 0] + } + } + }, + "bone": { + "rotation": { + "0.0": { + "vector": [-26, 0, 0] + }, + "0.25": { + "vector": [31.5, 0, 0] + }, + "0.5": { + "vector": [-26, 0, 0] + }, + "0.75": { + "vector": [31.5, 0, 0] + }, + "1.0": { + "vector": [-26, 0, 0] + }, + "1.25": { + "vector": [31.5, 0, 0] + }, + "1.5": { + "vector": [-26, 0, 0] + }, + "1.75": { + "vector": [31.5, 0, 0] + }, + "2.0": { + "vector": [-26, 0, 0] + } + } + }, + "FAT": { + "scale": { + "0.0": { + "vector": [1, 1, 1] + }, + "0.25": { + "vector": [1.01, 1, 1] + }, + "0.5": { + "vector": [1, 1, 1] + }, + "0.75": { + "vector": [1.01, 1, 1] + }, + "1.0": { + "vector": [1, 1, 1] + }, + "1.25": { + "vector": [1.01, 1, 1] + }, + "1.5": { + "vector": [1, 1, 1] + }, + "1.75": { + "vector": [1.01, 1, 1] + }, + "2.0": { + "vector": [1, 1, 1] + } + } + }, + "LARM": { + "rotation": { + "0.0": { + "vector": [-22.5, 0, 0] + }, + "0.25": { + "vector": [27.5, 0, 0] + }, + "0.5": { + "vector": [-22.5, 0, 0] + }, + "0.75": { + "vector": [27.5, 0, 0] + }, + "1.0": { + "vector": [-22.5, 0, 0] + }, + "1.25": { + "vector": [27.5, 0, 0] + }, + "1.5": { + "vector": [-22.5, 0, 0] + }, + "1.75": { + "vector": [27.5, 0, 0] + }, + "2.0": { + "vector": [-22.5, 0, 0] + } + }, + "position": { + "vector": [0, 0, 0] + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/src/main/resources/assets/occultism/animations/entity/marid.animation.json b/src/main/resources/assets/occultism/animations/entity/marid_worker.animation.json similarity index 100% rename from src/main/resources/assets/occultism/animations/entity/marid.animation.json rename to src/main/resources/assets/occultism/animations/entity/marid_worker.animation.json diff --git a/src/main/resources/assets/occultism/geo/entity/afrit.geo.json b/src/main/resources/assets/occultism/geo/entity/afrit.geo.json index 85e2a5f76..290e2d134 100644 --- a/src/main/resources/assets/occultism/geo/entity/afrit.geo.json +++ b/src/main/resources/assets/occultism/geo/entity/afrit.geo.json @@ -3,7 +3,7 @@ "minecraft:geometry": [ { "description": { - "identifier": "geometry.unknown", + "identifier": "geometry.afrit", "texture_width": 64, "texture_height": 64, "visible_bounds_width": 2, diff --git a/src/main/resources/assets/occultism/geo/entity/afrit_worker.geo.json b/src/main/resources/assets/occultism/geo/entity/afrit_worker.geo.json new file mode 100644 index 000000000..7bcb98cca --- /dev/null +++ b/src/main/resources/assets/occultism/geo/entity/afrit_worker.geo.json @@ -0,0 +1,133 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.afrit_worker", + "texture_width": 64, + "texture_height": 64, + "visible_bounds_width": 2, + "visible_bounds_height": 3.5, + "visible_bounds_offset": [0, 1.25, 0] + }, + "bones": [ + { + "name": "All", + "pivot": [0, 0, 0] + }, + { + "name": "Torso", + "parent": "All", + "pivot": [0, 22, 0] + }, + { + "name": "Head", + "parent": "Torso", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-2.5, 32, -3], "size": [5, 4, 5], "uv": [32, 0]}, + {"origin": [-3.3, 35, -3.7], "size": [6.6, 3.4, 7.7], "pivot": [0, 38, 0], "rotation": [-15, 0, 0], "uv": [26, 9]} + ] + }, + { + "name": "Lhand", + "parent": "Torso", + "pivot": [5.5, 30, 0], + "cubes": [ + {"origin": [5, 23, -2], "size": [3, 8, 4], "uv": [46, 45]} + ] + }, + { + "name": "bone", + "parent": "Lhand", + "pivot": [6.5, 23.5, 0], + "cubes": [ + {"origin": [5.2, 17.5, -1.8], "size": [2.6, 6, 3.6], "uv": [50, 7]} + ] + }, + { + "name": "Rhand", + "parent": "Torso", + "pivot": [-5.5, 30, 0], + "cubes": [ + {"origin": [-8, 23, -2], "size": [3, 8, 4], "uv": [0, 40]} + ] + }, + { + "name": "bone2", + "parent": "Rhand", + "pivot": [-6.5, 23, 0], + "cubes": [ + {"origin": [-7.8, 17.3, -1.8], "size": [2.6, 5.7, 4], "uv": [49, 16]}, + {"origin": [-6.9, 18, -4], "size": [1.1, 1.4, 5], "uv": [46, 31]}, + {"origin": [-7.3, 17.3, -4.2], "size": [2, 2.9, 0.9], "uv": [0, 22]}, + {"origin": [-6.4, 17.7, -13.9], "size": [0.4, 2, 9.9], "pivot": [-6, 19, 0], "rotation": [4, 0, 0], "uv": [26, 10]}, + {"origin": [-6.3, 17.02341, -16.8341], "size": [0.2, 2.1, 4], "pivot": [-6, 19, -14], "rotation": [-23.5, 0, 0], "uv": [24, 0]} + ] + }, + { + "name": "chest", + "parent": "Torso", + "pivot": [0, 4, 0], + "cubes": [ + {"origin": [-5, 26, -3], "size": [10, 6, 6], "uv": [0, 16]}, + {"origin": [-3, 20, -2.3], "size": [6, 8, 4.7], "uv": [0, 28]} + ] + }, + { + "name": "Tail", + "parent": "All", + "pivot": [0, 0, 0] + }, + { + "name": "1", + "parent": "Tail", + "pivot": [0, 19, 0], + "cubes": [ + {"origin": [-2.6, 15.1, -1.9], "size": [5.3, 8, 4.5], "uv": [16, 36]} + ] + }, + { + "name": "bone3", + "parent": "1", + "pivot": [0, 19, 0], + "cubes": [ + {"origin": [-4.3, 14.9, -4.3], "size": [8.6, 8.2, 8.3], "uv": [0, 0]} + ] + }, + { + "name": "2", + "parent": "Tail", + "pivot": [0, 12, 0], + "cubes": [ + {"origin": [-2, 9, -1.6], "size": [4, 7, 3.6], "uv": [14, 48]} + ] + }, + { + "name": "bone4", + "parent": "2", + "pivot": [0, 12, 0], + "cubes": [ + {"origin": [-3, 8, -3], "size": [6, 8, 5.9], "uv": [27, 23]} + ] + }, + { + "name": "3", + "parent": "Tail", + "pivot": [0, 4, 0], + "cubes": [ + {"origin": [-1, 4, -1], "size": [2, 5, 2], "uv": [0, 0]} + ] + }, + { + "name": "bone5", + "parent": "3", + "pivot": [0, 5, 0], + "cubes": [ + {"origin": [-2, -0.3, -2], "size": [4, 9, 4], "uv": [34, 36]} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/occultism/geo/entity/foliot_worker.geo.json b/src/main/resources/assets/occultism/geo/entity/foliot_worker.geo.json new file mode 100644 index 000000000..f3b76c050 --- /dev/null +++ b/src/main/resources/assets/occultism/geo/entity/foliot_worker.geo.json @@ -0,0 +1,95 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.foliot_worker", + "texture_width": 32, + "texture_height": 32, + "visible_bounds_width": 2, + "visible_bounds_height": 2.5, + "visible_bounds_offset": [0, 0.75, 0] + }, + "bones": [ + { + "name": "All", + "pivot": [0, 0, 0] + }, + { + "name": "bone2", + "parent": "All", + "pivot": [-1.6, 4, 0], + "cubes": [ + {"origin": [-2.9, 1.2, -1], "size": [2.6, 3.1, 2], "uv": [0, 24]}, + {"origin": [-3, 0, -2.3], "size": [2.9, 2, 3.5], "uv": [16, 21]} + ] + }, + { + "name": "bone", + "parent": "All", + "pivot": [1.3, 3.9, 0], + "cubes": [ + {"origin": [0.3, 1.2, -1], "size": [2.6, 3.1, 2], "uv": [23, 10]}, + {"origin": [0.1, 0, -2.3], "size": [2.9, 2, 3.5], "uv": [18, 0]} + ] + }, + { + "name": "Torso", + "parent": "All", + "pivot": [0, 6, 0] + }, + { + "name": "FAT", + "parent": "Torso", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-3, 4, -3], "size": [6, 6, 6], "uv": [0, 0]} + ] + }, + { + "name": "Head", + "parent": "Torso", + "pivot": [0, 11.4, -2], + "cubes": [ + {"origin": [-2, 9, -2], "size": [4, 4, 4], "uv": [11, 13]}, + { + "origin": [-1.5, 12, -1.5], + "size": [0.8, 2, 0.8], + "pivot": [-1, 13, -1.1], + "rotation": [16.93839, -4.46375, 14.33501], + "uv": { + "north": {"uv": [0, 0], "uv_size": [0, 2]}, + "east": {"uv": [0, 0], "uv_size": [0, 2]}, + "south": {"uv": [0, 0], "uv_size": [0, 2]}, + "west": {"uv": [0, 0], "uv_size": [0, 2]}, + "up": {"uv": [0, 0], "uv_size": [0, 0]}, + "down": {"uv": [0, 0], "uv_size": [0, 0]} + } + }, + {"origin": [0.7, 12, -1.5], "size": [0.8, 2, 0.8], "pivot": [1, 13, -1.1], "rotation": [16.93839, 4.46375, -14.33501], "uv": [0, 0]}, + {"origin": [-0.4, 11.3, -2.8], "size": [0.9, 0.6, 1.5], "pivot": [0, 11.4, -2], "rotation": [32.5, 0, 0], "uv": [1, 1]}, + {"origin": [1.6, 11.4, -0.5], "size": [0.4, 2, 1.5], "pivot": [2, 11.7, 0], "rotation": [-23.01667, 16.64946, 8.06026], "uv": [1, 1]}, + {"origin": [-2, 11.4, -0.5], "size": [0.4, 2, 1.5], "pivot": [-2, 11.7, 0], "rotation": [-23.01667, -16.64946, -8.06026], "uv": [1, 1], "mirror": true} + ] + }, + { + "name": "LARM", + "parent": "Torso", + "pivot": [-5, 8.3, -0.3], + "rotation": [-28, 0, 0], + "cubes": [ + {"origin": [-5, 4.08168, -1.07023], "size": [2, 5, 2], "pivot": [-3.5, 8.28168, -0.07023], "rotation": [28.30479, -7.48388, -4.25406], "uv": [8, 21]} + ] + }, + { + "name": "RARM", + "parent": "Torso", + "pivot": [3, 8, 0], + "cubes": [ + {"origin": [3, 4, -1], "size": [2, 5, 2], "uv": [0, 17]} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/occultism/geo/entity/marid.geo.json b/src/main/resources/assets/occultism/geo/entity/marid_worker.geo.json similarity index 99% rename from src/main/resources/assets/occultism/geo/entity/marid.geo.json rename to src/main/resources/assets/occultism/geo/entity/marid_worker.geo.json index 7e923c313..b7d70f355 100644 --- a/src/main/resources/assets/occultism/geo/entity/marid.geo.json +++ b/src/main/resources/assets/occultism/geo/entity/marid_worker.geo.json @@ -3,7 +3,7 @@ "minecraft:geometry": [ { "description": { - "identifier": "geometry.marid", + "identifier": "geometry.marid_worker", "texture_width": 64, "texture_height": 64, "visible_bounds_width": 5, diff --git a/src/main/resources/assets/occultism/textures/entity/afrit_worker.png b/src/main/resources/assets/occultism/textures/entity/afrit_worker.png new file mode 100644 index 0000000000000000000000000000000000000000..aa3f071e161429ee5842bc7572eda61d9e223dc6 GIT binary patch literal 5479 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 E0ThQ3i2wiq literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/occultism/textures/entity/afrit_worker_glowmask.png b/src/main/resources/assets/occultism/textures/entity/afrit_worker_glowmask.png new file mode 100644 index 0000000000000000000000000000000000000000..bcb7eaa1b7b0f489ef450c21933839efd8340a32 GIT binary patch literal 2357 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 N002ovPDHLkV1i3IsIUM4 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/occultism/textures/entity/marid_worker.png b/src/main/resources/assets/occultism/textures/entity/marid_worker.png new file mode 100644 index 0000000000000000000000000000000000000000..e1132c23e44b7e59b145b9481255b8461610e276 GIT binary patch literal 7522 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