chore: init 1.7.10
This commit is contained in:
parent
1076357106
commit
dd380f1e7a
67 changed files with 167 additions and 3027 deletions
128
build.gradle
128
build.gradle
|
@ -1,50 +1,95 @@
|
|||
plugins {
|
||||
id "architectury-plugin" version "3.4-SNAPSHOT"
|
||||
id "dev.architectury.loom" version "1.3-SNAPSHOT" apply false
|
||||
}
|
||||
|
||||
architectury {
|
||||
minecraft = rootProject.minecraft_version
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply plugin: "dev.architectury.loom"
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
name = "forge"
|
||||
url = "https://maven.minecraftforge.net/"
|
||||
}
|
||||
maven {
|
||||
name = "sonatype"
|
||||
url = "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
||||
// The following line declares the yarn mappings you may select this one as well.
|
||||
mappings "net.fabricmc:yarn:1.18.2+build.4:v2"
|
||||
classpath ('com.anatawa12.forge:ForgeGradle:1.2-1.0.+') {
|
||||
changing = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: "java"
|
||||
apply plugin: "architectury-plugin"
|
||||
apply plugin: "maven-publish"
|
||||
apply plugin: 'forge'
|
||||
apply plugin: 'maven-publish'
|
||||
apply from: './gradle/scripts/mixins.gradle'
|
||||
|
||||
base {
|
||||
archivesName = rootProject.archives_base_name
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
|
||||
version = "0.1.0"
|
||||
group= "net.anvilcraft"
|
||||
archivesBaseName = "anvillib-7"
|
||||
|
||||
configurations {
|
||||
embedded
|
||||
implementation.extendsFrom(embedded)
|
||||
}
|
||||
|
||||
minecraft {
|
||||
version = "1.7.10-10.13.4.1614-1.7.10"
|
||||
runDir = "run"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url = "https://maven.tilera.xyz" }
|
||||
maven { url = "https://jitpack.io" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
embedded "net.anvilcraft:jalec:0.1.2"
|
||||
implementation "com.github.tox1cozZ:mixin-booter-legacy:1.1.2"
|
||||
annotationProcessor "com.github.tox1cozZ:mixin-booter-legacy:1.1.2:processor"
|
||||
}
|
||||
|
||||
jar {
|
||||
from (configurations.embedded.collect { it.isDirectory() ? it : zipTree(it) }) {
|
||||
duplicatesStrategy = 'exclude'
|
||||
exclude 'LICENSE.txt', 'META-INF/MANIFSET.MF', 'META-INF/maven/**', 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/services/*.Processor', 'META-INF/versions/**'
|
||||
}
|
||||
}
|
||||
|
||||
version = rootProject.mod_version
|
||||
group = rootProject.maven_group
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
inputs.property "mcversion", project.minecraft.version
|
||||
|
||||
filesMatching('mcmod.info') {
|
||||
expand 'version':project.version, 'mcversion':project.minecraft.version
|
||||
}
|
||||
}
|
||||
|
||||
task deobfJar(type: Jar) {
|
||||
from sourceSets.main.output
|
||||
classifier = 'deobf'
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
from sourceSets.main.allSource
|
||||
classifier = 'sources'
|
||||
}
|
||||
|
||||
publishing {
|
||||
tasks.publish.dependsOn 'build'
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
artifactId = project.archivesBaseName
|
||||
|
||||
artifact deobfJar
|
||||
artifact sourcesJar
|
||||
artifact jar
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url "https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/" }
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.encoding = "UTF-8"
|
||||
options.release = 17
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
if (project.hasProperty("mvnURL")) {
|
||||
if (project.hasProperty('mvnURL')) {
|
||||
maven {
|
||||
credentials {
|
||||
username findProperty("mvnUsername")
|
||||
|
@ -52,8 +97,9 @@ allprojects {
|
|||
}
|
||||
url = findProperty("mvnURL")
|
||||
}
|
||||
}
|
||||
mavenLocal()
|
||||
}
|
||||
else {
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
architectury {
|
||||
common(rootProject.enabled_platforms.split(","))
|
||||
}
|
||||
|
||||
loom {
|
||||
accessWidenerPath = file("src/main/resources/anvillib.accesswidener")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
|
||||
// Do NOT use other classes from fabric loader
|
||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||
modImplementation "software.bernie.geckolib:geckolib-fabric-1.18:3.0.80"
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenCommon(MavenPublication) {
|
||||
artifactId = rootProject.archives_base_name
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package net.anvilcraft.anvillib;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.anvilcraft.anvillib.cosmetics.ClientEventHandler;
|
||||
import net.anvilcraft.anvillib.event.Bus;
|
||||
import software.bernie.geckolib3.GeckoLib;
|
||||
|
||||
public class AnvilLib {
|
||||
public static final String MODID = "anvillib";
|
||||
public static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
public static void initialize() {
|
||||
GeckoLib.initialize();
|
||||
}
|
||||
|
||||
public static void initializeClient() {
|
||||
Bus.MAIN.register(new ClientEventHandler());
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package net.anvilcraft.anvillib;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.tag.TagKey;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
public class Util {
|
||||
public static ItemStack stackFromRegistry(Identifier id) {
|
||||
if (Registry.ITEM.containsId(id)) {
|
||||
return new ItemStack(Registry.ITEM.get(id));
|
||||
} else if (Registry.BLOCK.containsId(id)) {
|
||||
return new ItemStack(Registry.BLOCK.get(id));
|
||||
} else {
|
||||
throw new IllegalArgumentException("No block or item with ID " + id + "!");
|
||||
}
|
||||
}
|
||||
|
||||
public static Ingredient ingredientFromString(String s) {
|
||||
if (s.charAt(0) == '#')
|
||||
return Ingredient.fromTag(
|
||||
TagKey.of(Registry.ITEM_KEY, new Identifier(s.substring(1)))
|
||||
);
|
||||
|
||||
return Ingredient.ofStacks(stackFromRegistry(new Identifier(s)));
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.Objects;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.anvilcraft.anvillib.AnvilLib;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.RemoteCosmeticProvider;
|
||||
import net.anvilcraft.anvillib.event.AddEntityRenderLayersEvent;
|
||||
import net.anvilcraft.anvillib.event.Bus;
|
||||
import net.anvilcraft.anvillib.event.IEventBusRegisterable;
|
||||
import net.minecraft.client.render.entity.EntityRenderer;
|
||||
import net.minecraft.client.render.entity.PlayerEntityRenderer;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
||||
public class ClientEventHandler implements IEventBusRegisterable {
|
||||
private void onAddLayers(AddEntityRenderLayersEvent ev) {
|
||||
for (Entry<String, EntityRenderer<? extends PlayerEntity>> skin :
|
||||
ev.skinMap().entrySet())
|
||||
if (skin.getValue() instanceof PlayerEntityRenderer render)
|
||||
render.addFeature(new CosmeticFeatureRenderer(render, skin.getKey()));
|
||||
}
|
||||
|
||||
public static void registerRemoteCosmetics(File assetsCache) {
|
||||
File cacheDir = new File(Objects.requireNonNull(assetsCache), "anvillib");
|
||||
try {
|
||||
URI playerBase = new URI("https://api.tilera.xyz/anvillib/data/players/");
|
||||
URI cosmeticBase = new URI("https://api.tilera.xyz/anvillib/data/cosmetics/");
|
||||
URI capeBase = new URI("https://api.tilera.xyz/anvillib/data/capes/");
|
||||
CosmeticsManager.registerProvider(
|
||||
new RemoteCosmeticProvider(playerBase, cosmeticBase, capeBase, cacheDir)
|
||||
);
|
||||
} catch (Exception e) {
|
||||
AnvilLib.LOGGER.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerEventHandlers(Bus bus) {
|
||||
bus.register(AddEntityRenderLayersEvent.class, this::onAddLayers);
|
||||
}
|
||||
}
|
|
@ -1,453 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.client.render.OverlayTexture;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.entity.model.BipedEntityModel;
|
||||
import net.minecraft.client.render.entity.model.EntityModelLayers;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Matrix4f;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Vec3f;
|
||||
import net.minecraft.util.math.Vector4f;
|
||||
import software.bernie.geckolib3.core.IAnimatable;
|
||||
import software.bernie.geckolib3.core.IAnimatableModel;
|
||||
import software.bernie.geckolib3.core.controller.AnimationController;
|
||||
import software.bernie.geckolib3.core.controller.AnimationController.ModelFetcher;
|
||||
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
|
||||
import software.bernie.geckolib3.core.processor.IBone;
|
||||
import software.bernie.geckolib3.core.util.Color;
|
||||
import software.bernie.geckolib3.geo.render.built.GeoBone;
|
||||
import software.bernie.geckolib3.geo.render.built.GeoModel;
|
||||
import software.bernie.geckolib3.geo.render.built.GeoQuad;
|
||||
import software.bernie.geckolib3.geo.render.built.GeoVertex;
|
||||
import software.bernie.geckolib3.model.AnimatedGeoModel;
|
||||
import software.bernie.geckolib3.renderers.geo.IGeoRenderer;
|
||||
import software.bernie.geckolib3.util.EModelRenderCycle;
|
||||
import software.bernie.geckolib3.util.GeoUtils;
|
||||
import software.bernie.geckolib3.util.IRenderCycle;
|
||||
import software.bernie.geckolib3.util.RenderUtils;
|
||||
|
||||
public class CosmeticArmorRenderer extends BipedEntityModel<PlayerEntity>
|
||||
implements IGeoRenderer<CosmeticItem>, ModelFetcher<CosmeticItem> {
|
||||
protected CosmeticItem currentArmorItem;
|
||||
protected LivingEntity entityLiving;
|
||||
protected float widthScale = 1;
|
||||
protected float heightScale = 1;
|
||||
protected Matrix4f dispatchedMat = new Matrix4f();
|
||||
protected Matrix4f renderEarlyMat = new Matrix4f();
|
||||
protected int currentFrame = 0;
|
||||
|
||||
public String headBone = null;
|
||||
public String bodyBone = null;
|
||||
public String rightArmBone = null;
|
||||
public String leftArmBone = null;
|
||||
public String rightLegBone = null;
|
||||
public String leftLegBone = null;
|
||||
|
||||
private final AnimatedGeoModel<CosmeticItem> modelProvider;
|
||||
|
||||
protected VertexConsumerProvider rtb = null;
|
||||
|
||||
private IRenderCycle currentModelRenderCycle = EModelRenderCycle.INITIAL;
|
||||
|
||||
{ AnimationController.addModelFetcher(this); }
|
||||
|
||||
@Override
|
||||
public IAnimatableModel<CosmeticItem> apply(IAnimatable t) {
|
||||
if (t instanceof CosmeticItem)
|
||||
return this.getGeoModelProvider();
|
||||
return null;
|
||||
}
|
||||
|
||||
public CosmeticArmorRenderer() {
|
||||
super(MinecraftClient.getInstance().getEntityModelLoader().getModelPart(
|
||||
EntityModelLayers.PLAYER_INNER_ARMOR
|
||||
));
|
||||
|
||||
this.modelProvider = new CosmeticModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
MatrixStack poseStack,
|
||||
VertexConsumer buffer,
|
||||
int packedLight,
|
||||
int packedOverlay,
|
||||
float red,
|
||||
float green,
|
||||
float blue,
|
||||
float alpha
|
||||
) {
|
||||
this.render(0, poseStack, buffer, packedLight);
|
||||
}
|
||||
|
||||
public void render(
|
||||
float partialTick, MatrixStack poseStack, VertexConsumer buffer, int packedLight
|
||||
) {
|
||||
GeoModel model = this.modelProvider.getModel(
|
||||
this.modelProvider.getModelLocation(this.currentArmorItem)
|
||||
);
|
||||
AnimationEvent<CosmeticItem> animationEvent = new AnimationEvent<>(
|
||||
this.currentArmorItem,
|
||||
0,
|
||||
0,
|
||||
MinecraftClient.getInstance().getTickDelta(),
|
||||
false, // can also be getLastFrameDuration()
|
||||
Arrays.asList(this.entityLiving)
|
||||
);
|
||||
|
||||
poseStack.push();
|
||||
poseStack.translate(0, 24 / 16F, 0);
|
||||
poseStack.scale(-1, -1, 1);
|
||||
|
||||
double currentTick = entityLiving.age / this.getCurrentCosmetic().getFrameTime();
|
||||
currentFrame
|
||||
= ((int) (currentTick * 1.0F)) % this.getCurrentCosmetic().getTotalFrames();
|
||||
;
|
||||
|
||||
//this.dispatchedMat = poseStack.last().pose().copy();
|
||||
this.dispatchedMat = poseStack.peek().getPositionMatrix().copy();
|
||||
|
||||
this.modelProvider.setCustomAnimations(
|
||||
this.currentArmorItem, getInstanceId(this.currentArmorItem), animationEvent
|
||||
);
|
||||
setCurrentModelRenderCycle(EModelRenderCycle.INITIAL);
|
||||
fitToBiped();
|
||||
RenderSystem.setShaderTexture(0, getTextureLocation(this.currentArmorItem));
|
||||
|
||||
Color renderColor = getRenderColor(
|
||||
this.currentArmorItem, partialTick, poseStack, null, buffer, packedLight
|
||||
);
|
||||
RenderLayer renderType = getRenderType(
|
||||
this.currentArmorItem,
|
||||
partialTick,
|
||||
poseStack,
|
||||
null,
|
||||
buffer,
|
||||
packedLight,
|
||||
getTextureLocation(this.currentArmorItem)
|
||||
);
|
||||
|
||||
render(
|
||||
model,
|
||||
this.currentArmorItem,
|
||||
partialTick,
|
||||
renderType,
|
||||
poseStack,
|
||||
null,
|
||||
buffer,
|
||||
packedLight,
|
||||
OverlayTexture.DEFAULT_UV,
|
||||
renderColor.getRed() / 255f,
|
||||
renderColor.getGreen() / 255f,
|
||||
renderColor.getBlue() / 255f,
|
||||
renderColor.getAlpha() / 255f
|
||||
);
|
||||
|
||||
//if (ModList.get().isLoaded("patchouli"))
|
||||
// PatchouliCompat.patchouliLoaded(poseStack);
|
||||
|
||||
poseStack.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderEarly(
|
||||
CosmeticItem animatable,
|
||||
MatrixStack poseStack,
|
||||
float partialTick,
|
||||
VertexConsumerProvider bufferSource,
|
||||
VertexConsumer buffer,
|
||||
int packedLight,
|
||||
int packedOverlay,
|
||||
float red,
|
||||
float green,
|
||||
float blue,
|
||||
float alpha
|
||||
) {
|
||||
//this.renderEarlyMat = poseStack.last().pose().copy();
|
||||
this.renderEarlyMat = poseStack.peek().getPositionMatrix().copy();
|
||||
this.currentArmorItem = animatable;
|
||||
|
||||
IGeoRenderer.super.renderEarly(
|
||||
animatable,
|
||||
poseStack,
|
||||
partialTick,
|
||||
bufferSource,
|
||||
buffer,
|
||||
packedLight,
|
||||
packedOverlay,
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
alpha
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderRecursively(
|
||||
GeoBone bone,
|
||||
MatrixStack poseStack,
|
||||
VertexConsumer buffer,
|
||||
int packedLight,
|
||||
int packedOverlay,
|
||||
float red,
|
||||
float green,
|
||||
float blue,
|
||||
float alpha
|
||||
) {
|
||||
if (bone.isTrackingXform()) {
|
||||
//Matrix4f poseState = poseStack.last().pose();
|
||||
Matrix4f poseState = poseStack.peek().getPositionMatrix();
|
||||
Vec3d renderOffset = getRenderOffset(this.currentArmorItem, 1);
|
||||
Matrix4f localMatrix
|
||||
= RenderUtils.invertAndMultiplyMatrices(poseState, this.dispatchedMat);
|
||||
|
||||
bone.setModelSpaceXform(
|
||||
RenderUtils.invertAndMultiplyMatrices(poseState, this.renderEarlyMat)
|
||||
);
|
||||
//localMatrix.translate(new Vec3f(renderOffset));
|
||||
localMatrix.addToLastColumn(new Vec3f(renderOffset));
|
||||
bone.setLocalSpaceXform(localMatrix);
|
||||
}
|
||||
|
||||
IGeoRenderer.super.renderRecursively(
|
||||
bone, poseStack, buffer, packedLight, packedOverlay, red, green, blue, alpha
|
||||
);
|
||||
}
|
||||
|
||||
public Vec3d getRenderOffset(CosmeticItem entity, float partialTick) {
|
||||
return Vec3d.ZERO;
|
||||
}
|
||||
|
||||
protected void fitToBiped() {
|
||||
if (this.headBone != null) {
|
||||
IBone headBone = this.modelProvider.getBone(this.headBone);
|
||||
|
||||
GeoUtils.copyRotations(this.head, headBone);
|
||||
headBone.setPositionX(this.head.pivotX);
|
||||
headBone.setPositionY(-this.head.pivotY);
|
||||
headBone.setPositionZ(this.head.pivotZ);
|
||||
}
|
||||
|
||||
if (this.bodyBone != null) {
|
||||
IBone bodyBone = this.modelProvider.getBone(this.bodyBone);
|
||||
|
||||
GeoUtils.copyRotations(this.body, bodyBone);
|
||||
bodyBone.setPositionX(this.body.pivotX);
|
||||
bodyBone.setPositionY(-this.body.pivotY);
|
||||
bodyBone.setPositionZ(this.body.pivotZ);
|
||||
}
|
||||
|
||||
if (this.rightArmBone != null) {
|
||||
IBone rightArmBone = this.modelProvider.getBone(this.rightArmBone);
|
||||
|
||||
GeoUtils.copyRotations(this.rightArm, rightArmBone);
|
||||
rightArmBone.setPositionX(this.rightArm.pivotX + 5);
|
||||
rightArmBone.setPositionY(2 - this.rightArm.pivotY);
|
||||
rightArmBone.setPositionZ(this.rightArm.pivotZ);
|
||||
}
|
||||
|
||||
if (this.leftArmBone != null) {
|
||||
IBone leftArmBone = this.modelProvider.getBone(this.leftArmBone);
|
||||
|
||||
GeoUtils.copyRotations(this.leftArm, leftArmBone);
|
||||
leftArmBone.setPositionX(this.leftArm.pivotX - 5);
|
||||
leftArmBone.setPositionY(2 - this.leftArm.pivotY);
|
||||
leftArmBone.setPositionZ(this.leftArm.pivotZ);
|
||||
}
|
||||
|
||||
if (this.rightLegBone != null) {
|
||||
IBone rightLegBone = this.modelProvider.getBone(this.rightLegBone);
|
||||
|
||||
GeoUtils.copyRotations(this.rightLeg, rightLegBone);
|
||||
rightLegBone.setPositionX(this.rightLeg.pivotX + 2);
|
||||
rightLegBone.setPositionY(12 - this.rightLeg.pivotY);
|
||||
rightLegBone.setPositionZ(this.rightLeg.pivotZ);
|
||||
}
|
||||
|
||||
if (this.leftLegBone != null) {
|
||||
IBone leftLegBone = this.modelProvider.getBone(this.leftLegBone);
|
||||
|
||||
GeoUtils.copyRotations(this.leftLeg, leftLegBone);
|
||||
leftLegBone.setPositionX(this.leftLeg.pivotX - 2);
|
||||
leftLegBone.setPositionY(12 - this.leftLeg.pivotY);
|
||||
leftLegBone.setPositionZ(this.leftLeg.pivotZ);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnimatedGeoModel<CosmeticItem> getGeoModelProvider() {
|
||||
return this.modelProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IRenderCycle getCurrentModelRenderCycle() {
|
||||
return this.currentModelRenderCycle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentModelRenderCycle(IRenderCycle currentModelRenderCycle) {
|
||||
this.currentModelRenderCycle = currentModelRenderCycle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getWidthScale(CosmeticItem animatable) {
|
||||
return this.widthScale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHeightScale(CosmeticItem entity) {
|
||||
return this.heightScale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getTextureLocation(CosmeticItem animatable) {
|
||||
return this.modelProvider.getTextureLocation(animatable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Everything after this point needs to be called every frame before rendering
|
||||
*/
|
||||
public CosmeticArmorRenderer setCurrentItem(LivingEntity entity, CosmeticItem item) {
|
||||
this.entityLiving = entity;
|
||||
this.currentArmorItem = item;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public final CosmeticArmorRenderer
|
||||
applyEntityStats(BipedEntityModel<AbstractClientPlayerEntity> defaultArmor) {
|
||||
this.child = defaultArmor.child;
|
||||
this.sneaking = defaultArmor.sneaking;
|
||||
this.riding = defaultArmor.riding;
|
||||
this.rightArmPose = defaultArmor.rightArmPose;
|
||||
this.leftArmPose = defaultArmor.leftArmPose;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void filterBones() {
|
||||
this.headBone = getCurrentCosmetic().getHead();
|
||||
this.bodyBone = getCurrentCosmetic().getBody();
|
||||
this.leftArmBone = getCurrentCosmetic().getLeftArm();
|
||||
this.rightArmBone = getCurrentCosmetic().getRightArm();
|
||||
this.leftLegBone = getCurrentCosmetic().getLeftLeg();
|
||||
this.rightLegBone = getCurrentCosmetic().getRightLeg();
|
||||
|
||||
getGeoModelProvider().getModel(getCurrentCosmetic().getModelLocation());
|
||||
|
||||
this.setBoneVisibility(this.headBone, getCurrentCosmetic().getHead() != null);
|
||||
this.setBoneVisibility(this.bodyBone, getCurrentCosmetic().getBody() != null);
|
||||
this.setBoneVisibility(
|
||||
this.leftArmBone, getCurrentCosmetic().getLeftArm() != null
|
||||
);
|
||||
this.setBoneVisibility(
|
||||
this.rightArmBone, getCurrentCosmetic().getRightArm() != null
|
||||
);
|
||||
this.setBoneVisibility(
|
||||
this.leftLegBone, getCurrentCosmetic().getLeftLeg() != null
|
||||
);
|
||||
this.setBoneVisibility(
|
||||
this.rightLegBone, getCurrentCosmetic().getRightLeg() != null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a specific bone (and its child-bones) to visible or not
|
||||
* @param boneName The name of the bone
|
||||
* @param isVisible Whether the bone should be visible
|
||||
*/
|
||||
protected void setBoneVisibility(String boneName, boolean isVisible) {
|
||||
if (boneName == null)
|
||||
return;
|
||||
|
||||
this.modelProvider.getBone(boneName).setHidden(!isVisible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use {@link CosmeticArmorRenderer#setBoneVisibility(String, boolean)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
protected IBone getAndHideBone(String boneName) {
|
||||
setBoneVisibility(boneName, false);
|
||||
|
||||
return this.modelProvider.getBone(boneName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInstanceId(CosmeticItem animatable) {
|
||||
return Objects.hash(
|
||||
this.currentArmorItem.getCosmetic().getID(), this.entityLiving.getUuid()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentRTB(VertexConsumerProvider bufferSource) {
|
||||
this.rtb = bufferSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumerProvider getCurrentRTB() {
|
||||
return this.rtb;
|
||||
}
|
||||
|
||||
public ICosmetic getCurrentCosmetic() {
|
||||
return this.currentArmorItem.getCosmetic();
|
||||
}
|
||||
|
||||
public float calcVOffset(float v) {
|
||||
float totalFrames = (float) this.getCurrentCosmetic().getTotalFrames();
|
||||
float currentTextureOffset = (float) currentFrame / totalFrames;
|
||||
return (v / totalFrames) + currentTextureOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createVerticesOfQuad(
|
||||
GeoQuad quad,
|
||||
Matrix4f poseState,
|
||||
Vec3f normal,
|
||||
VertexConsumer buffer,
|
||||
int packedLight,
|
||||
int packedOverlay,
|
||||
float red,
|
||||
float green,
|
||||
float blue,
|
||||
float alpha
|
||||
) {
|
||||
for (GeoVertex vertex : quad.vertices) {
|
||||
Vector4f vector4f = new Vector4f(
|
||||
vertex.position.getX(), vertex.position.getY(), vertex.position.getZ(), 1
|
||||
);
|
||||
|
||||
vector4f.transform(poseState);
|
||||
buffer.vertex(
|
||||
vector4f.getX(),
|
||||
vector4f.getY(),
|
||||
vector4f.getZ(),
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
alpha,
|
||||
vertex.textureU,
|
||||
calcVOffset(vertex.textureV),
|
||||
packedOverlay,
|
||||
packedLight,
|
||||
normal.getX(),
|
||||
normal.getY(),
|
||||
normal.getZ()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.model.ModelPart;
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.entity.PlayerEntityRenderer;
|
||||
import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer;
|
||||
import net.minecraft.client.render.entity.model.BipedEntityModel;
|
||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||
import net.minecraft.client.render.item.ItemRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
public class CosmeticFeatureRenderer extends ArmorFeatureRenderer<
|
||||
AbstractClientPlayerEntity,
|
||||
PlayerEntityModel<AbstractClientPlayerEntity>,
|
||||
BipedEntityModel<AbstractClientPlayerEntity>> {
|
||||
private static final Map<ICosmetic, CosmeticItem> modelCache = new HashMap<>();
|
||||
private static CosmeticArmorRenderer cosmeticRenderer = null;
|
||||
PlayerEntityRenderer renderer;
|
||||
String skin;
|
||||
|
||||
public CosmeticFeatureRenderer(PlayerEntityRenderer renderer, String skin) {
|
||||
super(renderer, null, null);
|
||||
this.renderer = renderer;
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
MatrixStack matrix,
|
||||
VertexConsumerProvider buffer,
|
||||
int light,
|
||||
AbstractClientPlayerEntity player,
|
||||
float limbSwing,
|
||||
float limbSwingAmount,
|
||||
float partialTicks,
|
||||
float ageInTicks,
|
||||
float netHeadYaw,
|
||||
float headPitch
|
||||
) {
|
||||
if (player.isInvisible())
|
||||
return;
|
||||
for (ICosmetic c : CosmeticsManager.getCosmeticsForPlayer(player.getUuid())) {
|
||||
if (c.readyToRender())
|
||||
this.renderCosmetic(matrix, buffer, player, light, c, partialTicks);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderCosmetic(
|
||||
MatrixStack matrix,
|
||||
VertexConsumerProvider buffer,
|
||||
AbstractClientPlayerEntity player,
|
||||
int light,
|
||||
ICosmetic cosmetic,
|
||||
float partialTicks
|
||||
) {
|
||||
if (cosmeticRenderer == null)
|
||||
cosmeticRenderer = new CosmeticArmorRenderer();
|
||||
if (!modelCache.containsKey(cosmetic))
|
||||
modelCache.put(cosmetic, new CosmeticItem(cosmetic));
|
||||
CosmeticItem item = modelCache.get(cosmetic);
|
||||
copyRotations(this.renderer.getModel(), cosmeticRenderer);
|
||||
cosmeticRenderer.applyEntityStats(this.renderer.getModel());
|
||||
cosmeticRenderer.setCurrentItem(player, item);
|
||||
cosmeticRenderer.filterBones();
|
||||
|
||||
VertexConsumer vertex = ItemRenderer.getArmorGlintConsumer(
|
||||
buffer,
|
||||
RenderLayer.getArmorCutoutNoCull(cosmetic.getTextureLocation()),
|
||||
false,
|
||||
false
|
||||
);
|
||||
cosmeticRenderer.render(partialTicks, matrix, vertex, light);
|
||||
}
|
||||
|
||||
private static void copyRotations(BipedEntityModel<?> from, BipedEntityModel<?> to) {
|
||||
copyRotations(from.head, to.head);
|
||||
copyRotations(from.hat, to.hat);
|
||||
copyRotations(from.body, to.body);
|
||||
copyRotations(from.leftArm, to.leftArm);
|
||||
copyRotations(from.rightArm, to.rightArm);
|
||||
copyRotations(from.rightLeg, to.rightLeg);
|
||||
copyRotations(from.leftLeg, to.leftLeg);
|
||||
}
|
||||
|
||||
private static void copyRotations(ModelPart from, ModelPart to) {
|
||||
to.copyTransform(from);
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics;
|
||||
|
||||
import software.bernie.geckolib3.core.IAnimatable;
|
||||
import software.bernie.geckolib3.core.PlayState;
|
||||
import software.bernie.geckolib3.core.builder.AnimationBuilder;
|
||||
import software.bernie.geckolib3.core.builder.ILoopType.EDefaultLoopTypes;
|
||||
import software.bernie.geckolib3.core.controller.AnimationController;
|
||||
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
|
||||
import software.bernie.geckolib3.core.manager.AnimationData;
|
||||
import software.bernie.geckolib3.core.manager.AnimationFactory;
|
||||
import software.bernie.geckolib3.util.GeckoLibUtil;
|
||||
|
||||
public class CosmeticItem implements IAnimatable {
|
||||
private ICosmetic cosmetic = null;
|
||||
private AnimationBuilder animationBuilder = new AnimationBuilder();
|
||||
|
||||
public CosmeticItem(ICosmetic cosmetic) {
|
||||
this.cosmetic = cosmetic;
|
||||
if (cosmetic.getIdleAnimationName() != null) {
|
||||
this.animationBuilder.addAnimation(
|
||||
cosmetic.getIdleAnimationName(), EDefaultLoopTypes.LOOP
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private <P extends IAnimatable> PlayState predicate(AnimationEvent<P> event) {
|
||||
event.getController().transitionLengthTicks = 0;
|
||||
event.getController().setAnimation(animationBuilder);
|
||||
return PlayState.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerControllers(AnimationData data) {
|
||||
data.addAnimationController(
|
||||
new AnimationController<>(this, "controller", 20, this::predicate)
|
||||
);
|
||||
}
|
||||
|
||||
private final AnimationFactory factory = GeckoLibUtil.createFactory(this);
|
||||
|
||||
@Override
|
||||
public AnimationFactory getFactory() {
|
||||
return this.factory;
|
||||
}
|
||||
|
||||
public ICosmetic getCosmetic() {
|
||||
return this.cosmetic;
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics;
|
||||
|
||||
import net.anvilcraft.anvillib.mixin.accessor.AnimatedGeoModelAccessor;
|
||||
import net.minecraft.util.Identifier;
|
||||
import software.bernie.geckolib3.core.IAnimatable;
|
||||
import software.bernie.geckolib3.core.builder.Animation;
|
||||
import software.bernie.geckolib3.file.AnimationFile;
|
||||
import software.bernie.geckolib3.geo.exception.GeckoLibException;
|
||||
import software.bernie.geckolib3.geo.render.built.GeoBone;
|
||||
import software.bernie.geckolib3.geo.render.built.GeoModel;
|
||||
import software.bernie.geckolib3.model.AnimatedGeoModel;
|
||||
import software.bernie.geckolib3.resource.GeckoLibCache;
|
||||
|
||||
public class CosmeticModel extends AnimatedGeoModel<CosmeticItem> {
|
||||
@Override
|
||||
public Identifier getAnimationFileLocation(CosmeticItem animatable) {
|
||||
return animatable.getCosmetic().getAnimationFileLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getModelLocation(CosmeticItem animatable) {
|
||||
return animatable.getCosmetic().getModelLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getTextureLocation(CosmeticItem animatable) {
|
||||
return animatable.getCosmetic().getTextureLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animation getAnimation(String name, IAnimatable animatable) {
|
||||
Identifier location
|
||||
= ((CosmeticItem) animatable).getCosmetic().getAnimationFileLocation();
|
||||
AnimationFile animation = CosmeticsManager.getAnimations(location);
|
||||
if (animation == null) {
|
||||
animation = GeckoLibCache.getInstance().getAnimations().get(location);
|
||||
}
|
||||
|
||||
if (animation == null) {
|
||||
throw new GeckoLibException(
|
||||
location, "Could not find animation file. Please double check name."
|
||||
);
|
||||
}
|
||||
|
||||
return animation.getAnimation(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeoModel getModel(Identifier location) {
|
||||
GeoModel model = CosmeticsManager.getModel(location);
|
||||
if (model == null) {
|
||||
model = GeckoLibCache.getInstance().getGeoModels().get(location);
|
||||
}
|
||||
|
||||
AnimatedGeoModelAccessor accessor = (AnimatedGeoModelAccessor) this;
|
||||
if (model != accessor.getCurrentModel()) {
|
||||
accessor.getAnimationProcessor().clearModelRendererList();
|
||||
accessor.setCurrentModel(model);
|
||||
|
||||
for (GeoBone bone : model.topLevelBones) {
|
||||
registerBone(bone);
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import software.bernie.geckolib3.geo.render.built.GeoBone;
|
||||
import software.bernie.geckolib3.geo.render.built.GeoModel;
|
||||
|
||||
public class CosmeticParts {
|
||||
public boolean head = false;
|
||||
public boolean body = false;
|
||||
public boolean leftArm = false;
|
||||
public boolean leftLeg = false;
|
||||
public boolean rightArm = false;
|
||||
public boolean rightLeg = false;
|
||||
|
||||
public final String headName = "head";
|
||||
public final String bodyName = "body";
|
||||
public final String leftArmName = "arm_left";
|
||||
public final String leftLegName = "leg_left";
|
||||
public final String rightArmName = "arm_right";
|
||||
public final String rightLegName = "leg_right";
|
||||
|
||||
public CosmeticParts() {}
|
||||
|
||||
public CosmeticParts(GeoModel model) {
|
||||
Optional<GeoBone> maybeRoot = model.getBone("root");
|
||||
if (maybeRoot.isEmpty())
|
||||
return;
|
||||
GeoBone root = maybeRoot.get();
|
||||
for (GeoBone bone : root.childBones) {
|
||||
switch (bone.name) {
|
||||
case headName:
|
||||
this.head = true;
|
||||
break;
|
||||
case bodyName:
|
||||
this.body = true;
|
||||
break;
|
||||
case leftArmName:
|
||||
this.leftArm = true;
|
||||
break;
|
||||
case leftLegName:
|
||||
this.leftLeg = true;
|
||||
break;
|
||||
case rightArmName:
|
||||
this.rightArm = true;
|
||||
break;
|
||||
case rightLegName:
|
||||
this.rightLeg = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
import software.bernie.geckolib3.file.AnimationFile;
|
||||
import software.bernie.geckolib3.geo.render.built.GeoModel;
|
||||
|
||||
public class CosmeticsManager {
|
||||
private static List<ICosmeticProvider> providers = new ArrayList<>();
|
||||
private static Map<UUID, List<ICosmetic>> cosmeticCache = new HashMap<>();
|
||||
private static Map<UUID, Identifier> capeCache = new HashMap<>();
|
||||
private static Set<UUID> activePlayers = new HashSet<>();
|
||||
private static Map<Identifier, GeoModel> cachedModels = new ConcurrentHashMap<>();
|
||||
private static Map<Identifier, AnimationFile> cachedAnimations
|
||||
= new ConcurrentHashMap<>();
|
||||
|
||||
private static void refresh() {
|
||||
boolean doRefresh = false;
|
||||
for (ICosmeticProvider provider : providers) {
|
||||
doRefresh = doRefresh || provider.requestsRefresh();
|
||||
}
|
||||
if (!doRefresh)
|
||||
return;
|
||||
cosmeticCache.clear();
|
||||
for (UUID uuid : activePlayers) {
|
||||
loadPlayer(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadPlayer(UUID player) {
|
||||
if (cosmeticCache.containsKey(player))
|
||||
return;
|
||||
cosmeticCache.put(player, new ArrayList<>());
|
||||
List<ICosmetic> cosmetics = cosmeticCache.get(player);
|
||||
for (ICosmeticProvider provider : providers) {
|
||||
provider.addCosmetics(player, (cosmetic) -> cosmetics.add(cosmetic));
|
||||
if (!capeCache.containsKey(player)) {
|
||||
Identifier cape = provider.getCape(player);
|
||||
if (cape != null)
|
||||
capeCache.put(player, cape);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerProvider(ICosmeticProvider provider) {
|
||||
providers.add(provider);
|
||||
}
|
||||
|
||||
protected static List<ICosmetic> getCosmeticsForPlayer(UUID uuid) {
|
||||
if (!activePlayers.contains(uuid)) {
|
||||
activePlayers.add(uuid);
|
||||
loadPlayer(uuid);
|
||||
}
|
||||
refresh();
|
||||
return cosmeticCache.get(uuid);
|
||||
}
|
||||
|
||||
public static Identifier getCape(UUID player) {
|
||||
if (!activePlayers.contains(player)) {
|
||||
activePlayers.add(player);
|
||||
loadPlayer(player);
|
||||
}
|
||||
refresh();
|
||||
return capeCache.get(player);
|
||||
}
|
||||
|
||||
protected static GeoModel getModel(Identifier id) {
|
||||
return cachedModels.get(id);
|
||||
}
|
||||
|
||||
protected static AnimationFile getAnimations(Identifier id) {
|
||||
return cachedAnimations.get(id);
|
||||
}
|
||||
|
||||
public static void loadModel(Identifier id, GeoModel model) {
|
||||
cachedModels.put(id, model);
|
||||
}
|
||||
|
||||
public static void loadAnimations(Identifier id, AnimationFile animations) {
|
||||
cachedAnimations.put(id, animations);
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public interface ICosmetic {
|
||||
Identifier getAnimationFileLocation();
|
||||
|
||||
Identifier getModelLocation();
|
||||
|
||||
Identifier getTextureLocation();
|
||||
|
||||
default String getHead() {
|
||||
return null; //head
|
||||
}
|
||||
|
||||
default String getBody() {
|
||||
return null; //body
|
||||
}
|
||||
|
||||
default String getLeftArm() {
|
||||
return null; //arm_left
|
||||
}
|
||||
|
||||
default String getRightArm() {
|
||||
return null; //arm_right
|
||||
}
|
||||
|
||||
default String getLeftLeg() {
|
||||
return null; //leg_left
|
||||
}
|
||||
|
||||
default String getRightLeg() {
|
||||
return null; //leg_right
|
||||
}
|
||||
|
||||
default String getIdleAnimationName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default boolean readyToRender() {
|
||||
return true;
|
||||
}
|
||||
|
||||
Identifier getID();
|
||||
|
||||
default int getTotalFrames() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how many ticks a frame of the animation should take.
|
||||
*/
|
||||
default int getFrameTime() {
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public interface ICosmeticProvider {
|
||||
boolean requestsRefresh();
|
||||
|
||||
void addCosmetics(UUID player, Consumer<ICosmetic> cosmeticAdder);
|
||||
|
||||
default Identifier getCape(UUID player) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote;
|
||||
|
||||
import net.anvilcraft.anvillib.cosmetics.CosmeticsManager;
|
||||
import net.anvilcraft.anvillib.cosmetics.ICosmetic;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.model.AnimationData;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.model.TextureData;
|
||||
import net.anvilcraft.anvillib.cosmetics.CosmeticParts;
|
||||
import net.minecraft.util.Identifier;
|
||||
import software.bernie.geckolib3.file.AnimationFile;
|
||||
import software.bernie.geckolib3.geo.render.built.GeoModel;
|
||||
|
||||
public class RemoteCosmetic implements ICosmetic {
|
||||
private Identifier id;
|
||||
private boolean loadedModel = false;
|
||||
private boolean loadedTexture = false;
|
||||
private boolean loadedAnimations = false;
|
||||
private Identifier modelLocation;
|
||||
private Identifier textureLocation;
|
||||
private Identifier animationsLocation;
|
||||
private CosmeticParts parts = new CosmeticParts();
|
||||
private String idleAnimation = null;
|
||||
private int frameTime = 1;
|
||||
private int frameCount = 1;
|
||||
|
||||
public RemoteCosmetic(String id) {
|
||||
this.id = new Identifier("anvillib", id);
|
||||
this.modelLocation = new Identifier("anvillib", "models/remote/" + id);
|
||||
this.textureLocation = new Identifier("anvillib", "textures/remote/" + id);
|
||||
this.animationsLocation = new Identifier("anvillib", "animations/remote/" + id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getAnimationFileLocation() {
|
||||
return this.animationsLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getModelLocation() {
|
||||
return this.modelLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getTextureLocation() {
|
||||
return this.textureLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getID() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readyToRender() {
|
||||
return this.loadedModel && this.loadedTexture && this.loadedAnimations;
|
||||
}
|
||||
|
||||
public void loadModel(GeoModel model) {
|
||||
CosmeticsManager.loadModel(this.modelLocation, model);
|
||||
this.parts = new CosmeticParts(model);
|
||||
this.loadedModel = true;
|
||||
}
|
||||
|
||||
public void loadTexture(TextureData data) {
|
||||
this.frameCount = data.frameCount;
|
||||
this.frameTime = data.frameTime;
|
||||
this.loadedTexture = true;
|
||||
}
|
||||
|
||||
public void loadAnimations(AnimationFile file, AnimationData data) {
|
||||
if (data == null || file == null) {
|
||||
this.animationsLocation = null;
|
||||
} else {
|
||||
CosmeticsManager.loadAnimations(this.animationsLocation, file);
|
||||
this.idleAnimation = data.idleAnimation;
|
||||
}
|
||||
this.loadedAnimations = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBody() {
|
||||
return this.parts.body ? this.parts.bodyName : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHead() {
|
||||
return this.parts.head ? this.parts.headName : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLeftArm() {
|
||||
return this.parts.leftArm ? this.parts.leftArmName : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLeftLeg() {
|
||||
return this.parts.leftLeg ? this.parts.leftLegName : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRightArm() {
|
||||
return this.parts.rightArm ? this.parts.rightArmName : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRightLeg() {
|
||||
return this.parts.rightLeg ? this.parts.rightLegName : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdleAnimationName() {
|
||||
return this.idleAnimation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalFrames() {
|
||||
return this.frameCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFrameTime() {
|
||||
return this.frameTime;
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.anvilcraft.anvillib.AnvilLib;
|
||||
import net.anvilcraft.anvillib.cosmetics.ICosmetic;
|
||||
import net.anvilcraft.anvillib.cosmetics.ICosmeticProvider;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.model.CosmeticData;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.thread.CapeLoaderThread;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.thread.CosmeticAssetsLoaderThread;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.thread.CosmeticLoaderThread;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.thread.PlayerCosmeticLoaderThread;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.Util;
|
||||
|
||||
public class RemoteCosmeticProvider implements ICosmeticProvider {
|
||||
public static RemoteCosmeticProvider INSTANCE = null;
|
||||
|
||||
public final Map<String, RemoteCosmetic> cosmetics = new ConcurrentHashMap<>();
|
||||
public final Map<UUID, Set<String>> playerCosmetics = new ConcurrentHashMap<>();
|
||||
public final Map<String, Identifier> capes = new ConcurrentHashMap<>();
|
||||
public final Map<UUID, String> playerCapes = new ConcurrentHashMap<>();
|
||||
private final Map<String, Boolean> knownCosmetics = new ConcurrentHashMap<>();
|
||||
private final Map<String, Boolean> knownCapes = new ConcurrentHashMap<>();
|
||||
private boolean dirty = false;
|
||||
|
||||
public final URI playerBase;
|
||||
public final URI cosmeticBase;
|
||||
public final URI capeBase;
|
||||
private final File cacheDir;
|
||||
|
||||
public RemoteCosmeticProvider(
|
||||
URI playerBase, URI cosmeticBase, URI capeBase, File cacheDir
|
||||
) {
|
||||
this.playerBase = playerBase;
|
||||
this.cosmeticBase = cosmeticBase;
|
||||
this.capeBase = capeBase;
|
||||
this.cacheDir = cacheDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requestsRefresh() {
|
||||
return this.dirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCosmetics(UUID player, Consumer<ICosmetic> cosmeticAdder) {
|
||||
this.dirty = false;
|
||||
if (playerCosmetics.containsKey(player)) {
|
||||
for (String id : playerCosmetics.get(player)) {
|
||||
if (!this.cosmetics.containsKey(id)
|
||||
|| !this.cosmetics.get(id).readyToRender())
|
||||
continue;
|
||||
cosmeticAdder.accept(this.cosmetics.get(id));
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
this.loadNewPlayer(player);
|
||||
} catch (MalformedURLException e) {
|
||||
AnvilLib.LOGGER.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getCape(UUID player) {
|
||||
if (!this.playerCapes.containsKey(player))
|
||||
return null;
|
||||
String cape = this.playerCapes.get(player);
|
||||
return this.capes.getOrDefault(cape, null);
|
||||
}
|
||||
|
||||
public void markDirty() {
|
||||
synchronized (this) {
|
||||
this.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void loadNewPlayer(UUID id) throws MalformedURLException {
|
||||
this.playerCosmetics.putIfAbsent(id, new HashSet<>());
|
||||
URI url = playerBase.resolve(id.toString());
|
||||
Util.getMainWorkerExecutor().execute(new PlayerCosmeticLoaderThread(url, this));
|
||||
}
|
||||
|
||||
public void loadCosmetic(String id) throws MalformedURLException {
|
||||
if (this.cosmetics.containsKey(id) || this.knownCosmetics.containsKey(id))
|
||||
return;
|
||||
this.knownCosmetics.put(id, true);
|
||||
URI url = cosmeticBase.resolve(id);
|
||||
Util.getMainWorkerExecutor().execute(new CosmeticLoaderThread(url, this));
|
||||
}
|
||||
|
||||
public void loadAssets(CosmeticData data, RemoteCosmetic cosmetic) {
|
||||
Util.getMainWorkerExecutor().execute(
|
||||
new CosmeticAssetsLoaderThread(cosmetic, data, this.cacheDir, this)
|
||||
);
|
||||
}
|
||||
|
||||
public void loadCape(String id) throws MalformedURLException {
|
||||
if (this.capes.containsKey(id) || this.knownCapes.containsKey(id))
|
||||
return;
|
||||
this.knownCapes.put(id, true);
|
||||
URI url = capeBase.resolve(id);
|
||||
Util.getMainWorkerExecutor().execute(
|
||||
new CapeLoaderThread(id, url, this.cacheDir, this)
|
||||
);
|
||||
}
|
||||
|
||||
public void failCosmeticLoading(String id) {
|
||||
AnvilLib.LOGGER.error("Cosmetic loading failed: {}", id);
|
||||
this.cosmetics.remove(id);
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote.model;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class AnimationData {
|
||||
@Expose
|
||||
public String url;
|
||||
@Expose
|
||||
@SerializedName("idle_animation")
|
||||
public String idleAnimation;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote.model;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
public class CapeData {
|
||||
@Expose
|
||||
public String id;
|
||||
@Expose
|
||||
public String url;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote.model;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class CosmeticData {
|
||||
@Expose
|
||||
public String id;
|
||||
@Expose
|
||||
@SerializedName("model_url")
|
||||
public String modelUrl;
|
||||
@Expose
|
||||
@SerializedName("animation_data")
|
||||
public AnimationData animationData;
|
||||
@Expose
|
||||
@SerializedName("texture_data")
|
||||
public TextureData textureData;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
public class PlayerData {
|
||||
@Expose
|
||||
public UUID uuid;
|
||||
@Expose
|
||||
public List<String> cosmetics;
|
||||
@Expose
|
||||
public String cape;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote.model;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class TextureData {
|
||||
@Expose
|
||||
public String url;
|
||||
|
||||
@Expose
|
||||
@SerializedName("total_frames")
|
||||
public int frameCount;
|
||||
|
||||
@Expose
|
||||
@SerializedName("frame_time")
|
||||
public int frameTime;
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote.thread;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonIOException;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import net.anvilcraft.anvillib.AnvilLib;
|
||||
|
||||
public abstract class AbstractFileDownloaderThread implements Runnable {
|
||||
protected Gson gson = new GsonBuilder().create();
|
||||
protected HttpClient client = HttpClient.newBuilder().build();
|
||||
protected final String version;
|
||||
|
||||
public AbstractFileDownloaderThread(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
protected HttpRequest buildRequest(URI url) {
|
||||
return HttpRequest.newBuilder()
|
||||
.GET()
|
||||
.uri(url)
|
||||
.header("User-Agent", System.getProperty("java.version"))
|
||||
.header("X-AnvilLib-Version", this.version)
|
||||
.header("X-Minecraft-Version", "1.18.2")
|
||||
.build();
|
||||
}
|
||||
|
||||
public InputStream getStreamForURL(URI url) {
|
||||
HttpRequest req = this.buildRequest(url);
|
||||
InputStream is = null;
|
||||
try {
|
||||
HttpResponse<InputStream> res
|
||||
= client.send(req, HttpResponse.BodyHandlers.ofInputStream());
|
||||
if (res.statusCode() == 200) {
|
||||
is = res.body();
|
||||
} else if (res.statusCode() != 404) {
|
||||
AnvilLib.LOGGER.error("Unexpected status code: {}", res.statusCode());
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
AnvilLib.LOGGER.error(e);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
public String getStringForURL(URI url) {
|
||||
HttpRequest req = this.buildRequest(url);
|
||||
String is = null;
|
||||
try {
|
||||
HttpResponse<String> res
|
||||
= client.send(req, HttpResponse.BodyHandlers.ofString());
|
||||
if (res.statusCode() == 200) {
|
||||
is = res.body();
|
||||
} else if (res.statusCode() != 404) {
|
||||
AnvilLib.LOGGER.error("Unexpected status code: {}", res.statusCode());
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
AnvilLib.LOGGER.error(e);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
public <T> T loadJson(URI url, Class<T> type) throws IOException {
|
||||
InputStream stream = this.getStreamForURL(url);
|
||||
if (stream == null)
|
||||
return null;
|
||||
try {
|
||||
T json = this.gson.fromJson(new InputStreamReader(stream), type);
|
||||
return json;
|
||||
} catch (JsonSyntaxException | JsonIOException e) {
|
||||
throw new IOException(e);
|
||||
} finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote.thread;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import com.google.common.hash.Hashing;
|
||||
|
||||
import net.anvilcraft.anvillib.AnvilLib;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.RemoteCosmeticProvider;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.model.CapeData;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.texture.AbstractTexture;
|
||||
import net.minecraft.client.texture.MissingSprite;
|
||||
import net.minecraft.client.texture.PlayerSkinTexture;
|
||||
import net.minecraft.client.texture.TextureManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class CapeLoaderThread extends AbstractFileDownloaderThread {
|
||||
private String id;
|
||||
private File cacheDir;
|
||||
private URI url;
|
||||
private RemoteCosmeticProvider provider;
|
||||
private TextureManager textureManager
|
||||
= MinecraftClient.getInstance().getTextureManager();
|
||||
|
||||
public CapeLoaderThread(
|
||||
String id, URI url, File cacheDir, RemoteCosmeticProvider provider
|
||||
) {
|
||||
super("0.2.0");
|
||||
this.id = id;
|
||||
this.url = url;
|
||||
this.cacheDir = cacheDir;
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void run() {
|
||||
CapeData data = null;
|
||||
try {
|
||||
data = this.loadJson(url, CapeData.class);
|
||||
} catch (IOException e) {
|
||||
AnvilLib.LOGGER.error("Can't load cape: {}", id, e);
|
||||
return;
|
||||
}
|
||||
Identifier location = new Identifier("anvillib", "textures/cape/" + data.id);
|
||||
String hash = Hashing.sha1().hashUnencodedChars(data.id).toString();
|
||||
AbstractTexture texture = this.textureManager.getOrDefault(
|
||||
location, MissingSprite.getMissingSpriteTexture()
|
||||
);
|
||||
if (texture == MissingSprite.getMissingSpriteTexture()) {
|
||||
File file = new File(
|
||||
this.cacheDir, hash.length() > 2 ? hash.substring(0, 2) : "xx"
|
||||
);
|
||||
File file2 = new File(file, hash);
|
||||
texture = new PlayerSkinTexture(
|
||||
file2, data.url, new Identifier("textures/block/dirt.png"), false, null
|
||||
);
|
||||
this.textureManager.registerTexture(location, texture);
|
||||
}
|
||||
this.provider.capes.put(data.id, location);
|
||||
this.provider.markDirty();
|
||||
}
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote.thread;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import net.anvilcraft.anvillib.AnvilLib;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.RemoteCosmetic;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.RemoteCosmeticProvider;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.model.AnimationData;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.model.CosmeticData;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.model.TextureData;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.texture.AbstractTexture;
|
||||
import net.minecraft.client.texture.MissingSprite;
|
||||
import net.minecraft.client.texture.PlayerSkinTexture;
|
||||
import net.minecraft.client.texture.TextureManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
import software.bernie.geckolib3.core.builder.Animation;
|
||||
import software.bernie.geckolib3.core.molang.MolangParser;
|
||||
import software.bernie.geckolib3.file.AnimationFile;
|
||||
import software.bernie.geckolib3.geo.exception.GeckoLibException;
|
||||
import software.bernie.geckolib3.geo.raw.pojo.Converter;
|
||||
import software.bernie.geckolib3.geo.raw.pojo.FormatVersion;
|
||||
import software.bernie.geckolib3.geo.raw.pojo.RawGeoModel;
|
||||
import software.bernie.geckolib3.geo.raw.tree.RawGeometryTree;
|
||||
import software.bernie.geckolib3.geo.render.GeoBuilder;
|
||||
import software.bernie.geckolib3.geo.render.built.GeoModel;
|
||||
import software.bernie.geckolib3.util.json.JsonAnimationUtils;
|
||||
|
||||
public class CosmeticAssetsLoaderThread extends AbstractFileDownloaderThread {
|
||||
private RemoteCosmetic cosmetic;
|
||||
private CosmeticData data;
|
||||
private MolangParser parser = new MolangParser();
|
||||
private TextureManager textureManager
|
||||
= MinecraftClient.getInstance().getTextureManager();
|
||||
private File cacheDir;
|
||||
private RemoteCosmeticProvider provider;
|
||||
|
||||
public CosmeticAssetsLoaderThread(
|
||||
RemoteCosmetic cosmetic,
|
||||
CosmeticData data,
|
||||
File cacheDir,
|
||||
RemoteCosmeticProvider provider
|
||||
) {
|
||||
super("0.2.0");
|
||||
this.cosmetic = cosmetic;
|
||||
this.data = data;
|
||||
this.cacheDir = cacheDir;
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.loadModel(this.data.modelUrl);
|
||||
this.loadTexture(this.data.textureData);
|
||||
this.loadAnimations(this.data.animationData);
|
||||
this.provider.markDirty();
|
||||
}
|
||||
|
||||
private void loadAnimations(AnimationData anim) {
|
||||
if (anim == null) {
|
||||
this.cosmetic.loadAnimations(null, anim);
|
||||
return;
|
||||
}
|
||||
AnimationFile animations = null;
|
||||
try {
|
||||
URI url = new URI(this.data.animationData.url);
|
||||
JsonObject data = this.loadJson(url, JsonObject.class);
|
||||
animations = this.buildAnimationFile(data);
|
||||
} catch (IOException | URISyntaxException | NullPointerException e) {
|
||||
AnvilLib.LOGGER.error(
|
||||
"Could not load animation: {}", this.data.animationData.url, e
|
||||
);
|
||||
}
|
||||
this.cosmetic.loadAnimations(animations, anim);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void loadTexture(TextureData data) {
|
||||
String hash = Hashing.sha1().hashUnencodedChars(this.data.id).toString();
|
||||
AbstractTexture texture = this.textureManager.getOrDefault(
|
||||
this.cosmetic.getTextureLocation(), MissingSprite.getMissingSpriteTexture()
|
||||
);
|
||||
if (texture == MissingSprite.getMissingSpriteTexture()) {
|
||||
File file = new File(
|
||||
this.cacheDir, hash.length() > 2 ? hash.substring(0, 2) : "xx"
|
||||
);
|
||||
File file2 = new File(file, hash);
|
||||
texture = new PlayerSkinTexture(
|
||||
file2, data.url, new Identifier("textures/block/dirt.png"), false, null
|
||||
);
|
||||
this.textureManager.registerTexture(
|
||||
this.cosmetic.getTextureLocation(), texture
|
||||
);
|
||||
}
|
||||
this.cosmetic.loadTexture(data);
|
||||
}
|
||||
|
||||
private void loadModel(String url) {
|
||||
try {
|
||||
URI uri = new URI(url);
|
||||
String data = Objects.requireNonNull(this.getStringForURL(uri));
|
||||
GeoModel model = this.buildModel(data);
|
||||
this.cosmetic.loadModel(model);
|
||||
} catch (
|
||||
NullPointerException | URISyntaxException | IOException | GeckoLibException e
|
||||
) {
|
||||
AnvilLib.LOGGER.error("Can't load remote model: {}", url, e);
|
||||
this.handleFailure();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFailure() {
|
||||
this.provider.failCosmeticLoading(this.data.id);
|
||||
}
|
||||
|
||||
private AnimationFile buildAnimationFile(JsonObject json) {
|
||||
AnimationFile animationFile = new AnimationFile();
|
||||
for (Map.Entry<String, JsonElement> entry :
|
||||
JsonAnimationUtils.getAnimations(json)) {
|
||||
String animationName = entry.getKey();
|
||||
Animation animation;
|
||||
try {
|
||||
animation = JsonAnimationUtils.deserializeJsonToAnimation(
|
||||
JsonAnimationUtils.getAnimation(json, animationName), parser
|
||||
);
|
||||
animationFile.putAnimation(animationName, animation);
|
||||
} catch (Exception e) {
|
||||
AnvilLib.LOGGER.error("Could not load animation: {}", animationName, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return animationFile;
|
||||
}
|
||||
|
||||
private GeoModel buildModel(String json) throws IOException {
|
||||
Identifier location = this.cosmetic.getModelLocation();
|
||||
RawGeoModel rawModel = Converter.fromJsonString(json);
|
||||
if (rawModel.getFormatVersion() != FormatVersion.VERSION_1_12_0) {
|
||||
throw new GeckoLibException(
|
||||
location, "Wrong geometry json version, expected 1.12.0"
|
||||
);
|
||||
}
|
||||
RawGeometryTree rawGeometryTree = RawGeometryTree.parseHierarchy(rawModel);
|
||||
return GeoBuilder.getGeoBuilder(location.getNamespace())
|
||||
.constructGeoModel(rawGeometryTree);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote.thread;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import net.anvilcraft.anvillib.AnvilLib;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.RemoteCosmetic;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.RemoteCosmeticProvider;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.model.CosmeticData;
|
||||
|
||||
public class CosmeticLoaderThread extends AbstractFileDownloaderThread {
|
||||
private URI url;
|
||||
private RemoteCosmeticProvider provider;
|
||||
|
||||
public CosmeticLoaderThread(URI url, RemoteCosmeticProvider provider) {
|
||||
super("0.2.0");
|
||||
this.url = url;
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
CosmeticData data = this.loadJson(url, CosmeticData.class);
|
||||
if (data == null)
|
||||
throw new IOException("Cosmetic not found");
|
||||
RemoteCosmetic cosmetic = new RemoteCosmetic(data.id);
|
||||
this.provider.cosmetics.put(data.id, cosmetic);
|
||||
this.provider.loadAssets(data, cosmetic);
|
||||
} catch (IOException e) {
|
||||
AnvilLib.LOGGER.error("Can't load cosmetic", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package net.anvilcraft.anvillib.cosmetics.remote.thread;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.RemoteCosmeticProvider;
|
||||
import net.anvilcraft.anvillib.cosmetics.remote.model.PlayerData;
|
||||
|
||||
public class PlayerCosmeticLoaderThread extends AbstractFileDownloaderThread {
|
||||
private URI config;
|
||||
private RemoteCosmeticProvider provider;
|
||||
|
||||
public PlayerCosmeticLoaderThread(URI config, RemoteCosmeticProvider provider) {
|
||||
super("0.2.0");
|
||||
this.config = config;
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
PlayerData player = this.loadJson(config, PlayerData.class);
|
||||
if (player == null)
|
||||
return;
|
||||
for (String id : player.cosmetics) {
|
||||
this.provider.loadCosmetic(id);
|
||||
this.provider.playerCosmetics.get(player.uuid).add(id);
|
||||
}
|
||||
if (player.cape != null) {
|
||||
this.provider.loadCape(player.cape);
|
||||
this.provider.playerCapes.put(player.uuid, player.cape);
|
||||
}
|
||||
|
||||
this.provider.markDirty();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package net.anvilcraft.anvillib.event;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.render.entity.EntityRenderer;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
||||
public record
|
||||
AddEntityRenderLayersEvent(Map<String, EntityRenderer<? extends PlayerEntity>> skinMap) {}
|
|
@ -1,31 +0,0 @@
|
|||
package net.anvilcraft.anvillib.event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Bus {
|
||||
public static final Bus MAIN = new Bus();
|
||||
|
||||
private final Map<Class<?>, List<Consumer<?>>> handlerMap = new HashMap<>();
|
||||
|
||||
public void register(IEventBusRegisterable obj) {
|
||||
obj.registerEventHandlers(this);
|
||||
}
|
||||
|
||||
public <T> void register(Class<T> clazz, Consumer<T> handler) {
|
||||
handlerMap.computeIfAbsent(clazz, alec -> new ArrayList<>()).add(handler);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> void fire(T ev) {
|
||||
var clazz = ev.getClass();
|
||||
if (handlerMap.containsKey(clazz)) {
|
||||
for (Consumer<?> handler : handlerMap.get(clazz)) {
|
||||
((Consumer<T>) handler).accept(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package net.anvilcraft.anvillib.event;
|
||||
|
||||
/**
|
||||
* IEventBusRegisterable describes a class which contains one or more event handlers to be
|
||||
* registered on the anvillib event bus.
|
||||
*/
|
||||
public interface IEventBusRegisterable {
|
||||
/**
|
||||
* Register this object's event handlers on the given bus.
|
||||
*/
|
||||
public void registerEventHandlers(Bus bus);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package net.anvilcraft.anvillib.mixin.accessor;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import software.bernie.geckolib3.core.processor.AnimationProcessor;
|
||||
import software.bernie.geckolib3.geo.render.built.GeoModel;
|
||||
import software.bernie.geckolib3.model.AnimatedGeoModel;
|
||||
|
||||
@Mixin(AnimatedGeoModel.class)
|
||||
public interface AnimatedGeoModelAccessor {
|
||||
@Accessor(remap = false)
|
||||
AnimationProcessor getAnimationProcessor();
|
||||
|
||||
@Accessor(remap = false)
|
||||
GeoModel getCurrentModel();
|
||||
|
||||
@Accessor(remap = false)
|
||||
void setCurrentModel(GeoModel model);
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package net.anvilcraft.anvillib.mixin.client;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import net.anvilcraft.anvillib.cosmetics.CosmeticsManager;
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
@Mixin(AbstractClientPlayerEntity.class)
|
||||
public abstract class AbstractClientPlayerEntityMixin extends PlayerEntity {
|
||||
private static Identifier ELYTRA = new Identifier("textures/entity/elytra.png");
|
||||
|
||||
public AbstractClientPlayerEntityMixin(
|
||||
World world, BlockPos pos, float yaw, GameProfile profile
|
||||
) {
|
||||
super(world, pos, yaw, profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Custom capes & no Mojank capes
|
||||
* @author tilera
|
||||
*/
|
||||
@Overwrite
|
||||
public Identifier getCapeTexture() {
|
||||
return CosmeticsManager.getCape(this.uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Custom capes & no Mojank capes
|
||||
* @author tilera
|
||||
*/
|
||||
@Overwrite
|
||||
public Identifier getElytraTexture() {
|
||||
return ELYTRA;
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package net.anvilcraft.anvillib.mixin.client;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
import net.anvilcraft.anvillib.cosmetics.ClientEventHandler;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.RunArgs;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public class MinecraftClientMixin {
|
||||
@Inject(at = @At("RETURN"), method = "<init>")
|
||||
public void init(RunArgs args, CallbackInfo info) {
|
||||
ClientEventHandler.registerRemoteCosmetics(args.directories.assetDir);
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package net.anvilcraft.anvillib.mixin.common;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import net.anvilcraft.anvillib.AnvilLib;
|
||||
import net.anvilcraft.anvillib.event.Bus;
|
||||
import net.anvilcraft.anvillib.recipe.RecipesEvent;
|
||||
import net.minecraft.recipe.Recipe;
|
||||
import net.minecraft.recipe.RecipeManager;
|
||||
import net.minecraft.recipe.RecipeType;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
|
||||
@Mixin(RecipeManager.class)
|
||||
public class RecipeManagerMixin {
|
||||
@Shadow
|
||||
private Map<RecipeType<?>, Map<Identifier, Recipe<?>>> recipes;
|
||||
|
||||
@Shadow
|
||||
private Map<Identifier, Recipe<?>> recipesById;
|
||||
|
||||
@Inject(method = "apply", at = @At("RETURN"))
|
||||
private void afterLoad(
|
||||
Map<Identifier, JsonElement> alec1,
|
||||
ResourceManager alec2,
|
||||
Profiler alec3,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
AnvilLib.LOGGER.info("Firing Recipe Event");
|
||||
Map<RecipeType<?>, Map<Identifier, Recipe<?>>> recipes = new HashMap<>();
|
||||
this.recipes.forEach((k, v) -> recipes.put(k, new HashMap<>(v)));
|
||||
|
||||
var ev = new RecipesEvent(recipes, new HashMap<>(this.recipesById));
|
||||
Bus.MAIN.fire(ev);
|
||||
this.recipes = ev.recipes;
|
||||
this.recipesById = ev.recipesById;
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package net.anvilcraft.anvillib.mixin.common;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
import net.anvilcraft.anvillib.worldgen.AdvancedStructurePoolFeatureConfig;
|
||||
import net.minecraft.structure.PoolStructurePiece;
|
||||
import net.minecraft.structure.pool.StructurePoolBasedGenerator;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.world.gen.feature.StructurePoolFeatureConfig;
|
||||
|
||||
@Mixin(StructurePoolBasedGenerator.class)
|
||||
public class StructurePoolBasedGeneratorMixin {
|
||||
// this is a lambda
|
||||
@ModifyVariable(method = "method_39824", at = @At(value = "STORE", ordinal = 0))
|
||||
private static Box adjustAdvBoundingBox(
|
||||
Box box, PoolStructurePiece alec, StructurePoolFeatureConfig conf
|
||||
) {
|
||||
if (conf instanceof AdvancedStructurePoolFeatureConfig aconf) {
|
||||
return new Box(
|
||||
box.minX + 80 - aconf.maxDistanceFromCenter,
|
||||
box.minY + 80 - aconf.maxDistanceFromCenter,
|
||||
box.minZ + 80 - aconf.maxDistanceFromCenter,
|
||||
box.maxX - 80 + aconf.maxDistanceFromCenter,
|
||||
box.maxY - 80 + aconf.maxDistanceFromCenter,
|
||||
box.maxZ - 80 + aconf.maxDistanceFromCenter
|
||||
);
|
||||
}
|
||||
return box;
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package net.anvilcraft.anvillib.mixinutils;
|
||||
|
||||
import net.minecraft.structure.StructurePiece;
|
||||
import net.minecraft.util.math.BlockBox;
|
||||
|
||||
public record BeardifierLocals(
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
StructurePiece structurePiece,
|
||||
BlockBox boundingBox,
|
||||
int l,
|
||||
int m
|
||||
) {}
|
|
@ -1,23 +0,0 @@
|
|||
package net.anvilcraft.anvillib.recipe;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.anvilcraft.anvillib.Util;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public abstract class AbstractIngredientCondition implements Predicate<Ingredient> {
|
||||
public static AbstractIngredientCondition of(String s) {
|
||||
return s.charAt(0) == '#'
|
||||
? new TagIngredientCondition(new Identifier(s.substring(1)))
|
||||
: new StackIngredientCondition(Util.stackFromRegistry(new Identifier(s)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Ingredient i) {
|
||||
return Arrays.stream(i.entries).anyMatch(this::entryMatches);
|
||||
}
|
||||
|
||||
public abstract boolean entryMatches(Ingredient.Entry e);
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package net.anvilcraft.anvillib.recipe;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.recipe.Recipe;
|
||||
|
||||
/**
|
||||
* IRecipeMapper describes a class that knows how to conditionally replace recipes.
|
||||
*/
|
||||
public interface IRecipeMapper extends Function<Recipe<?>, Recipe<?>> {
|
||||
public boolean shouldMap(Recipe<?> recipe);
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package net.anvilcraft.anvillib.recipe;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.recipe.Recipe;
|
||||
|
||||
public class IngredientsContainPredicate implements Predicate<Recipe<?>> {
|
||||
public Predicate<Ingredient> pred;
|
||||
|
||||
public IngredientsContainPredicate(Predicate<Ingredient> pred) {
|
||||
this.pred = pred;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Recipe<?> r) {
|
||||
return r.getIngredients().stream().anyMatch(this.pred);
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package net.anvilcraft.anvillib.recipe;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.anvilcraft.anvillib.Util;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.recipe.Recipe;
|
||||
|
||||
public class InputReplaceRecipeMapper implements IRecipeMapper {
|
||||
public Map<Predicate<Ingredient>, Ingredient> replacements = new HashMap<>();
|
||||
|
||||
public InputReplaceRecipeMapper replace(Predicate<Ingredient> p, Ingredient i) {
|
||||
this.replacements.put(p, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
public InputReplaceRecipeMapper replace(String p, Ingredient i) {
|
||||
return this.replace(AbstractIngredientCondition.of(p), i);
|
||||
}
|
||||
|
||||
public InputReplaceRecipeMapper replace(String p, String i) {
|
||||
return this.replace(p, Util.ingredientFromString(i));
|
||||
}
|
||||
|
||||
public InputReplaceRecipeMapper replace(Predicate<Ingredient> p, String i) {
|
||||
return this.replace(p, Util.ingredientFromString(i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldMap(Recipe<?> recipe) {
|
||||
var ingredients = recipe.getIngredients();
|
||||
if (ingredients == null)
|
||||
return false;
|
||||
|
||||
for (var k : this.replacements.keySet())
|
||||
if (ingredients.stream().anyMatch(k))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Recipe<?> apply(Recipe<?> recipe) {
|
||||
var ingredients = recipe.getIngredients();
|
||||
for (int i = 0; i < ingredients.size(); i++) {
|
||||
var ing = ingredients.get(i);
|
||||
for (var entry : this.replacements.entrySet())
|
||||
if (entry.getKey().test(ing))
|
||||
ingredients.set(i, entry.getValue());
|
||||
}
|
||||
return recipe;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package net.anvilcraft.anvillib.recipe;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.Recipe;
|
||||
|
||||
public class RecipeContainsPredicate implements Predicate<Recipe<?>> {
|
||||
public ItemStack item;
|
||||
|
||||
public RecipeContainsPredicate(ItemStack item) {
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Recipe<?> r) {
|
||||
return r.getIngredients() == null
|
||||
? false
|
||||
: r.getIngredients().stream().anyMatch(new StackIngredientCondition(this.item)
|
||||
) || r.getOutput().isItemEqual(this.item);
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
package net.anvilcraft.anvillib.recipe;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import net.minecraft.recipe.Recipe;
|
||||
import net.minecraft.recipe.RecipeType;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class RecipesEvent {
|
||||
public Map<RecipeType<?>, Map<Identifier, Recipe<?>>> recipes;
|
||||
public Map<Identifier, Recipe<?>> recipesById;
|
||||
|
||||
public RecipesEvent(
|
||||
Map<RecipeType<?>, Map<Identifier, Recipe<?>>> recipes,
|
||||
Map<Identifier, Recipe<?>> recipesById
|
||||
) {
|
||||
this.recipes = recipes;
|
||||
this.recipesById = recipesById;
|
||||
}
|
||||
|
||||
public void registerRecipe(Recipe<?> recipe) {
|
||||
if (!this.recipes.containsKey(recipe.getType()))
|
||||
this.recipes.put(recipe.getType(), new HashMap<>());
|
||||
|
||||
this.recipes.get(recipe.getType()).put(recipe.getId(), recipe);
|
||||
this.recipesById.put(recipe.getId(), recipe);
|
||||
}
|
||||
|
||||
public Optional<Recipe<?>> removeRecipeID(Identifier id) {
|
||||
if (this.recipesById.containsKey(id)) {
|
||||
return Optional.of(
|
||||
this.recipes.get(this.recipesById.remove(id).getType()).remove(id)
|
||||
);
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void removeRecipesMatching(Predicate<Recipe<?>> p) {
|
||||
var iter = this.recipesById.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
var entry = iter.next();
|
||||
if (p.test(entry.getValue())) {
|
||||
iter.remove();
|
||||
this.recipes.get(entry.getValue().getType()).remove(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void mapRecipes(IRecipeMapper mapper) {
|
||||
var iter = this.recipesById.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
var entry = iter.next();
|
||||
if (mapper.shouldMap(entry.getValue())) {
|
||||
var mapped = mapper.apply(entry.getValue());
|
||||
if (mapped != entry.getValue()) {
|
||||
iter.remove();
|
||||
this.recipes.get(entry.getValue().getType()).remove(entry.getKey());
|
||||
this.registerRecipe(mapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void mapRecipeID(Identifier id, Function<Recipe<?>, Recipe<?>> func) {
|
||||
var recipe = this.recipesById.get(id);
|
||||
if (recipe != null) {
|
||||
var mapped = func.apply(recipe);
|
||||
if (recipe != mapped) {
|
||||
this.removeRecipeID(id);
|
||||
this.registerRecipe(mapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
package net.anvilcraft.anvillib.recipe;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.recipe.ShapedRecipe;
|
||||
import net.minecraft.tag.TagKey;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
public class ShapedRecipeBuilder {
|
||||
public Identifier ident;
|
||||
public String[] pattern;
|
||||
public Map<Character, Ingredient> ingredients = new HashMap<>();
|
||||
public ItemStack output;
|
||||
|
||||
public ShapedRecipeBuilder(Identifier ident, ItemStack output) {
|
||||
this.ident = ident;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
public ShapedRecipeBuilder pattern(String... pat) {
|
||||
this.pattern = pat;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ShapedRecipeBuilder ingredient(char c, Ingredient i) {
|
||||
this.ingredients.put(c, i);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ShapedRecipeBuilder ingredient(char c, ItemStack... is) {
|
||||
return this.ingredient(c, Ingredient.ofStacks(is));
|
||||
}
|
||||
|
||||
public ShapedRecipeBuilder ingredient(char c, Item i) {
|
||||
return this.ingredient(c, new ItemStack(i));
|
||||
}
|
||||
|
||||
public ShapedRecipeBuilder ingredient(char c, Block b) {
|
||||
return this.ingredient(c, new ItemStack(b));
|
||||
}
|
||||
|
||||
public ShapedRecipeBuilder ingredient(char c, String s) {
|
||||
if (s.charAt(0) == '#') {
|
||||
return this.tagIngredient(c, new Identifier(s.substring(1)));
|
||||
}
|
||||
|
||||
var ident = new Identifier(s);
|
||||
var maybeItem = Registry.ITEM.get(ident);
|
||||
if (maybeItem == null) {
|
||||
var maybeBlock = Registry.BLOCK.get(ident);
|
||||
if (maybeBlock == null)
|
||||
throw new IllegalArgumentException(
|
||||
"ID " + s + " not found in item or block registry!"
|
||||
);
|
||||
|
||||
return this.ingredient(c, maybeBlock);
|
||||
}
|
||||
|
||||
return this.ingredient(c, maybeItem);
|
||||
}
|
||||
|
||||
public ShapedRecipeBuilder tagIngredient(char c, Identifier t) {
|
||||
return this.ingredient(c, Ingredient.fromTag(TagKey.of(Registry.ITEM_KEY, t)));
|
||||
}
|
||||
|
||||
public ShapedRecipe build() {
|
||||
int width = -1;
|
||||
for (String line : this.pattern) {
|
||||
if (width != -1 && width != line.length())
|
||||
throw new IllegalArgumentException(
|
||||
"Lines in crafting pattern must be same width!"
|
||||
);
|
||||
width = line.length();
|
||||
}
|
||||
|
||||
DefaultedList<Ingredient> ingredients = DefaultedList.of();
|
||||
Arrays.stream(this.pattern)
|
||||
.flatMap(s -> s.chars().mapToObj(c -> (char) c))
|
||||
.map(k -> this.ingredients.getOrDefault(k, Ingredient.empty()))
|
||||
.forEach(ingredients::add);
|
||||
|
||||
return new ShapedRecipe(
|
||||
this.ident, "", width, this.pattern.length, ingredients, this.output
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package net.anvilcraft.anvillib.recipe;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.Ingredient.Entry;
|
||||
import net.minecraft.recipe.Ingredient.StackEntry;
|
||||
|
||||
public class StackIngredientCondition extends AbstractIngredientCondition {
|
||||
public ItemStack stack;
|
||||
|
||||
public StackIngredientCondition(ItemStack stack) {
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean entryMatches(Entry e) {
|
||||
return e instanceof StackEntry se && se.stack.isItemEqual(this.stack);
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package net.anvilcraft.anvillib.recipe;
|
||||
|
||||
import net.minecraft.recipe.Ingredient.Entry;
|
||||
import net.minecraft.recipe.Ingredient.TagEntry;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class TagIngredientCondition extends AbstractIngredientCondition {
|
||||
public Identifier id;
|
||||
|
||||
public TagIngredientCondition(Identifier id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean entryMatches(Entry e) {
|
||||
return e instanceof TagEntry te && te.tag.id().equals(this.id);
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package net.anvilcraft.anvillib.worldgen;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
|
||||
import net.minecraft.structure.pool.StructurePool;
|
||||
import net.minecraft.util.registry.RegistryEntry;
|
||||
import net.minecraft.world.gen.feature.StructurePoolFeatureConfig;
|
||||
|
||||
public class AdvancedStructurePoolFeatureConfig extends StructurePoolFeatureConfig {
|
||||
public static final Codec<StructurePoolFeatureConfig> CODEC
|
||||
= RecordCodecBuilder.create((instance) -> {
|
||||
return instance
|
||||
.group(
|
||||
StructurePool.REGISTRY_CODEC.fieldOf("start_pool")
|
||||
.forGetter(
|
||||
(self)
|
||||
-> ((AdvancedStructurePoolFeatureConfig) self)
|
||||
.getStartPool()
|
||||
),
|
||||
Codec.intRange(0, 7).fieldOf("size").forGetter(
|
||||
(self) -> ((AdvancedStructurePoolFeatureConfig) self).getSize()
|
||||
),
|
||||
Codec.INT.fieldOf("max_distance_from_center")
|
||||
.forGetter(
|
||||
(self)
|
||||
-> ((AdvancedStructurePoolFeatureConfig) self)
|
||||
.maxDistanceFromCenter
|
||||
),
|
||||
Codec.BOOL.fieldOf("use_box_beardifier").forGetter(
|
||||
(self) -> ((AdvancedStructurePoolFeatureConfig) self).useBoxBeardifier
|
||||
)
|
||||
)
|
||||
.apply(instance, AdvancedStructurePoolFeatureConfig::new);
|
||||
});
|
||||
|
||||
public final int maxDistanceFromCenter;
|
||||
public final boolean useBoxBeardifier;
|
||||
|
||||
public AdvancedStructurePoolFeatureConfig(
|
||||
RegistryEntry<StructurePool> startPool, int size, int maxDistanceFromCenter, boolean useBoxBeardifier
|
||||
) {
|
||||
super(startPool, size);
|
||||
this.maxDistanceFromCenter = maxDistanceFromCenter;
|
||||
this.useBoxBeardifier = useBoxBeardifier;
|
||||
}
|
||||
|
||||
public AdvancedStructurePoolFeatureConfig(
|
||||
RegistryEntry<StructurePool> startPool, int size, int maxDistanceFromCenter
|
||||
) {
|
||||
this(startPool, size, maxDistanceFromCenter, false);
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.anvilcraft.anvillib.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"minVersion": "0.8",
|
||||
"client": [
|
||||
"client.MinecraftClientMixin",
|
||||
"client.AbstractClientPlayerEntityMixin"
|
||||
],
|
||||
"mixins": [
|
||||
"accessor.AnimatedGeoModelAccessor",
|
||||
"common.RecipeManagerMixin",
|
||||
"common.StructurePoolBasedGeneratorMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
accessWidener v2 named
|
||||
# vim: ft=conf
|
||||
|
||||
accessible class net/minecraft/recipe/Ingredient$Entry
|
||||
accessible field net/minecraft/recipe/Ingredient entries [Lnet/minecraft/recipe/Ingredient$Entry;
|
||||
accessible class net/minecraft/recipe/Ingredient$TagEntry
|
||||
accessible field net/minecraft/recipe/Ingredient$TagEntry tag Lnet/minecraft/tag/TagKey;
|
||||
accessible class net/minecraft/recipe/Ingredient$StackEntry
|
||||
accessible field net/minecraft/recipe/Ingredient$StackEntry stack Lnet/minecraft/item/ItemStack;
|
||||
|
||||
accessible method net/minecraft/client/render/entity/LivingEntityRenderer addFeature (Lnet/minecraft/client/render/entity/feature/FeatureRenderer;)Z
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"accessWidener": "anvillib.accesswidener"
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"pack": {
|
||||
"description": "Resources for anvillib",
|
||||
"pack_format": 8,
|
||||
"_comment": "pack_format 8 is the current format for Minecraft 1.18.2. Be aware may have changed by the time you use this template!"
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
plugins {
|
||||
id "com.github.johnrengelman.shadow" version "7.1.2"
|
||||
}
|
||||
|
||||
architectury {
|
||||
platformSetupLoomIde()
|
||||
fabric()
|
||||
}
|
||||
|
||||
loom {
|
||||
accessWidenerPath = project(":common").loom.accessWidenerPath
|
||||
}
|
||||
|
||||
configurations {
|
||||
common
|
||||
shadowCommon // Don't use shadow from the shadow plugin since it *excludes* files.
|
||||
compileClasspath.extendsFrom common
|
||||
runtimeClasspath.extendsFrom common
|
||||
developmentFabric.extendsFrom common
|
||||
}
|
||||
|
||||
dependencies {
|
||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||
|
||||
modImplementation "software.bernie.geckolib:geckolib-fabric-1.18:3.0.80"
|
||||
|
||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||
shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false }
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand "version": project.version
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
exclude "architectury.common.json"
|
||||
|
||||
configurations = [project.configurations.shadowCommon]
|
||||
archiveClassifier = "dev-shadow"
|
||||
}
|
||||
|
||||
remapJar {
|
||||
injectAccessWidener = true
|
||||
input.set shadowJar.archiveFile
|
||||
dependsOn shadowJar
|
||||
}
|
||||
|
||||
sourcesJar {
|
||||
def commonSources = project(":common").sourcesJar
|
||||
dependsOn commonSources
|
||||
from commonSources.archiveFile.map { zipTree(it) }
|
||||
}
|
||||
|
||||
components.java {
|
||||
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenFabric(MavenPublication) {
|
||||
artifactId = rootProject.archives_base_name + "-" + project.name
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package net.anvilcraft.anvillib;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
|
||||
public class AnvilLibFabric implements ModInitializer, ClientModInitializer {
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
AnvilLib.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
AnvilLib.initializeClient();
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package net.anvilcraft.anvillib.mixin.fabric.client;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.anvilcraft.anvillib.event.AddEntityRenderLayersEvent;
|
||||
import net.anvilcraft.anvillib.event.Bus;
|
||||
import net.minecraft.client.render.entity.EntityRenderDispatcher;
|
||||
import net.minecraft.client.render.entity.EntityRenderer;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
|
||||
@Mixin(EntityRenderDispatcher.class)
|
||||
public class EntityRenderDispatcherMixin {
|
||||
@Shadow
|
||||
private Map<String, EntityRenderer<? extends PlayerEntity>> modelRenderers;
|
||||
|
||||
@Inject(method = "reload", at = @At("TAIL"))
|
||||
public void onReload(ResourceManager alec, CallbackInfo ci) {
|
||||
Bus.MAIN.fire(new AddEntityRenderLayersEvent(this.modelRenderers));
|
||||
}
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
package net.anvilcraft.anvillib.mixin.fabric.common;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArgs;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
import org.spongepowered.asm.mixin.injection.invoke.arg.Args;
|
||||
|
||||
import net.anvilcraft.anvillib.mixinutils.BeardifierLocals;
|
||||
import net.anvilcraft.anvillib.worldgen.AdvancedStructurePoolFeatureConfig;
|
||||
import net.minecraft.structure.StructurePiece;
|
||||
import net.minecraft.structure.StructureStart;
|
||||
import net.minecraft.util.math.BlockBox;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.gen.StructureWeightSampler;
|
||||
import net.minecraft.world.gen.densityfunction.DensityFunction;
|
||||
import net.minecraft.world.gen.feature.ConfiguredStructureFeature;
|
||||
|
||||
/**
|
||||
* This mixin is responsible for reimplementing 1.19's BEARD_BOX which causes terrain
|
||||
* to be removed around ancient city structures.
|
||||
*/
|
||||
@Mixin(StructureWeightSampler.class)
|
||||
public class BeardifierMixin {
|
||||
private static ThreadLocal<BeardifierLocals> currentLocals = new ThreadLocal<>();
|
||||
@Unique
|
||||
private Map<Object, ConfiguredStructureFeature<?, ?>> featureMap = new HashMap<>();
|
||||
|
||||
@ModifyArgs(
|
||||
method = "method_38319",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lit/unimi/dsi/fastutil/objects/ObjectList;add(Ljava/lang/Object;)Z"
|
||||
),
|
||||
remap = false
|
||||
)
|
||||
private void
|
||||
addStructurePieceToMap(
|
||||
Args args, ChunkPos alec1, int alec2, int alec3, StructureStart ss
|
||||
) {
|
||||
featureMap.put(args.get(0), ss.getFeature());
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "sample",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target
|
||||
= "Lnet/minecraft/structure/StructurePiece;getWeightType()Lnet/minecraft/world/gen/StructureWeightType;"
|
||||
),
|
||||
locals = LocalCapture.CAPTURE_FAILHARD
|
||||
)
|
||||
private void
|
||||
collectVariables(
|
||||
DensityFunction.NoisePos alec1,
|
||||
CallbackInfoReturnable<Double> ci,
|
||||
int i,
|
||||
int j,
|
||||
int k,
|
||||
double alec2,
|
||||
StructurePiece structurePiece,
|
||||
BlockBox boundingBox,
|
||||
int l,
|
||||
int m
|
||||
) {
|
||||
currentLocals.set(new BeardifierLocals(i, j, k, structurePiece, boundingBox, l, m)
|
||||
);
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private static double getStructureWeight(int l, int m, int n) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "sample",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target
|
||||
= "Lnet/minecraft/world/gen/StructureWeightSampler;getStructureWeight(III)D"
|
||||
)
|
||||
)
|
||||
private double
|
||||
beardContribution(int l, int m, int n) {
|
||||
BeardifierLocals locals = currentLocals.get();
|
||||
if (locals == null)
|
||||
return getStructureWeight(l, m, n);
|
||||
currentLocals.remove();
|
||||
|
||||
ConfiguredStructureFeature<?, ?> sf = this.featureMap.get(locals.structurePiece());
|
||||
if (sf == null /* WTF */ || !(sf.config instanceof AdvancedStructurePoolFeatureConfig && ((AdvancedStructurePoolFeatureConfig) sf.config).useBoxBeardifier))
|
||||
return getStructureWeight(l, m, n);
|
||||
|
||||
int q = Math.max(0, Math.max(-m, locals.y() - locals.boundingBox().getMaxY()));
|
||||
|
||||
return getAncientCityBeardContribution(l, q, n, m);
|
||||
}
|
||||
|
||||
private static double getAncientCityBeardContribution(int i, int j, int k, int l) {
|
||||
int m = i + 12;
|
||||
int n = j + 12;
|
||||
int o = k + 12;
|
||||
if (!(m >= 0 && m < 24 && n >= 0 && n < 24 && o >= 0 && o < 24)) {
|
||||
return 0.0;
|
||||
}
|
||||
double d = (double) l + 0.5;
|
||||
double e = MathHelper.squaredMagnitude(i, d, k);
|
||||
double f = -d * MathHelper.fastInverseSqrt(e / 2.0) / 2.0;
|
||||
return f * (double) computeBeardContribution(o - 12, m - 12, n - 12);
|
||||
}
|
||||
|
||||
private static double computeBeardContribution(int i, double d, int j) {
|
||||
double e = MathHelper.squaredMagnitude(i, d, j);
|
||||
double f = Math.pow(Math.E, -e / 16.0);
|
||||
return f;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.anvilcraft.anvillib.mixin.fabric",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"minVersion": "0.8",
|
||||
"client": [
|
||||
"client.EntityRenderDispatcherMixin"
|
||||
],
|
||||
"mixins": [
|
||||
"common.BeardifierMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "anvillib",
|
||||
"version": "${version}",
|
||||
"name": "AnvilLib",
|
||||
"description": "ALEC!",
|
||||
"authors": [
|
||||
"LordMZTE",
|
||||
"tilera"
|
||||
],
|
||||
"contact": {
|
||||
"homepage": "https://anvilcraft.net/",
|
||||
"sources": "https://git.tilera.org/anvilcraft/anvillib"
|
||||
},
|
||||
"license": "AGPL-3.0+ALEC",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.anvilcraft.anvillib.AnvilLibFabric"
|
||||
],
|
||||
"client": [
|
||||
"net.anvilcraft.anvillib.AnvilLibFabric"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"anvillib.mixins.json",
|
||||
"anvillib-common.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"minecraft": "1.18.2"
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
plugins {
|
||||
id "com.github.johnrengelman.shadow" version "7.1.2"
|
||||
}
|
||||
|
||||
architectury {
|
||||
platformSetupLoomIde()
|
||||
forge()
|
||||
}
|
||||
|
||||
loom {
|
||||
accessWidenerPath = project(":common").loom.accessWidenerPath
|
||||
|
||||
forge {
|
||||
convertAccessWideners = true
|
||||
extraAccessWideners.add loom.accessWidenerPath.get().asFile.name
|
||||
|
||||
mixinConfig "anvillib-common.mixins.json"
|
||||
mixinConfig "anvillib.mixins.json"
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
common
|
||||
shadowCommon // Don't use shadow from the shadow plugin since it *excludes* files.
|
||||
compileClasspath.extendsFrom common
|
||||
runtimeClasspath.extendsFrom common
|
||||
developmentForge.extendsFrom common
|
||||
}
|
||||
|
||||
dependencies {
|
||||
forge "net.minecraftforge:forge:${rootProject.forge_version}"
|
||||
|
||||
modImplementation "software.bernie.geckolib:geckolib-forge-1.18:3.0.57"
|
||||
|
||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||
shadowCommon(project(path: ":common", configuration: "transformProductionForge")) { transitive = false }
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.property "version", project.version
|
||||
|
||||
filesMatching("META-INF/mods.toml") {
|
||||
expand "version": project.version
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
exclude "fabric.mod.json"
|
||||
exclude "architectury.common.json"
|
||||
|
||||
configurations = [project.configurations.shadowCommon]
|
||||
archiveClassifier = "dev-shadow"
|
||||
}
|
||||
|
||||
remapJar {
|
||||
input.set shadowJar.archiveFile
|
||||
dependsOn shadowJar
|
||||
}
|
||||
|
||||
sourcesJar {
|
||||
def commonSources = project(":common").sourcesJar
|
||||
dependsOn commonSources
|
||||
from commonSources.archiveFile.map { zipTree(it) }
|
||||
}
|
||||
|
||||
components.java {
|
||||
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenForge(MavenPublication) {
|
||||
artifactId = rootProject.archives_base_name + "-" + project.name
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
loom.platform=forge
|
|
@ -1,15 +0,0 @@
|
|||
package net.anvilcraft.anvillib;
|
||||
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
|
||||
@Mod(AnvilLib.MODID)
|
||||
public class AnvilLibForge {
|
||||
public AnvilLibForge() {
|
||||
AnvilLib.initialize();
|
||||
IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
bus.<FMLClientSetupEvent>addListener(alec -> AnvilLib.initializeClient());
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package net.anvilcraft.anvillib.client;
|
||||
|
||||
import net.anvilcraft.anvillib.AnvilLib;
|
||||
import net.anvilcraft.anvillib.event.AddEntityRenderLayersEvent;
|
||||
import net.anvilcraft.anvillib.event.Bus;
|
||||
import net.anvilcraft.anvillib.mixin.forge.accessor.AddLayersAccessor;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.EntityRenderersEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
|
||||
|
||||
@EventBusSubscriber(
|
||||
modid = AnvilLib.MODID, bus = EventBusSubscriber.Bus.MOD, value = { Dist.CLIENT }
|
||||
)
|
||||
public class ClientEventHandler {
|
||||
@SubscribeEvent
|
||||
public static void onAddLayers(EntityRenderersEvent.AddLayers ev) {
|
||||
Bus.MAIN.fire(new AddEntityRenderLayersEvent(((AddLayersAccessor) ev).getSkinMap()
|
||||
));
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package net.anvilcraft.anvillib.mixin.forge.accessor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.client.render.entity.EntityRenderer;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraftforge.client.event.EntityRenderersEvent.AddLayers;
|
||||
|
||||
@Mixin(AddLayers.class)
|
||||
public interface AddLayersAccessor {
|
||||
@Accessor(remap = false)
|
||||
public Map<String, EntityRenderer<? extends PlayerEntity>> getSkinMap();
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
package net.anvilcraft.anvillib.mixin.forge.common;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import net.anvilcraft.anvillib.mixinutils.BeardifierLocals;
|
||||
import net.anvilcraft.anvillib.worldgen.AdvancedStructurePoolFeatureConfig;
|
||||
import net.minecraft.structure.StructurePiece;
|
||||
import net.minecraft.structure.StructureStart;
|
||||
import net.minecraft.util.math.BlockBox;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.gen.StructureWeightSampler;
|
||||
import net.minecraft.world.gen.densityfunction.DensityFunction;
|
||||
import net.minecraft.world.gen.feature.ConfiguredStructureFeature;
|
||||
|
||||
/**
|
||||
* This mixin is responsible for reimplementing 1.19's BEARD_BOX which causes terrain
|
||||
* to be removed around ancient city structures.
|
||||
*/
|
||||
@Mixin(StructureWeightSampler.class)
|
||||
public class BeardifierMixin {
|
||||
private static ThreadLocal<BeardifierLocals> currentLocals = new ThreadLocal<>();
|
||||
@Unique
|
||||
private Map<Object, ConfiguredStructureFeature<?, ?>> featureMap = new HashMap<>();
|
||||
|
||||
// This is different than the fabric implementation where this is @ModifyArgs, but
|
||||
// that's borked on Forge (as per usual).
|
||||
@Inject(
|
||||
// for this nonsense to work in the devenv, replace this with method_38319
|
||||
// for prod, use m_208194_
|
||||
// very elegant!
|
||||
method = "m_208194_",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lit/unimi/dsi/fastutil/objects/ObjectList;add(Ljava/lang/Object;)Z"
|
||||
),
|
||||
remap = false,
|
||||
locals = LocalCapture.CAPTURE_FAILHARD
|
||||
)
|
||||
private void
|
||||
addStructurePieceToMap(
|
||||
ChunkPos alec1,
|
||||
int alec2,
|
||||
int alec3,
|
||||
StructureStart ss,
|
||||
CallbackInfo ci,
|
||||
Iterator<?> alec4,
|
||||
StructurePiece sp
|
||||
) {
|
||||
featureMap.put(sp, ss.getFeature());
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "sample",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target
|
||||
= "Lnet/minecraft/structure/StructurePiece;getWeightType()Lnet/minecraft/world/gen/StructureWeightType;"
|
||||
),
|
||||
locals = LocalCapture.CAPTURE_FAILHARD
|
||||
)
|
||||
private void
|
||||
collectVariables(
|
||||
DensityFunction.NoisePos alec1,
|
||||
CallbackInfoReturnable<Double> ci,
|
||||
int i,
|
||||
int j,
|
||||
int k,
|
||||
double alec2,
|
||||
StructurePiece structurePiece,
|
||||
BlockBox boundingBox,
|
||||
int l,
|
||||
int m
|
||||
) {
|
||||
currentLocals.set(new BeardifierLocals(i, j, k, structurePiece, boundingBox, l, m)
|
||||
);
|
||||
}
|
||||
|
||||
@Shadow
|
||||
protected static double getStructureWeight(int l, int m, int n) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "sample",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target
|
||||
= "Lnet/minecraft/world/gen/StructureWeightSampler;getStructureWeight(III)D"
|
||||
)
|
||||
)
|
||||
private double
|
||||
beardContribution(int l, int m, int n) {
|
||||
BeardifierLocals locals = currentLocals.get();
|
||||
if (locals == null)
|
||||
return getStructureWeight(l, m, n);
|
||||
currentLocals.remove();
|
||||
|
||||
ConfiguredStructureFeature<?, ?> sf = this.featureMap.get(locals.structurePiece());
|
||||
if (sf == null /* WTF */ || !(sf.config instanceof AdvancedStructurePoolFeatureConfig && ((AdvancedStructurePoolFeatureConfig) sf.config).useBoxBeardifier))
|
||||
return getStructureWeight(l, m, n);
|
||||
|
||||
int q = Math.max(0, Math.max(-m, locals.y() - locals.boundingBox().getMaxY()));
|
||||
|
||||
return getAncientCityBeardContribution(l, q, n, m);
|
||||
}
|
||||
|
||||
private static double getAncientCityBeardContribution(int i, int j, int k, int l) {
|
||||
int m = i + 12;
|
||||
int n = j + 12;
|
||||
int o = k + 12;
|
||||
if (!(m >= 0 && m < 24 && n >= 0 && n < 24 && o >= 0 && o < 24)) {
|
||||
return 0.0;
|
||||
}
|
||||
double d = (double) l + 0.5;
|
||||
double e = MathHelper.squaredMagnitude(i, d, k);
|
||||
double f = -d * MathHelper.fastInverseSqrt(e / 2.0) / 2.0;
|
||||
return f * (double) computeBeardContribution(o - 12, m - 12, n - 12);
|
||||
}
|
||||
|
||||
private static double computeBeardContribution(int i, double d, int j) {
|
||||
double e = MathHelper.squaredMagnitude(i, d, j);
|
||||
double f = Math.pow(Math.E, -e / 16.0);
|
||||
return f;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
modLoader = "javafml"
|
||||
loaderVersion = "[40,)"
|
||||
#issueTrackerURL = ""
|
||||
license = "AGPL-3.0+ALEC"
|
||||
|
||||
[[mods]]
|
||||
modId = "anvillib"
|
||||
version = "${version}"
|
||||
displayName = "AnvilLib"
|
||||
authors = "LordMZTE, tilera"
|
||||
description = '''
|
||||
AnvilLib library mod
|
||||
'''
|
||||
#logoFile = ""
|
||||
|
||||
[[dependencies.anvillib]]
|
||||
modId = "forge"
|
||||
mandatory = true
|
||||
versionRange = "[40,)"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
|
||||
[[dependencies.anvillib]]
|
||||
modId = "minecraft"
|
||||
mandatory = true
|
||||
versionRange = "[1.18.2]"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
|
||||
[[dependencies.anvillib]]
|
||||
modId = "geckolib3"
|
||||
mandatory = true
|
||||
versionRange = "[3.0.57,)"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.anvilcraft.anvillib.mixin.forge",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"minVersion": "0.8",
|
||||
"client": [
|
||||
"accessor.AddLayersAccessor"
|
||||
],
|
||||
"mixins": [
|
||||
"common.BeardifierMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
# Done to increase the memory available to gradle.
|
||||
org.gradle.jvmargs=-Xmx2G
|
||||
|
||||
minecraft_version=1.18.2
|
||||
enabled_platforms=fabric,forge
|
||||
|
||||
#architectury_version=4.11.93
|
||||
fabric_loader_version=0.14.23
|
||||
fabric_api_version=0.76.0+1.18.2
|
||||
forge_version=1.18.2-40.2.10
|
||||
|
||||
mod_version=1.1.0
|
||||
maven_group=net.anvilcraft
|
||||
archives_base_name=anvillib-18
|
||||
mod_id=anvillib
|
||||
mod_author=LordMZTE, (tilera)
|
78
gradle/scripts/mixins.gradle
Normal file
78
gradle/scripts/mixins.gradle
Normal file
|
@ -0,0 +1,78 @@
|
|||
abstract class MixinTask extends DefaultTask {
|
||||
|
||||
@Input
|
||||
abstract Property<String> getMixinRefMapName()
|
||||
|
||||
private File mixinSrg
|
||||
private File mixinRefMap
|
||||
|
||||
MixinTask() {
|
||||
mixinRefMapName.convention("mixin.${project.name.replaceAll('[_\\-.]', '').toLowerCase()}.refmap.json")
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void action() {
|
||||
def mixinDir = new File(project.buildDir, 'mixins')
|
||||
if (!mixinDir.exists()) {
|
||||
mixinDir.mkdirs()
|
||||
}
|
||||
def srgFile = new File(project.buildDir, 'srgs/mcp-srg.srg')
|
||||
mixinSrg = new File(mixinDir, "${mixinRefMapName.get()}.srg")
|
||||
mixinRefMap = new File(mixinDir, mixinRefMapName.get())
|
||||
|
||||
if (!mixinSrg.exists()) {
|
||||
mixinSrg.createNewFile()
|
||||
}
|
||||
|
||||
project.tasks.reobf.configure {
|
||||
addExtraSrgFile mixinSrg
|
||||
}
|
||||
|
||||
def compileJava = project.tasks.compileJava
|
||||
compileJava.configure {
|
||||
options.compilerArgs += [
|
||||
'-Xlint:-processing',
|
||||
"-AoutSrgFile=${mixinSrg.canonicalPath}",
|
||||
"-AoutRefMapFile=${mixinRefMap.canonicalPath}",
|
||||
"-AreobfSrgFile=${srgFile.canonicalPath}"
|
||||
]
|
||||
}
|
||||
|
||||
project.tasks.jar.configure {
|
||||
from mixinRefMap
|
||||
}
|
||||
}
|
||||
|
||||
@Internal
|
||||
File getMixinSrg() {
|
||||
return mixinSrg
|
||||
}
|
||||
|
||||
@Internal
|
||||
File getMixinRefMap() {
|
||||
return mixinRefMap
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('mixin', MixinTask)
|
||||
|
||||
task copySrgs(type: Copy, dependsOn: 'genSrgs') {
|
||||
from plugins.getPlugin('forge').delayedFile('{SRG_DIR}')
|
||||
include '**/*.srg'
|
||||
into layout.buildDirectory.file('srgs')
|
||||
}
|
||||
|
||||
compileJava.dependsOn(copySrgs, mixin)
|
||||
tasks.findByPath(":prepareKotlinBuildScriptModel")?.dependsOn(copySrgs, mixin)
|
||||
|
||||
processResources {
|
||||
afterEvaluate {
|
||||
def refmap = tasks.mixin.mixinRefMapName.get()
|
||||
inputs.property 'mixin_refmap', refmap
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include '*.json'
|
||||
expand 'mixin_refmap': refmap
|
||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
}
|
||||
}
|
||||
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
#Wed Jul 02 15:54:47 CDT 2014
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
pluginManagement {
|
||||
repositories {
|
||||
maven { url "https://maven.fabricmc.net/" }
|
||||
maven { url "https://maven.architectury.dev/" }
|
||||
maven { url "https://maven.minecraftforge.net/" }
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
include("common")
|
||||
include("fabric")
|
||||
include("forge")
|
||||
|
||||
rootProject.name = "anvillib"
|
Loading…
Reference in a new issue