diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7a59df --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.gradle +build +resources +run +.idea \ No newline at end of file diff --git a/build.gradle b/build.gradle index 9cba286..6a02bfb 100644 --- a/build.gradle +++ b/build.gradle @@ -11,21 +11,19 @@ base { } repositories { - repositories { - maven { - name = "TerraformersMC" - url = "https://maven.terraformersmc.com/" - } - maven { - name = "Ladysnake Libs" - url = 'https://maven.ladysnake.org/releases' - } - maven { - url "https://cursemaven.com" - } - maven { - url = "https://api.modrinth.com/maven" - } + maven { + name = "TerraformersMC" + url = "https://maven.terraformersmc.com/" + } + maven { + name = "Ladysnake Libs" + url = 'https://maven.ladysnake.org/releases' + } + maven { + url "https://cursemaven.com" + } + maven { + url = "https://api.modrinth.com/maven" } } @@ -43,10 +41,8 @@ dependencies { // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - include modImplementation("dev.onyxstudios.cardinal-components-api:cardinal-components-base:${project.cca_version}") - include modImplementation("dev.onyxstudios.cardinal-components-api:cardinal-components-entity:${project.cca_version}") - include modImplementation("dev.onyxstudios.cardinal-components-api:cardinal-components-world:${project.cca_version}") include modImplementation("dev.emi:trinkets:${project.trinkets_version}") + } processResources { diff --git a/gradle.properties b/gradle.properties index 41c411e..cab31d2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,19 +4,19 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.19.2 -yarn_mappings=1.19.2+build.28 -loader_version=0.16.14 +minecraft_version=1.20.1 +yarn_mappings=1.20.1+build.10 +loader_version=0.16.10 loom_version=1.10-SNAPSHOT # Mod Properties -mod_version=0.1.3-1.19.2 +mod_version=0.1.8-1.20.1 maven_group=net.capozi.demise archives_base_name=demise # Dependencies -fabric_version=0.77.0+1.19.2 -trinkets_version=3.4.1 +fabric_version=0.92.5+1.20.1 +trinkets_version=3.7.2 # Cardinal Components cca_version = 5.0.2 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..1b33c55 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ca025c8 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index f3b75f3..23d15a9 100644 --- a/gradlew +++ b/gradlew @@ -114,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -205,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9b42019..5eed7ee 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/qodana.yaml b/qodana.yaml new file mode 100644 index 0000000..654508c --- /dev/null +++ b/qodana.yaml @@ -0,0 +1,31 @@ +#-------------------------------------------------------------------------------# +# Qodana analysis is configured by qodana.yaml file # +# https://www.jetbrains.com/help/qodana/qodana-yaml.html # +#-------------------------------------------------------------------------------# +version: "1.0" + +#Specify inspection profile for code analysis +profile: + name: qodana.starter + +#Enable inspections +#include: +# - name: + +#Disable inspections +#exclude: +# - name: +# paths: +# - + +projectJDK: "17" #(Applied in CI/CD pipeline) + +#Execute shell command before Qodana execution (Applied in CI/CD pipeline) +#bootstrap: sh ./prepare-qodana.sh + +#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline) +#plugins: +# - id: #(plugin id can be found at https://plugins.jetbrains.com) + +#Specify Qodana linter for analysis (Applied in CI/CD pipeline) +linter: jetbrains/qodana-jvm-community:2025.1 diff --git a/src/main/java/net/capozi/demise/Demise.java b/src/main/java/net/capozi/demise/Demise.java index c1aa188..6c5ba3a 100644 --- a/src/main/java/net/capozi/demise/Demise.java +++ b/src/main/java/net/capozi/demise/Demise.java @@ -1,5 +1,8 @@ package net.capozi.demise; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.capozi.demise.common.GameruleRegistry; import net.capozi.demise.common.entity.EntityTypeRegistry; import net.fabricmc.api.ModInitializer; import net.minecraft.util.Identifier; @@ -9,10 +12,10 @@ public class Demise implements ModInitializer { public static final String MOD_ID = "demise"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - @Override public void onInitialize() { EntityTypeRegistry.register(); + GameruleRegistry.register(); } public static Identifier id(String name) { return Identifier.of(MOD_ID, name); diff --git a/src/main/java/net/capozi/demise/common/entity/EntityTypeRegistry.java b/src/main/java/net/capozi/demise/common/entity/EntityTypeRegistry.java index a7efcc7..6cc6789 100644 --- a/src/main/java/net/capozi/demise/common/entity/EntityTypeRegistry.java +++ b/src/main/java/net/capozi/demise/common/entity/EntityTypeRegistry.java @@ -11,10 +11,7 @@ public class EntityTypeRegistry { //public static final EntityModelLayer PLAYER_REMAINS_MODEL_LAYER = new EntityModelLayer(Grimoire.id("player_remains"), "main"); - public static final EntityType PLAYER_REMAINS_TYPE = Registry.register(Registries.ENTITY_TYPE, - Demise.id("player_remains"), - FabricEntityTypeBuilder.create(SpawnGroup.MISC, PlayerRemainsEntity::new).dimensions(EntityDimensions.changing(0.8f, 0.8f)).build()); - + public static final EntityType PLAYER_REMAINS_TYPE = Registry.register(Registries.ENTITY_TYPE, Demise.id("player_remains"), FabricEntityTypeBuilder.create(SpawnGroup.MISC, PlayerRemainsEntity::new).dimensions(EntityDimensions.changing(0.8f, 0.8f)).build()); public static void register() { FabricDefaultAttributeRegistry.register(PLAYER_REMAINS_TYPE, PlayerRemainsEntity.createAttributes()); } diff --git a/src/main/java/net/capozi/demise/common/entity/PlayerRemainsEntity.java b/src/main/java/net/capozi/demise/common/entity/PlayerRemainsEntity.java index 9e05562..428c523 100644 --- a/src/main/java/net/capozi/demise/common/entity/PlayerRemainsEntity.java +++ b/src/main/java/net/capozi/demise/common/entity/PlayerRemainsEntity.java @@ -1,42 +1,68 @@ package net.capozi.demise.common.entity; +import com.mojang.authlib.GameProfile; +import net.capozi.demise.common.GameruleRegistry; import net.minecraft.entity.*; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.data.DataTracker; +import net.minecraft.entity.data.TrackedData; +import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.vehicle.VehicleInventory; import net.minecraft.inventory.Inventories; import net.minecraft.item.*; import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtHelper; import net.minecraft.screen.GenericContainerScreenHandler; import net.minecraft.screen.ScreenHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; import net.minecraft.util.ActionResult; import net.minecraft.util.Arm; import net.minecraft.util.Hand; import net.minecraft.util.Identifier; import net.minecraft.util.collection.DefaultedList; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -import net.minecraft.world.event.GameEvent; import org.jetbrains.annotations.Nullable; import java.util.Collections; +import java.util.List; public class PlayerRemainsEntity extends LivingEntity implements VehicleInventory { + public PlayerEntity playerFor; private static final int MAX_SIZE = 27*2; // Maximum inventory size private DefaultedList inventory; - - public PlayerRemainsEntity(EntityType entityType, World world) { + protected PlayerRemainsEntity(EntityType entityType, World world) { + super(entityType, world); + this.setInvulnerable(true); + this.inventory = DefaultedList.ofSize(MAX_SIZE, ItemStack.EMPTY); + } + private PlayerRemainsEntity(EntityType entityType, World world, PlayerEntity player) { super(entityType, world); this.setInvulnerable(true); + this.playerFor = player; this.inventory = DefaultedList.ofSize(MAX_SIZE, ItemStack.EMPTY); } + public static PlayerRemainsEntity create(EntityType type, World world, PlayerEntity player) { + return new PlayerRemainsEntity(type, world, player); + } public static DefaultAttributeContainer.Builder createAttributes() { return LivingEntity.createLivingAttributes() .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0f) .add(EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE, 100f) .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 0f); } + + @Override + public boolean isGlowing() { + return true; + } + @Override public void readCustomDataFromNbt(NbtCompound nbt) { super.readCustomDataFromNbt(nbt); @@ -49,10 +75,27 @@ public void writeCustomDataToNbt(NbtCompound nbt) { } @Override public boolean damage(DamageSource source, float amount) { - if(source.getAttacker() instanceof PlayerEntity player) { + if (source.getAttacker() instanceof PlayerEntity player) { if(player.isSneaking()) { if(getEntityWorld().isClient) return true; this.dropInventory(); + this.clearInventory(); + Vec3d center = this.getPos(); + double radius = 10.0; + Box box = new Box( + center.x - radius, center.y - (radius/2), center.z - radius, + center.x + radius, center.y + (radius/2), center.z + radius + ); + List entities = this.getWorld().getEntitiesByClass( + LivingEntity.class, + box, + e -> e.squaredDistanceTo(center) <= radius * radius + ); + for (LivingEntity entity : entities) { + if (entity instanceof ServerPlayerEntity playerEntity) { + playerEntity.closeHandledScreen(); + } + } this.discard(); return true; } @@ -93,6 +136,30 @@ public void addInventoryStack(ItemStack stack) { } } @Override + public void onPlayerCollision(PlayerEntity player) { + if (this.getWorld().isClient) return; + if (!player.getGameProfile().getName().equals(playerFor.getEntityName())) return; + + for (int i = 0; i < inventory.size(); i++) { + if (!player.getInventory().insertStack(inventory.get(i))) { + player.dropItem(inventory.get(i), false); + } else { + this.getWorld().playSound( + null, + player.getX(), + player.getY(), + player.getZ(), + SoundEvents.ENTITY_ITEM_PICKUP, + SoundCategory.PLAYERS, + 0.2F, + (player.getSoundPitch() - player.getSoundPitch()) * 0.7F + 1.0F * 2.0F + ); + } + } + + discard(); + } + @Override public DefaultedList getInventory() { return inventory; } @@ -154,24 +221,18 @@ public ItemStack getEquippedStack(EquipmentSlot slot) { return new ItemStack(Items.AIR); } @Override - public void equipStack(EquipmentSlot slot, ItemStack stack) { - - } + public void equipStack(EquipmentSlot slot, ItemStack stack) {} @Override public Arm getMainArm() { return Arm.RIGHT; } @Override public boolean isPushable() { - return false; + return true; } @Override public boolean isPushedByFluids() { - return false; - } - @Override - protected void initDataTracker() { - super.initDataTracker(); + return true; } //region// No clue // @Override @@ -179,20 +240,9 @@ protected void initDataTracker() { return null; } @Override - public void setLootTableId(@Nullable Identifier lootTableId) { - - } - @Override - public long getLootTableSeed() { - return 0; - } + public void setLootTableId(@Nullable Identifier lootTableId) {} @Override - public void setLootTableSeed(long lootTableSeed) { - - } + public void setLootTableSeed(long lootTableSeed) {} @Override - public void markDirty() { - - } - //endregion + public void markDirty() {} } diff --git a/src/main/java/net/capozi/demise/common/entity/PlayerRemainsEntityRenderer.java b/src/main/java/net/capozi/demise/common/entity/PlayerRemainsEntityRenderer.java index d24117e..ac68d1d 100644 --- a/src/main/java/net/capozi/demise/common/entity/PlayerRemainsEntityRenderer.java +++ b/src/main/java/net/capozi/demise/common/entity/PlayerRemainsEntityRenderer.java @@ -1,5 +1,7 @@ package net.capozi.demise.common.entity; +import com.mojang.authlib.GameProfile; +import net.capozi.demise.common.GameruleRegistry; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; @@ -11,38 +13,37 @@ import net.minecraft.client.render.model.json.ModelTransformationMode; import net.minecraft.client.render.model.json.Transformation; import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtHelper; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Identifier; -import org.joml.Quaternionf; +import net.minecraft.util.math.RotationAxis; +import static java.lang.Math.abs; +import static java.lang.Math.sin; @Environment(EnvType.CLIENT) public class PlayerRemainsEntityRenderer extends LivingEntityRenderer> { public PlayerRemainsEntityRenderer(EntityRendererFactory.Context ctx) { super(ctx, new PlayerRemainsEntityModel<>(), 0.3f); } - + ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer(); @Override public void render(PlayerRemainsEntity entity, float yaw, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumers, int light) { - ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer(); ItemStack stack = new ItemStack(Items.SKELETON_SKULL); - float angle = (entity.getWorld().getTime() + tickDelta) * 2.5f; - BakedModel model = itemRenderer.getModel(stack, entity.getWorld(), null, 0); - Transformation groundTransform = model.getTransformation().ground; - matrixStack.push(); matrixStack.scale(1.5f, 1.5f, 1.5f); - matrixStack.translate(0, 0.25, 0); - matrixStack.translate(0, Math.sin((entity.getWorld().getTime() + tickDelta)*0.1f)*0.1f, 0); - matrixStack.multiply(new Quaternionf().fromAxisAngleDeg(0, 1, 0, angle)); - + matrixStack.translate(0, 0.2, 0); + matrixStack.translate(0, (abs(sin((float)entity.age / 15) + 1) / 7), 0); + matrixStack.multiply(RotationAxis.POSITIVE_Y.rotation((float)entity.age / 20)); itemRenderer.renderItem(stack, ModelTransformationMode.GROUND, false, matrixStack, vertexConsumers, light, 0, itemRenderer.getModel(stack, entity.getWorld(), null, 0)); - matrixStack.pop(); - if(entity.getCustomName() != null) { - this.renderLabelIfPresent(entity, entity.getCustomName(), matrixStack, vertexConsumers, light); - } + if(entity.getCustomName() != null) { + this.renderLabelIfPresent(entity, entity.getCustomName(), matrixStack, vertexConsumers, light); + } } @Override diff --git a/src/main/java/net/capozi/demise/mixin/LivingEntityMixin.java b/src/main/java/net/capozi/demise/mixin/LivingEntityMixin.java index bec9e4e..9b61a0e 100644 --- a/src/main/java/net/capozi/demise/mixin/LivingEntityMixin.java +++ b/src/main/java/net/capozi/demise/mixin/LivingEntityMixin.java @@ -2,14 +2,16 @@ import net.capozi.demise.TrinketsHelper; import net.capozi.demise.common.GameruleRegistry; +import net.capozi.demise.common.TwoHanded; import net.capozi.demise.common.entity.EntityTypeRegistry; import net.capozi.demise.common.entity.PlayerRemainsEntity; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; import net.minecraft.world.GameRules; -import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -18,42 +20,45 @@ @Mixin(LivingEntity.class) public abstract class LivingEntityMixin { - @Shadow - public abstract World getWorld(); - @Inject( - method = "damage", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/entity/LivingEntity;onDeath(Lnet/minecraft/entity/damage/DamageSource;)V" - ) - ) - private void grimoire$onDeath(DamageSource source, float amount, CallbackInfoReturnable cir) { - if (!((Object)this instanceof PlayerEntity player)) return; - if (getWorld().getGameRules().getBoolean(GameruleRegistry.CREATE_GRAVE)) { - if (player.getWorld().getGameRules().getBoolean(GameRules.KEEP_INVENTORY)) return; + @Shadow protected abstract void consumeItem(); - PlayerRemainsEntity remains = new PlayerRemainsEntity(EntityTypeRegistry.PLAYER_REMAINS_TYPE, player.getWorld()); - remains.setPosition(player.getPos()); - remains.resetInventory(); - - player.getInventory().main.forEach(stack -> remains.addInventoryStack(stack.copy())); - player.getInventory().offHand.forEach(stack -> remains.addInventoryStack(stack.copy())); - player.getInventory().armor.forEach(stack -> remains.addInventoryStack(stack.copy())); - - if (getWorld().getGameRules().getBoolean(GameruleRegistry.SAVE_TRINKETS) && - FabricLoader.getInstance().isModLoaded("trinkets")) { - try { - TrinketsHelper.findAllEquippedBy(player).forEach(remains::addInventoryStack); - TrinketsHelper.clearAllEquippedTrinkets(player); - } catch (Exception ignore) {} + @Inject(method = "getOffHandStack", at = @At("HEAD"), cancellable = true) + public void demise$getOffHandStack(CallbackInfoReturnable cir) { + if((LivingEntity)(Object)this instanceof PlayerEntity player) { + if(player.getMainHandStack().getItem() instanceof TwoHanded) cir.setReturnValue(new ItemStack(Items.AIR)); + } + } + @Inject(method = "damage", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;onDeath(Lnet/minecraft/entity/damage/DamageSource;)V")) + private void demise$onDeath(DamageSource source, float amount, CallbackInfoReturnable cir) { + if((Object)this instanceof PlayerEntity player) { + if(!((LivingEntity)(Object)this).getWorld().getGameRules().getBoolean(GameruleRegistry.CREATE_GRAVE)) return; + if(player.getWorld().getGameRules().getBoolean(GameRules.KEEP_INVENTORY)) return; + PlayerRemainsEntity playerRemainsEntity = PlayerRemainsEntity.create(EntityTypeRegistry.PLAYER_REMAINS_TYPE, player.getWorld(), player); + playerRemainsEntity.setPosition(player.getPos()); + playerRemainsEntity.resetInventory(); + for(int i = 0;i=0.16.11", + "fabricloader": ">=0.16.10", "minecraft": "~1.20.1", "java": ">=17", - "fabric-api": "*" + "fabric-api": "*", + "dotzip": ">=1.1.3.1a" }, "suggests": { "another-mod": "*"