diff --git a/.editorconfig b/.editorconfig index 55b4b1307..60828afe7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,3 +6,6 @@ charset = utf-8 indent_style = space indent_size = 4 trim_trailing_whitespace = true + +[*.json] +indent_size = 2 diff --git a/build.gradle b/build.gradle index c299034a4..8f9b599fd 100644 --- a/build.gradle +++ b/build.gradle @@ -10,6 +10,7 @@ plugins { id "net.minecrell.licenser" version "0.4.1" id "com.matthewprenger.cursegradle" version "1.1.2" id "maven-publish" + id "com.wynprice.cursemaven" version "1.2.3" } group = rootProject.maven_group @@ -59,10 +60,6 @@ allprojects { url "http://maven.fabricmc.net/" name "Fabric" } - maven { - url "https://jitpack.io" - name "JitPack" - } } task apiJar(type: Jar, dependsOn: apiClasses) { @@ -95,7 +92,7 @@ allprojects { // Fabric API. This is technically optional, but you probably want it anyway. modApi "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - + // Lazily evaluated callable returning a non-live (unlike a FileCollection) list of files sourceSets.api.compileClasspath += files({sourceSets.main.compileClasspath.toList()}) @@ -138,16 +135,28 @@ allprojects { } } +repositories { + maven { + name = "NerdHubMC" + url = "https://maven.abusedmaster.xyz" + } + maven { + url "https://jitpack.io" + name "JitPack" + } +} + dependencies { - modImplementation("com.github.Ladysnake:Satin:${rootProject.satin_version}") + modApi("com.github.Ladysnake:Satin:${rootProject.satin_version}") include "com.github.Ladysnake:Satin:${satin_version}" modRuntime "io.github.prospector.modmenu:ModMenu:${modmenu_version}" - modApi "com.github.Pyrofab.Cardinal-Components-API:cardinal-components-base:${cca_version}" - include "com.github.Pyrofab.Cardinal-Components-API:cardinal-components-base:${cca_version}" - modImplementation "com.github.Pyrofab.Cardinal-Components-API:cardinal-components-entity:${cca_version}" - include "com.github.Pyrofab.Cardinal-Components-API:cardinal-components-entity:${cca_version}" - modImplementation "com.github.Pyrofab.Cardinal-Components-API:cardinal-components-world:${cca_version}" - include "com.github.Pyrofab.Cardinal-Components-API:cardinal-components-world:${cca_version}" + modApi "com.github.NerdHubMC.Cardinal-Components-API:cardinal-components-base:${cca_version}" + include "com.github.NerdHubMC.Cardinal-Components-API:cardinal-components-base:${cca_version}" + modImplementation "com.github.NerdHubMC.Cardinal-Components-API:cardinal-components-entity:${cca_version}" + include "com.github.NerdHubMC.Cardinal-Components-API:cardinal-components-entity:${cca_version}" + modImplementation "com.github.NerdHubMC.Cardinal-Components-API:cardinal-components-world:${cca_version}" + include "com.github.NerdHubMC.Cardinal-Components-API:cardinal-components-world:${cca_version}" + modImplementation curse.resolve('immersive-portals-mod', 2806496) } jar { @@ -157,4 +166,4 @@ jar { license { exclude "**/RayHelper.java" -} \ No newline at end of file +} diff --git a/changelog.md b/changelog.md index f27dc2c26..c63072deb 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,10 @@ +------------------------------------------------------ +Version 1.0.1 +------------------------------------------------------ +Bug Fixes +- Possessed mobs now raise their arms when attacking or using a bow +- Fixed most incompatibilities with Immersive Portals + ------------------------------------------------------ Version 1.0.0 ------------------------------------------------------ diff --git a/expansions/pandemonium/build.gradle b/expansions/pandemonium/build.gradle index 9d546d22f..5568e5bce 100644 --- a/expansions/pandemonium/build.gradle +++ b/expansions/pandemonium/build.gradle @@ -1,6 +1,5 @@ dependencies { compile rootProject - modImplementation("com.github.Ladysnake:Satin:${rootProject.satin_version}") } jar { diff --git a/gradle.properties b/gradle.properties index 2e77097f8..08c67329d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs = -Xmx5G # Base properties -mod_version = 1.0.0 +mod_version = 1.0.1 maven_group = io.github.Ladysnake #General @@ -15,7 +15,7 @@ loader_version=0.4.8+build.159 fabric_version=0.3.0+build.207 # Minecraft dependencies -cca_version = 2.0.1-pre2 +cca_version = 2.0.3 modmenu_version=1.6.3-95 satin_version = 1.3.2 diff --git a/src/main/java/ladysnake/requiem/Requiem.java b/src/main/java/ladysnake/requiem/Requiem.java index 9f2278313..df10e1ec9 100644 --- a/src/main/java/ladysnake/requiem/Requiem.java +++ b/src/main/java/ladysnake/requiem/Requiem.java @@ -27,19 +27,16 @@ import ladysnake.requiem.common.command.RequiemCommand; import ladysnake.requiem.common.impl.ApiInitializer; import ladysnake.requiem.common.impl.movement.MovementAltererManager; -import ladysnake.requiem.common.impl.remnant.RevivingDeathSuspender; import ladysnake.requiem.common.impl.remnant.dialogue.ReloadableDialogueRegistry; import ladysnake.requiem.common.impl.resurrection.ResurrectionDataLoader; import ladysnake.requiem.common.item.RequiemItems; import ladysnake.requiem.common.network.RequiemNetworking; import ladysnake.requiem.common.network.ServerMessageHandling; import ladysnake.requiem.common.sound.RequiemSoundEvents; -import nerdhub.cardinal.components.api.event.EntityComponentCallback; import nerdhub.cardinal.components.api.event.WorldComponentCallback; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.registry.CommandRegistry; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; import org.apache.logging.log4j.LogManager; @@ -68,7 +65,7 @@ public void onInitialize() { CommandRegistry.INSTANCE.register(false, RequiemCommand::register); this.registerSubDataManagers(); ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(ResurrectionDataLoader.INSTANCE); - EntityComponentCallback.event(PlayerEntity.class).register((player, components) -> components.put(RequiemComponents.DEATH_SUSPENDER, new RevivingDeathSuspender(player))); + RequiemComponents.initComponents(); SyncServerResourcesCallback.EVENT.register(player -> RequiemNetworking.sendTo(player, RequiemNetworking.createDataSyncMessage(SubDataManagerHelper.getServerHelper()))); ApiInitializer.setPluginCallback(this::registerPlugin); } diff --git a/src/main/java/ladysnake/requiem/common/RequiemComponents.java b/src/main/java/ladysnake/requiem/common/RequiemComponents.java index d75b62ae4..e09f799ac 100644 --- a/src/main/java/ladysnake/requiem/common/RequiemComponents.java +++ b/src/main/java/ladysnake/requiem/common/RequiemComponents.java @@ -22,10 +22,13 @@ import ladysnake.requiem.api.v1.remnant.DeathSuspender; import ladysnake.requiem.api.v1.util.SubDataManager; import ladysnake.requiem.common.impl.movement.MovementAltererManager; +import ladysnake.requiem.common.impl.remnant.RevivingDeathSuspender; import nerdhub.cardinal.components.api.ComponentRegistry; import nerdhub.cardinal.components.api.ComponentType; import nerdhub.cardinal.components.api.component.ComponentProvider; +import nerdhub.cardinal.components.api.event.EntityComponentCallback; import nerdhub.cardinal.components.api.util.ObjectPath; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.world.World; public final class RequiemComponents { @@ -46,4 +49,10 @@ public final class RequiemComponents { public static final ComponentType DEATH_SUSPENDER = ComponentRegistry.INSTANCE.registerIfAbsent( Requiem.id("death_suspension"), DeathSuspender.class ); + + public static void initComponents() { + EntityComponentCallback.event(PlayerEntity.class).register((player, components) -> { + components.put(DEATH_SUSPENDER, new RevivingDeathSuspender(player)); + }); + } } diff --git a/src/main/java/ladysnake/requiem/common/entity/ability/MeleeAbility.java b/src/main/java/ladysnake/requiem/common/entity/ability/MeleeAbility.java index c340a04c1..6fdc3ec8d 100644 --- a/src/main/java/ladysnake/requiem/common/entity/ability/MeleeAbility.java +++ b/src/main/java/ladysnake/requiem/common/entity/ability/MeleeAbility.java @@ -40,6 +40,7 @@ public boolean trigger(PlayerEntity player, Entity target) { // We actually need to check if the entity has an attack damage attribute, because mojang doesn't. boolean success = (ignoreDamageAttribute || owner.getAttributeInstance(EntityAttributes.ATTACK_DAMAGE) != null) && owner.tryAttack(target); if (success && target instanceof LivingEntity) { + this.owner.setAttacking(true); player.getMainHandStack().postHit((LivingEntity) target, player); // Reset cooldown player.resetLastAttackedTicks(); diff --git a/src/main/java/ladysnake/requiem/common/impl/possession/PossessionComponentImpl.java b/src/main/java/ladysnake/requiem/common/impl/possession/PossessionComponentImpl.java index 1e8592a9b..9fbe4c2aa 100644 --- a/src/main/java/ladysnake/requiem/common/impl/possession/PossessionComponentImpl.java +++ b/src/main/java/ladysnake/requiem/common/impl/possession/PossessionComponentImpl.java @@ -59,13 +59,11 @@ public final class PossessionComponentImpl implements PossessionComponent { private static final Set attributeUpdated = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap()); private final PlayerEntity player; - @Nullable private UUID possessedUuid; - private int possessedNetworkId; + @Nullable private MobEntity possessed; private int conversionTimer = -1; public PossessionComponentImpl(PlayerEntity player) { this.player = player; - this.possessedNetworkId = -1; } @Override @@ -121,10 +119,9 @@ private void startPossessing0(MobEntity host, Possessable possessable) { } } // Actually set the possessed entity - this.possessedUuid = host.getUuid(); - this.possessedNetworkId = host.getEntityId(); + this.possessed = host; possessable.setPossessor(this.player); - this.syncPossessed(); + this.syncPossessed(host.getEntityId()); // Update some attributes this.player.copyPositionAndRotation(host); this.player.calculateDimensions(); // update size @@ -162,7 +159,6 @@ public void stopPossessing() { public void stopPossessing(boolean transfer) { LivingEntity possessed = this.getPossessedEntity(); if (possessed != null) { - this.possessedUuid = null; this.resetState(); ((Possessable)possessed).setPossessor(null); if (player instanceof ServerPlayerEntity && transfer) { @@ -181,9 +177,9 @@ public void stopPossessing(boolean transfer) { } } - private void syncPossessed() { + private void syncPossessed(int entityId) { if (!this.player.world.isClient) { - sendToAllTrackingIncluding(this.player, createPossessionMessage(this.player.getUuid(), this.possessedNetworkId)); + sendToAllTrackingIncluding(this.player, createPossessionMessage(this.player.getUuid(), entityId)); } } @@ -196,36 +192,28 @@ public MobEntity getPossessedEntity() { if (!isPossessing()) { return null; } - // First attempt: use the network id (client & server) - Entity host = this.player.world.getEntityById(this.possessedNetworkId); - if (host == null) { + + if (this.possessed.removed) { + UUID possessedUuid = this.possessed.getUuid(); + Requiem.LOGGER.debug("{}: this player's possessed entity has disappeared", this.player); + this.resetState(); + // Attempt to find an equivalent entity using the UUID if (this.player.world instanceof ServerWorld) { - // Second attempt: use the UUID (server) - // method_14190 == getEntityByUuid - host = ((ServerWorld)this.player.world).getEntity(this.getPossessedEntityUuid()); - } - // Set the possessed uuid to null to avoid infinite recursion - this.possessedUuid = null; - if (host instanceof MobEntity && host instanceof Possessable) { - this.startPossessing((MobEntity) host); - } else { - if (host != null) { - Requiem.LOGGER.warn("{}: this player's supposedly possessed entity ({}) cannot be possessed!", this.player, host); + Entity host = ((ServerWorld)this.player.world).getEntity(possessedUuid); + if (host instanceof MobEntity && host instanceof Possessable) { + this.startPossessing((MobEntity) host); } - Requiem.LOGGER.debug("{}: this player's possessed entity is nowhere to be found", this); - this.resetState(); - host = null; } } - return (MobEntity) host; + return this.possessed; } private void resetState() { - this.possessedNetworkId = -1; + this.possessed = null; ((RequiemPlayer) this.player).getMovementAlterer().setConfig(((RequiemPlayer)player).asRemnant().isSoul() ? SerializableMovementConfig.SOUL : null); this.player.calculateDimensions(); // update size this.player.setBreath(this.player.getMaxBreath()); - syncPossessed(); + syncPossessed(-1); } /** @@ -233,7 +221,7 @@ private void resetState() { */ @Override public boolean isPossessing() { - return this.possessedUuid != null; + return this.possessed != null; } @Override @@ -262,11 +250,6 @@ public void update() { } } - @CheckForNull - public UUID getPossessedEntityUuid() { - return this.possessedUuid; - } - @Override public CompoundTag toTag(CompoundTag tag) { tag.putInt("conversionTimer", this.conversionTimer); diff --git a/src/main/java/ladysnake/requiem/common/item/DebugItem.java b/src/main/java/ladysnake/requiem/common/item/DebugItem.java index 2563c55ef..dbf6ef212 100644 --- a/src/main/java/ladysnake/requiem/common/item/DebugItem.java +++ b/src/main/java/ladysnake/requiem/common/item/DebugItem.java @@ -38,9 +38,11 @@ public DebugItem(Settings item$Settings_1) { @Override public TypedActionResult use(World world, PlayerEntity player, Hand hand) { - if (player.isSneaking() && !world.isClient) { - debugMode = (debugMode + 1) % 2; - player.addChatMessage(new TranslatableText("Switched mode to %s", debugMode), true); + if (player.isSneaking()) { + if (!world.isClient) { + debugMode = (debugMode + 1) % 2; + player.addChatMessage(new TranslatableText("Switched mode to %s", debugMode), true); + } } else { switch (debugMode) { case 0: diff --git a/src/main/java/ladysnake/requiem/mixin/item/BowItemMixin.java b/src/main/java/ladysnake/requiem/mixin/item/BowItemMixin.java index fcaa56721..956de6cff 100644 --- a/src/main/java/ladysnake/requiem/mixin/item/BowItemMixin.java +++ b/src/main/java/ladysnake/requiem/mixin/item/BowItemMixin.java @@ -22,11 +22,15 @@ import ladysnake.requiem.common.entity.internal.ItemStackConvertible; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.mob.AbstractSkeletonEntity; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.ProjectileEntity; import net.minecraft.item.BowItem; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.RangedWeaponItem; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; import net.minecraft.world.World; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; @@ -34,6 +38,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(BowItem.class) public abstract class BowItemMixin extends RangedWeaponItem { @@ -42,6 +47,14 @@ public BowItemMixin(Item.Settings settings) { super(settings); } + @Inject(method = "use", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;setCurrentHand(Lnet/minecraft/util/Hand;)V")) + private void setAttackingMode(World world, PlayerEntity player, Hand hand, CallbackInfoReturnable> cir) { + MobEntity possessed = RequiemPlayer.from(player).asPossessor().getPossessedEntity(); + if (possessed != null) { + possessed.setAttacking(true); + } + } + @Inject( method = "onStoppedUsing", at = @At( @@ -52,7 +65,11 @@ public BowItemMixin(Item.Settings settings) { ) ) private void setCurrentUser(ItemStack item, World world, LivingEntity user, int charge, CallbackInfo ci) { - REQUIEM__CURRENT_USER.set(((RequiemPlayer) user).asPossessor().getPossessedEntity()); + MobEntity possessed = ((RequiemPlayer) user).asPossessor().getPossessedEntity(); + REQUIEM__CURRENT_USER.set(possessed); + if (possessed != null) { // counterpart to setAttackingMode + possessed.setAttacking(false); + } } @ModifyVariable(method = "onStoppedUsing", ordinal = 0, at = @At("STORE")) diff --git a/src/main/java/ladysnake/requiem/mixin/possession/entity/PossessableLivingEntityMixin.java b/src/main/java/ladysnake/requiem/mixin/possession/entity/PossessableLivingEntityMixin.java index 40d901948..5ae9ce7c3 100644 --- a/src/main/java/ladysnake/requiem/mixin/possession/entity/PossessableLivingEntityMixin.java +++ b/src/main/java/ladysnake/requiem/mixin/possession/entity/PossessableLivingEntityMixin.java @@ -128,7 +128,7 @@ public void setPossessor(@CheckForNull PlayerEntity possessor) { return; } // we need a cast here to trick the compiler - if (this.possessor != null && ((RequiemPlayer) this.possessor).asPossessor().getPossessedEntity() == (Entity)this) { + if (((this.possessor != null) && (((RequiemPlayer) this.possessor).asPossessor().getPossessedEntity() == (Entity) this)) && !this.world.isClient) { throw new IllegalStateException("Players must stop possessing an entity before it can change possessor!"); } this.possessor = possessor; diff --git a/src/main/java/ladysnake/requiem/mixin/possession/entity/PossessableMobEntityMixin.java b/src/main/java/ladysnake/requiem/mixin/possession/entity/PossessableMobEntityMixin.java index ae30abba6..a755205c6 100644 --- a/src/main/java/ladysnake/requiem/mixin/possession/entity/PossessableMobEntityMixin.java +++ b/src/main/java/ladysnake/requiem/mixin/possession/entity/PossessableMobEntityMixin.java @@ -29,6 +29,8 @@ import net.minecraft.item.ItemStack; import net.minecraft.world.World; 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.callback.CallbackInfo; @@ -37,7 +39,16 @@ @Mixin(MobEntity.class) public abstract class PossessableMobEntityMixin extends LivingEntity implements Possessable { + @Shadow + public abstract void setAttacking(boolean boolean_1); + + @Shadow + public abstract boolean isAttacking(); + + @Unique private MobAbilityController abilityController = MobAbilityController.DUMMY; + @Unique + private int attackingCountdown; public PossessableMobEntityMixin(EntityType type, World world) { super(type, world); @@ -55,6 +66,23 @@ public MobAbilityController getMobAbilityController() { return abilityController; } + @Inject(method = "setAttacking", at = @At("RETURN")) + private void resetAttackMode(boolean attacking, CallbackInfo ci) { + if (attacking && this.isBeingPossessed()) { + attackingCountdown = 100; + } + } + + @Inject(method = "tickMovement", at = @At("RETURN")) + private void resetAttackMode(CallbackInfo ci) { + if (this.isAttacking() && !this.isUsingItem() && this.isBeingPossessed()) { + this.attackingCountdown--; + if (this.attackingCountdown == 0) { + this.setAttacking(false); + } + } + } + @Inject(method = "getEquippedStack", at = @At("HEAD"), cancellable = true) private void getEquippedStack(EquipmentSlot slot, CallbackInfoReturnable cir) { PlayerEntity possessor = this.getPossessor(); @@ -70,4 +98,5 @@ private void setEquippedStack(EquipmentSlot slot, ItemStack item, CallbackInfo c possessor.setEquippedStack(slot, item); } } + } diff --git a/src/main/java/ladysnake/requiem/mixin/possession/player/PossessorServerPlayerEntityMixin.java b/src/main/java/ladysnake/requiem/mixin/possession/player/PossessorServerPlayerEntityMixin.java index fa9cd9d71..763e86df2 100644 --- a/src/main/java/ladysnake/requiem/mixin/possession/player/PossessorServerPlayerEntityMixin.java +++ b/src/main/java/ladysnake/requiem/mixin/possession/player/PossessorServerPlayerEntityMixin.java @@ -35,6 +35,7 @@ import net.minecraft.world.World; import net.minecraft.world.dimension.DimensionType; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -90,6 +91,7 @@ public void spawnResurrectionEntity() { } } + @Unique private void setResurrectionEntity(@Nullable CompoundTag serializedSecondLife) { this.requiem_possessedEntityTag = serializedSecondLife; } diff --git a/src/main/resources/mixins.requiem.common.json b/src/main/resources/mixins.requiem.common.json index b2940b086..52ae99b69 100644 --- a/src/main/resources/mixins.requiem.common.json +++ b/src/main/resources/mixins.requiem.common.json @@ -41,4 +41,4 @@ "injectors": { "defaultRequire": 1 } -} \ No newline at end of file +}