diff --git a/build.gradle b/build.gradle index 011172408..7427a363a 100644 --- a/build.gradle +++ b/build.gradle @@ -128,6 +128,12 @@ allprojects { compileOnly metaLibs.bundles.devAnnotations } + + //Fixes Crash with duplicate QuiltLoader and FAPI + project.configurations.configureEach { + exclude(group: "net.fabricmc", module: "fabric-loader") + exclude(group: "net.fabricmc.fabric-api") + } } chenille { @@ -183,7 +189,8 @@ dependencies { // modLocalRuntime compatLibs.biomeMakeover modCompileOnly (compatLibs.trinkets) { transitive = false } // modLocalRuntime compatLibs.trinkets - modCompileOnly (compatLibs.pehkui) { transitive = false } + //Doesn't resolve it because Curseforge's Maven times out + //modCompileOnly (compatLibs.pehkui) { transitive = true } // modApi (compatLibs.pehkui) { transitive = false } modCompileOnly (compatLibs.snowmercy) { transitive = false } @@ -219,6 +226,14 @@ dependencies { remapJar.dependsOn(project(":requiem-core").tasks.remapJar) +loom { + mods { + "requiem" { + accessWidenerPath = file("src/main/resources/requiem.accesswidener") + } + } +} + jar { from 'LICENSE-CODE' from 'LICENSE-ART' diff --git a/gradle.properties b/gradle.properties index 7fad92cbd..2ee85b1dd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,7 @@ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs = -Xmx4G +org.gradle.parallel=false # Base properties mod_version = 2.0.0-beta.17 diff --git a/gradle/compat-libs.versions.toml b/gradle/compat-libs.versions.toml index 63061d180..4af1edaad 100644 --- a/gradle/compat-libs.versions.toml +++ b/gradle/compat-libs.versions.toml @@ -51,6 +51,8 @@ mobz = { group = "curse.maven", name = "mobz-336554", versi omegaConfig = { group = "com.github.Draylar.omega-config", name = "omega-config-base", version.ref = "omegaConfig" } origins = { group = "maven.modrinth", name = "origins", version.ref = "origins" } patchouli = { group = "vazkii.patchouli", name = "Patchouli", version.ref = "patchouli" } +# The version from Github didn't compile because it couldn't find KanosConfig. According to Jitpack's log, it made a GET request to the Curseforge Maven which was answered with 522: Connection timed out TODO: by:Redfan2: Investigate Pehkui +#pehkui = { module= "maven.modrinth:pehkui", version.ref = "pehkui" } pehkui = { module= "com.github.Virtuoel:Pehkui", version.ref = "pehkui" } kano_config = { module= "com.github.Virtuoel:KanosConfig", version.ref = "kano"} snowmercy = { module = "io.github.ladysnake:Snow-Mercy", version.ref = "snowmercy" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0d1842103..e1adfb493 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/requiem-api/src/main/resources/quilt.mod.json b/requiem-api/src/main/resources/quilt.mod.json index 28d49ceed..0aa964c93 100644 --- a/requiem-api/src/main/resources/quilt.mod.json +++ b/requiem-api/src/main/resources/quilt.mod.json @@ -60,6 +60,7 @@ "requiem:soul_holder", "requiem:charged_jump", "requiem:rift_tracker", - "requiem:dropped_vessel_tracker" + "requiem:dropped_vessel_tracker", + "requiem:warden_sensed" ] } diff --git a/src/main/java/ladysnake/requiem/client/RequiemClient.java b/src/main/java/ladysnake/requiem/client/RequiemClient.java index 0f96fa717..c9f824415 100644 --- a/src/main/java/ladysnake/requiem/client/RequiemClient.java +++ b/src/main/java/ladysnake/requiem/client/RequiemClient.java @@ -42,6 +42,7 @@ import ladysnake.requiem.client.particle.CureParticle; import ladysnake.requiem.client.particle.EntityDustParticle; import ladysnake.requiem.client.particle.GhostParticle; +import ladysnake.requiem.client.particle.SoundParticle; import ladysnake.requiem.client.particle.wisp.WispTrailParticle; import ladysnake.requiem.client.render.block.RunestoneBlockEntityRenderer; import ladysnake.requiem.client.render.entity.CuredPiglinEntityRenderer; @@ -193,6 +194,7 @@ private void registerParticleFactories() { registry.register(RequiemParticleTypes.OBELISK_SOUL, SoulParticle.Factory::new); registry.register(RequiemParticleTypes.SOUL_TRAIL, WispTrailParticle.Factory::new); registry.register(RequiemParticleTypes.PENANCE, SpellParticle.EntityFactory::new); + registry.register(RequiemParticleTypes.SOUND, SoundParticle.Factory::new); } private void registerModelPredicates() { diff --git a/src/main/java/ladysnake/requiem/client/RequiemClientListener.java b/src/main/java/ladysnake/requiem/client/RequiemClientListener.java index d017a5acd..1ccb124c7 100644 --- a/src/main/java/ladysnake/requiem/client/RequiemClientListener.java +++ b/src/main/java/ladysnake/requiem/client/RequiemClientListener.java @@ -64,6 +64,7 @@ import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.ShulkerEntity; import net.minecraft.entity.mob.WitchEntity; +import net.minecraft.entity.mob.warden.WardenEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.BowItem; import net.minecraft.item.CrossbowItem; diff --git a/src/main/java/ladysnake/requiem/client/RequiemEntityShaderPicker.java b/src/main/java/ladysnake/requiem/client/RequiemEntityShaderPicker.java index 255bc94cd..17b02da49 100644 --- a/src/main/java/ladysnake/requiem/client/RequiemEntityShaderPicker.java +++ b/src/main/java/ladysnake/requiem/client/RequiemEntityShaderPicker.java @@ -43,6 +43,7 @@ import net.minecraft.client.gl.ShaderEffect; import net.minecraft.entity.Entity; import net.minecraft.entity.mob.WaterCreatureEntity; +import net.minecraft.entity.mob.warden.WardenEntity; import net.minecraft.entity.passive.BeeEntity; import net.minecraft.entity.passive.DolphinEntity; import net.minecraft.entity.passive.MooshroomEntity; @@ -64,6 +65,7 @@ public final class RequiemEntityShaderPicker implements PickEntityShaderCallback public static final Identifier FISH_EYE_SHADER_ID = shader("fish_eye"); public static final Identifier MOOSHROOM_SHADER_ID = shader("mooshroom"); + public static final Identifier WARDEN_SHADER_ID = shader("warden"); public void registerCallbacks() { PickEntityShaderCallback.EVENT.register(this); @@ -91,6 +93,8 @@ public void pickEntityShader(@Nullable Entity camera, Consumer loadS loadShaderFunc.accept(DOLPHIN_SHADER_ID); } else if (camera instanceof WaterCreatureEntity) { loadShaderFunc.accept(FISH_EYE_SHADER_ID); + } else if (camera instanceof WardenEntity) { + loadShaderFunc.accept(WARDEN_SHADER_ID); } } } diff --git a/src/main/java/ladysnake/requiem/client/particle/SoundParticle.java b/src/main/java/ladysnake/requiem/client/particle/SoundParticle.java new file mode 100644 index 000000000..0ce2196d9 --- /dev/null +++ b/src/main/java/ladysnake/requiem/client/particle/SoundParticle.java @@ -0,0 +1,191 @@ +/* + * Requiem + * Copyright (C) 2017-2024 Ladysnake + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Linking this mod statically or dynamically with other + * modules is making a combined work based on this mod. + * Thus, the terms and conditions of the GNU General Public License cover the whole combination. + * + * In addition, as a special exception, the copyright holders of + * this mod give you permission to combine this mod + * with free software programs or libraries that are released under the GNU LGPL + * and with code included in the standard release of Minecraft under All Rights Reserved (or + * modified versions of such code, with unchanged license). + * You may copy and distribute such a system following the terms of the GNU GPL for this mod + * and the licenses of the other code concerned. + * + * Note that people who make modified versions of this mod are not obligated to grant + * this special exception for their modified versions; it is their choice whether to do so. + * The GNU General Public License gives permission to release a modified version without this exception; + * this exception also makes it possible to release a modified version which carries forward this exception. + */ +package ladysnake.requiem.client.particle; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.VertexConsumer; +import ladysnake.requiem.api.v1.possession.PossessionComponent; +import ladysnake.requiem.client.render.RequiemRenderPhases; +import ladysnake.requiem.common.particle.RequiemSoundParticleEffect; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleFactory; +import net.minecraft.client.particle.ParticleTextureSheet; +import net.minecraft.client.particle.SpriteBillboardParticle; +import net.minecraft.client.particle.SpriteProvider; +import net.minecraft.client.render.Camera; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.Axis; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import org.joml.Quaternionf; +import org.joml.Vector3f; +import org.lwjgl.opengl.GL11; +import org.quiltmc.loader.api.minecraft.ClientOnly; + +import java.awt.*; + +public class SoundParticle extends SpriteBillboardParticle { + public final SpriteProvider spriteProvider; + private float red; + private float green; + private float blue; + //private final ParticleTextureSheet sheet; + //TODO: by:Redfan2: think about which VertexConsumer to use to not conflict with Darkness fog effect + private static final VertexConsumerProvider.Immediate soundVertexConsumerProvider = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers(); + //Tessellator.getInstance().getBufferBuilder() + //Doesnt render: Investigate: VertexConsumerProvider.immediate(new BufferBuilder(RequiemRenderPhases.GHOST_PARTICLE_LAYER.getExpectedBufferSize())); + + public SoundParticle(ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ, SpriteProvider spriteProvider, int color) { + super(world, x, y, z, velocityX, velocityY, velocityZ); + this.spriteProvider = spriteProvider; + this.setSpriteForAge(spriteProvider); + //Testing + Color tempColor = Color.BLUE; + this.green = tempColor.getGreen(); + //this.sheet=new TextureSheet(spriteProvider); + //Tessellator.getInstance().getBufferBuilder(). + this.red = tempColor.getRed(); + this.blue = tempColor.getBlue(); + this.maxAge = 10; + this.collidesWithWorld = false; + } + + @Override + public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) { + if (camera.getFocusedEntity() instanceof PlayerEntity player && player.getComponent(PossessionComponent.KEY).isPossessionOngoing()) { + //TODO Disabled for testing if (player.getComponent(PossessionComponent.KEY).getHost() instanceof WardenEntity) { + VertexConsumer actualConsumer = soundVertexConsumerProvider.getBuffer(RequiemRenderPhases.GHOST_PARTICLE_LAYER); + + RenderSystem.disableDepthTest(); + RenderSystem.depthFunc(GL11.GL_ALWAYS); + + + Vec3d vec3d = camera.getPos(); + float f = (float) (MathHelper.lerp(tickDelta, this.prevPosX, this.x) - vec3d.getX()); + float g = (float) (MathHelper.lerp(tickDelta, this.prevPosY, this.y) - vec3d.getY()); + float h = (float) (MathHelper.lerp(tickDelta, this.prevPosZ, this.z) - vec3d.getZ()); + Quaternionf quaternion2; + if (this.angle == 0.0F) { + quaternion2 = camera.getRotation(); + } else { + quaternion2 = new Quaternionf(camera.getRotation()); + float i = MathHelper.lerp(tickDelta, this.prevAngle, this.angle); + hamiltonProduct(quaternion2, Axis.Z_POSITIVE.rotation(i)); + } + + Vector3f Vec3f = new Vector3f(-1.0F, -1.0F, 0.0F); + Vec3f.rotate(quaternion2); + Vector3f[] Vec3fs = new Vector3f[]{new Vector3f(-1.0F, -1.0F, 0.0F), new Vector3f(-1.0F, 1.0F, 0.0F), new Vector3f(1.0F, 1.0F, 0.0F), new Vector3f(1.0F, -1.0F, 0.0F)}; + this.getSize(tickDelta); + + for (int k = 0; k < 4; ++k) { + Vector3f Vec3f2 = Vec3fs[k]; + Vec3f2.rotate(quaternion2); + Vec3f2.mul((float) new Vec3d(this.x, this.y, this.z).distanceTo(camera.getPos()) / 10f); + Vec3f2.add(f, g, h); + } + + float minU = this.getMinU(); + float maxU = this.getMaxU(); + float minV = this.getMinV(); + float maxV = this.getMaxV(); + int l = 15728880; + float alpha = 1; + + actualConsumer.vertex(Vec3fs[0].x(), Vec3fs[0].y(), Vec3fs[0].z()).uv(maxU, maxV).color(red, green, blue, alpha).light(l).next(); + actualConsumer.vertex(Vec3fs[1].x(), Vec3fs[1].y(), Vec3fs[1].z()).uv(maxU, minV).color(red, green, blue, alpha).light(l).next(); + actualConsumer.vertex(Vec3fs[2].x(), Vec3fs[2].y(), Vec3fs[2].z()).uv(minU, minV).color(red, green, blue, alpha).light(l).next(); + actualConsumer.vertex(Vec3fs[3].x(), Vec3fs[3].y(), Vec3fs[3].z()).uv(minU, maxV).color(red, green, blue, alpha).light(l).next(); + + + soundVertexConsumerProvider.draw(); + RenderSystem.enableDepthTest(); + RenderSystem.depthFunc(GL11.GL_LEQUAL); + //} + } else { + this.markDead(); + } + } + + @Override + public ParticleTextureSheet getType() { + return ParticleTextureSheet.CUSTOM; + } + + public void tick() { + this.setSpriteForAge(spriteProvider); + + if (this.age++ > this.maxAge) { + this.markDead(); + } + + this.prevPosX = this.x; + this.prevPosY = this.y; + this.prevPosZ = this.z; + } + + @ClientOnly + public static class Factory implements ParticleFactory { + private final SpriteProvider factorySpriteProvider; + + public Factory(SpriteProvider spriteProvider) { + this.factorySpriteProvider = spriteProvider; + } + + @Override + public Particle createParticle(RequiemSoundParticleEffect particleEffect, ClientWorld clientWorld, double d, double e, double f, double g, double h, double i) { + return new SoundParticle(clientWorld, d, e, f, g, h, i, this.factorySpriteProvider, particleEffect.getColor()); + } + } + + //Stolen using Linkie from Minecraft itself as it doesn't exist on JOML Quaternions + public void hamiltonProduct(Quaternionf first, Quaternionf second) { + float var2 = first.x(); + float var3 = first.y(); + float var4 = first.z(); + float var5 = first.w(); + float var6 = second.x(); + float var7 = second.y(); + float var8 = second.z(); + float var9 = second.w(); + first.x = var5 * var6 + var2 * var9 + var3 * var8 - var4 * var7; + first.y = var5 * var7 - var2 * var8 + var3 * var9 + var4 * var6; + first.z = var5 * var8 + var2 * var7 - var3 * var6 + var4 * var9; + first.w = var5 * var9 - var2 * var6 - var3 * var7 - var4 * var8; + } +} diff --git a/src/main/java/ladysnake/requiem/common/RequiemComponents.java b/src/main/java/ladysnake/requiem/common/RequiemComponents.java index 10efd2dcb..7eb3d46ed 100644 --- a/src/main/java/ladysnake/requiem/common/RequiemComponents.java +++ b/src/main/java/ladysnake/requiem/common/RequiemComponents.java @@ -59,6 +59,7 @@ import ladysnake.requiem.common.entity.cure.SimpleCurableEntityComponent; import ladysnake.requiem.common.entity.effect.PenanceComponent; import ladysnake.requiem.common.entity.effect.StatusEffectReapplicatorImpl; +import ladysnake.requiem.common.entity.warden.WardenSensedComponent; import ladysnake.requiem.common.gamerule.RequiemSyncedGamerules; import ladysnake.requiem.common.possession.LootingPossessedData; import ladysnake.requiem.common.remnant.DroppedVesselTracker; @@ -123,6 +124,7 @@ public void registerEntityComponentFactories(EntityComponentFactoryRegistry regi registry.registerFor(HorseBaseEntity.class, ExternalJumpingMount.KEY, e -> new DummyHorseJumpingMount(e, SoundEvents.ENTITY_HORSE_STEP, getPossessor)); registry.registerForPlayers(RiftTracker.KEY, PlayerRiftTracker::new, RespawnCopyStrategy.ALWAYS_COPY); registry.registerForPlayers(DroppedVesselTracker.KEY, DroppedVesselTracker::new, RespawnCopyStrategy.LOSSLESS_ONLY); + registry.registerForPlayers(WardenSensedComponent.KEY, WardenSensedComponent::new,RespawnCopyStrategy.NEVER_COPY); } @Override diff --git a/src/main/java/ladysnake/requiem/common/entity/internal/WardenExtension.java b/src/main/java/ladysnake/requiem/common/entity/internal/WardenExtension.java new file mode 100644 index 000000000..9e2646d92 --- /dev/null +++ b/src/main/java/ladysnake/requiem/common/entity/internal/WardenExtension.java @@ -0,0 +1,45 @@ +/* + * Requiem + * Copyright (C) 2017-2024 Ladysnake + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Linking this mod statically or dynamically with other + * modules is making a combined work based on this mod. + * Thus, the terms and conditions of the GNU General Public License cover the whole combination. + * + * In addition, as a special exception, the copyright holders of + * this mod give you permission to combine this mod + * with free software programs or libraries that are released under the GNU LGPL + * and with code included in the standard release of Minecraft under All Rights Reserved (or + * modified versions of such code, with unchanged license). + * You may copy and distribute such a system following the terms of the GNU GPL for this mod + * and the licenses of the other code concerned. + * + * Note that people who make modified versions of this mod are not obligated to grant + * this special exception for their modified versions; it is their choice whether to do so. + * The GNU General Public License gives permission to release a modified version without this exception; + * this exception also makes it possible to release a modified version which carries forward this exception. + */ +package ladysnake.requiem.common.entity.internal; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; + +import java.util.Set; + +public interface WardenExtension { + Set requiem$getVisibleEntities(); + Set requiem$getVisiblePlayers(); +} diff --git a/src/main/java/ladysnake/requiem/common/entity/warden/WardenSensedComponent.java b/src/main/java/ladysnake/requiem/common/entity/warden/WardenSensedComponent.java new file mode 100644 index 000000000..0c36f3705 --- /dev/null +++ b/src/main/java/ladysnake/requiem/common/entity/warden/WardenSensedComponent.java @@ -0,0 +1,142 @@ +/* + * Requiem + * Copyright (C) 2017-2024 Ladysnake + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Linking this mod statically or dynamically with other + * modules is making a combined work based on this mod. + * Thus, the terms and conditions of the GNU General Public License cover the whole combination. + * + * In addition, as a special exception, the copyright holders of + * this mod give you permission to combine this mod + * with free software programs or libraries that are released under the GNU LGPL + * and with code included in the standard release of Minecraft under All Rights Reserved (or + * modified versions of such code, with unchanged license). + * You may copy and distribute such a system following the terms of the GNU GPL for this mod + * and the licenses of the other code concerned. + * + * Note that people who make modified versions of this mod are not obligated to grant + * this special exception for their modified versions; it is their choice whether to do so. + * The GNU General Public License gives permission to release a modified version without this exception; + * this exception also makes it possible to release a modified version which carries forward this exception. + */ +package ladysnake.requiem.common.entity.warden; + +import dev.onyxstudios.cca.api.v3.component.ComponentKey; +import dev.onyxstudios.cca.api.v3.component.ComponentRegistry; +import dev.onyxstudios.cca.api.v3.component.TransientComponent; +import dev.onyxstudios.cca.api.v3.component.sync.AutoSyncedComponent; +import ladysnake.requiem.Requiem; +import ladysnake.requiem.api.v1.possession.PossessionComponent; +import ladysnake.requiem.core.RequiemCore; +import net.minecraft.entity.Entity; +import net.minecraft.entity.mob.warden.WardenEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +public class WardenSensedComponent implements TransientComponent, AutoSyncedComponent { + /*TODO proper implementation of syncing + */ + public static final ComponentKey KEY = ComponentRegistry.getOrCreate(RequiemCore.id("warden_sensed"), WardenSensedComponent.class); + + private Set entities; + + public WardenSensedComponent(PlayerEntity livingEntity) { + this.entities = new HashSet<>(); + } + + public Set getVisible() { + return entities; + } + + @Override + public void applySyncPacket(PacketByteBuf buf) { + int size = buf.readInt(); + if (size > 0) { + Set uuids = new HashSet<>(); + for (int i=0; i < size; i++) { + try { + uuids.add(buf.readUuid()); + } catch (Exception error) { + Requiem.LOGGER.error("Could not read element {}","warden_target_"+i ); + Requiem.LOGGER.error("Reason: {}", error.getMessage()); + } + } + this.entities = uuids; + } + } + + @Override + public void writeSyncPacket(PacketByteBuf buf, ServerPlayerEntity recipient) { + + //TODO think about a better data format for this + //MC only seems to have a ByteArray as closest, no UUIDArray or even just StringArray in NBTCompound + buf.writeInt(entities.size()); + for (int i = 0; i < entities.size(); i++) { + buf.writeUuid(entities.stream().toList().get(i)); + } + } + + public WardenSensedComponent setVisibile(Set entities) { + this.entities.addAll(convertToUUID(entities)); + return this; + } + + + @Override + public boolean shouldSyncWith(ServerPlayerEntity player) { + if (PossessionComponent.get(player).isPossessionOngoing() && PossessionComponent.get(player).getHost() instanceof WardenEntity) { + return true; + } else { + return false; + } + } + + public WardenSensedComponent clear() { + this.entities = new HashSet<>(); + return this; + } + + private static Set convertToUUID(Set entities) { + Set idsFromEntities = new HashSet<>(); + entities.forEach(entity -> { + if (entity != null) { + idsFromEntities.add(entity.getUuid()); + } + }); + return idsFromEntities; + } + + public boolean isEmpty() { + return this.entities.isEmpty(); + } + + public boolean isVisibleToWarden(Entity entity) { + return entities.contains(entity.getUuid()); + } + + public void setVisibility(Entity entity, boolean visibile) { + if (visibile && !entities.contains(entity.getUuid())) { + entities.add(entity.getUuid()); + } else { + entities.remove(entity.getUuid()); + } + } +} diff --git a/src/main/java/ladysnake/requiem/common/particle/RequiemParticleTypes.java b/src/main/java/ladysnake/requiem/common/particle/RequiemParticleTypes.java index 1255e59da..7127b5859 100644 --- a/src/main/java/ladysnake/requiem/common/particle/RequiemParticleTypes.java +++ b/src/main/java/ladysnake/requiem/common/particle/RequiemParticleTypes.java @@ -61,6 +61,12 @@ public Codec getCodec() { }; public static final DefaultParticleType OBELISK_SOUL = FabricParticleTypes.simple(false); public static final DefaultParticleType PENANCE = FabricParticleTypes.simple(false); + public static final ParticleType SOUND = new ParticleType<>(false, RequiemSoundParticleEffect.PARAMETERS_FACTORY) { + @Override + public Codec getCodec() { + return RequiemSoundParticleEffect.codec(this); + } + }; public static void init() { Registry.register(Registries.PARTICLE_TYPE, Requiem.id("attrition"), ATTRITION); @@ -71,5 +77,6 @@ public static void init() { Registry.register(Registries.PARTICLE_TYPE, Requiem.id("soul_trail"), SOUL_TRAIL); Registry.register(Registries.PARTICLE_TYPE, Requiem.id("obelisk_soul"), OBELISK_SOUL); Registry.register(Registries.PARTICLE_TYPE, Requiem.id("penance"), PENANCE); + Registry.register(Registries.PARTICLE_TYPE, Requiem.id("sound"), SOUND); } } diff --git a/src/main/java/ladysnake/requiem/common/particle/RequiemSoundParticleEffect.java b/src/main/java/ladysnake/requiem/common/particle/RequiemSoundParticleEffect.java new file mode 100644 index 000000000..b6ca85032 --- /dev/null +++ b/src/main/java/ladysnake/requiem/common/particle/RequiemSoundParticleEffect.java @@ -0,0 +1,95 @@ +/* + * Requiem + * Copyright (C) 2017-2024 Ladysnake + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Linking this mod statically or dynamically with other + * modules is making a combined work based on this mod. + * Thus, the terms and conditions of the GNU General Public License cover the whole combination. + * + * In addition, as a special exception, the copyright holders of + * this mod give you permission to combine this mod + * with free software programs or libraries that are released under the GNU LGPL + * and with code included in the standard release of Minecraft under All Rights Reserved (or + * modified versions of such code, with unchanged license). + * You may copy and distribute such a system following the terms of the GNU GPL for this mod + * and the licenses of the other code concerned. + * + * Note that people who make modified versions of this mod are not obligated to grant + * this special exception for their modified versions; it is their choice whether to do so. + * The GNU General Public License gives permission to release a modified version without this exception; + * this exception also makes it possible to release a modified version which carries forward this exception. + */ +package ladysnake.requiem.common.particle; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleType; +import net.minecraft.registry.Registries; + + +public class RequiemSoundParticleEffect implements ParticleEffect { + public RequiemSoundParticleEffect(ParticleType type, int color) { + this.type = type; + this.color = color; + } + + public int color; + private final ParticleType type; + + + public static final Factory PARAMETERS_FACTORY = new Factory<>() { + @Override + public RequiemSoundParticleEffect read(ParticleType particleType, StringReader stringReader) throws CommandSyntaxException { + stringReader.expect(' '); + int color = stringReader.readInt(); + return new RequiemSoundParticleEffect(particleType, color); + } + + @Override + public RequiemSoundParticleEffect read(ParticleType particleType, PacketByteBuf buf) { + return new RequiemSoundParticleEffect(particleType, buf.readInt()); + } + }; + + @Override + public void write(PacketByteBuf buf) { + buf.writeInt(color); + } + + @Override + public String asString() { + return "%s %d".formatted(Registries.PARTICLE_TYPE.getId(this.getType()), this.color); + } + + @Override + public ParticleType getType() { + return this.type; + } + + public int getColor() { + return this.color; + } + + public static Codec codec(ParticleType particleType) { + return RecordCodecBuilder.create(instance -> instance.group( + Codec.INT.fieldOf("color").forGetter(RequiemSoundParticleEffect::getColor) + ).apply(instance, color -> new RequiemSoundParticleEffect(particleType, color))); + } +} diff --git a/src/main/java/ladysnake/requiem/mixin/client/possession/EntityRenderDispatcherMixin.java b/src/main/java/ladysnake/requiem/mixin/client/possession/EntityRenderDispatcherMixin.java index b5130eeee..7ac79d835 100644 --- a/src/main/java/ladysnake/requiem/mixin/client/possession/EntityRenderDispatcherMixin.java +++ b/src/main/java/ladysnake/requiem/mixin/client/possession/EntityRenderDispatcherMixin.java @@ -37,17 +37,22 @@ import ladysnake.requiem.api.v1.event.requiem.client.RenderSelfPossessedEntityCallback; import ladysnake.requiem.api.v1.possession.PossessionComponent; import ladysnake.requiem.api.v1.remnant.RemnantComponent; +import ladysnake.requiem.common.entity.warden.WardenSensedComponent; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.render.Camera; import net.minecraft.client.render.Frustum; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.entity.EntityRenderDispatcher; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; +import net.minecraft.entity.mob.warden.WardenEntity; import net.minecraft.world.World; import net.minecraft.world.WorldView; +import org.spongepowered.asm.mixin.Debug; 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; @@ -55,11 +60,15 @@ import javax.annotation.Nullable; +@Debug(export=true) @Mixin(EntityRenderDispatcher.class) public abstract class EntityRenderDispatcherMixin { @Shadow public Camera camera; + @Unique @Nullable + /* + The entity the camera belongs to, or the possessed entity*/ private Entity requiem_camerasPossessed; /** @@ -90,4 +99,27 @@ private static void preventShadowRender(MatrixStack matrices, VertexConsumerProv ci.cancel(); } } + + @Inject(method = "shouldRender(Lnet/minecraft/entity/Entity;Lnet/minecraft/client/render/Frustum;DDD)Z", at = @At("HEAD"), cancellable = true) + public void notRenderNonDetectedByWarden(Entity entity, Frustum frustum, double x, double y, double z, CallbackInfoReturnable info) { + + /**/if (entity instanceof WardenEntity) { + //TODO: by:Redfan2: Fix posessed warden itself not rendering + info.setReturnValue(true); + } + + ClientPlayerEntity player = MinecraftClient.getInstance().player; + + if (requiem_camerasPossessed != null) { + //Check for posession + if (requiem_camerasPossessed instanceof WardenEntity) { + + if (!player.getComponent(WardenSensedComponent.KEY).isVisibleToWarden(entity)) { + info.setReturnValue(false); + + } + } + } + + } } diff --git a/src/main/java/ladysnake/requiem/mixin/client/possession/nightvision/BackgroundRendererMixin.java b/src/main/java/ladysnake/requiem/mixin/client/possession/nightvision/BackgroundRendererMixin.java index 8e9fe32c8..913375b68 100644 --- a/src/main/java/ladysnake/requiem/mixin/client/possession/nightvision/BackgroundRendererMixin.java +++ b/src/main/java/ladysnake/requiem/mixin/client/possession/nightvision/BackgroundRendererMixin.java @@ -39,6 +39,7 @@ import net.minecraft.client.render.Camera; import net.minecraft.client.world.ClientWorld; import org.objectweb.asm.Opcodes; +import org.quiltmc.loader.api.minecraft.ClientOnly; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -46,6 +47,7 @@ import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +@ClientOnly @Mixin(BackgroundRenderer.class) public abstract class BackgroundRendererMixin { @Shadow diff --git a/src/main/java/ladysnake/requiem/mixin/client/possession/wardenvision/BackgroundRendererMixin.java b/src/main/java/ladysnake/requiem/mixin/client/possession/wardenvision/BackgroundRendererMixin.java new file mode 100644 index 000000000..610301f14 --- /dev/null +++ b/src/main/java/ladysnake/requiem/mixin/client/possession/wardenvision/BackgroundRendererMixin.java @@ -0,0 +1,106 @@ +/* + * Requiem + * Copyright (C) 2017-2024 Ladysnake + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Linking this mod statically or dynamically with other + * modules is making a combined work based on this mod. + * Thus, the terms and conditions of the GNU General Public License cover the whole combination. + * + * In addition, as a special exception, the copyright holders of + * this mod give you permission to combine this mod + * with free software programs or libraries that are released under the GNU LGPL + * and with code included in the standard release of Minecraft under All Rights Reserved (or + * modified versions of such code, with unchanged license). + * You may copy and distribute such a system following the terms of the GNU GPL for this mod + * and the licenses of the other code concerned. + * + * Note that people who make modified versions of this mod are not obligated to grant + * this special exception for their modified versions; it is their choice whether to do so. + * The GNU General Public License gives permission to release a modified version without this exception; + * this exception also makes it possible to release a modified version which carries forward this exception. + */ +package ladysnake.requiem.mixin.client.possession.wardenvision; + +import com.mojang.blaze3d.systems.RenderSystem; +import ladysnake.requiem.api.v1.possession.PossessedData; +import ladysnake.requiem.api.v1.possession.PossessionComponent; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.render.BackgroundRenderer; +import net.minecraft.client.render.Camera; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.mob.warden.WardenEntity; +import net.minecraft.util.math.MathHelper; +import org.quiltmc.loader.api.minecraft.ClientOnly; +import org.spongepowered.asm.mixin.Debug; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Debug(export = true) +@Environment(EnvType.CLIENT) +@Mixin(BackgroundRenderer.class) +public abstract class BackgroundRendererMixin { + + /**The problem: + * I think we should give the Warden the Darkness status effect when he is posessed by a Player. This would also imply us removing the effect after the posession has ended. Can we solve this simpler using a Mixin into the BackgroundRenderer? + * If you know a good way to do this, let me know. I have had a look but couldn't come up with a solution without redirecting "Lnet/minecraft/client/render/BackgroundRenderer$FogEffect;fadeAsEffectWearsOff(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/entity/effect/StatusEffectInstance;FF)F" on line 153 inside render(), + * I am also unsure if it is a good idea to try to emulate the actions that are done on the FogEffect retrieved from the entity, meaning I am unsure if we should set the Fog Distances ourselves + * @see net.minecraft.client.render.BackgroundRenderer#render(Camera, float, ClientWorld, int, float) + * */ + @Unique + private static final StatusEffectInstance EFFECT = new StatusEffectInstance(StatusEffects.DARKNESS,1,1); + + //Some stuff I thought about for potentially solving this + @Redirect( + at=@At( + value = "INVOKE", + target = "Lnet/minecraft/client/render/BackgroundRenderer$FogEffect;fadeAsEffectWearsOff(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/entity/effect/StatusEffectInstance;FF)F" + ), + method = "render" + ) + private static float requiem$renderWardenDarkness(BackgroundRenderer.FogEffect fogEffect, LivingEntity entity, StatusEffectInstance effect, float horizonShading, float tickDelta) { + if (entity instanceof WardenEntity) { + return fogEffect.fadeAsEffectWearsOff(entity, EFFECT, horizonShading, 0.5f); + } + + return fogEffect.fadeAsEffectWearsOff(entity, entity.getStatusEffect(StatusEffects.DARKNESS), horizonShading, tickDelta); + } + + //This method by itself is useless as it is checked multiple other times whether the entity really has the needed StatusEffect + @Inject(at=@At("HEAD"), method = "findFogEffect(Lnet/minecraft/entity/Entity;F)Lnet/minecraft/client/render/BackgroundRenderer$FogEffect;", cancellable = true) + private static void requiem$findDarknessFogEffect(Entity entity, float tickDelta, CallbackInfoReturnable cir) { + if (entity instanceof WardenEntity) { + + //TODO: by:Redfan2: We do have a AccessWidener for it, why doesn't it work????? + //cir.setReturnValue(new BackgroundRenderer.DarknessFogEffect()); + + //Temporary solution while testing + cir.setReturnValue(BackgroundRenderer.FOG_EFFECTS.stream().filter(BackgroundRenderer.DarknessFogEffect.class::isInstance).toList().get(0)); + + } + } + + +} diff --git a/src/main/java/ladysnake/requiem/mixin/client/possession/wardenvision/MinecraftClientMixin.java b/src/main/java/ladysnake/requiem/mixin/client/possession/wardenvision/MinecraftClientMixin.java new file mode 100644 index 000000000..180b23027 --- /dev/null +++ b/src/main/java/ladysnake/requiem/mixin/client/possession/wardenvision/MinecraftClientMixin.java @@ -0,0 +1,61 @@ +/* + * Requiem + * Copyright (C) 2017-2024 Ladysnake + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Linking this mod statically or dynamically with other + * modules is making a combined work based on this mod. + * Thus, the terms and conditions of the GNU General Public License cover the whole combination. + * + * In addition, as a special exception, the copyright holders of + * this mod give you permission to combine this mod + * with free software programs or libraries that are released under the GNU LGPL + * and with code included in the standard release of Minecraft under All Rights Reserved (or + * modified versions of such code, with unchanged license). + * You may copy and distribute such a system following the terms of the GNU GPL for this mod + * and the licenses of the other code concerned. + * + * Note that people who make modified versions of this mod are not obligated to grant + * this special exception for their modified versions; it is their choice whether to do so. + * The GNU General Public License gives permission to release a modified version without this exception; + * this exception also makes it possible to release a modified version which carries forward this exception. + */ +package ladysnake.requiem.mixin.client.possession.wardenvision; + +import ladysnake.requiem.common.entity.warden.WardenSensedComponent; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.entity.Entity; +import org.jetbrains.annotations.Nullable; +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.CallbackInfoReturnable; + +@Mixin(MinecraftClient.class) +public class MinecraftClientMixin { + + @Shadow + @Nullable + public ClientPlayerEntity player; + + @Inject(at=@At("HEAD"), method= "hasOutline(Lnet/minecraft/entity/Entity;)Z", cancellable = true) + public void hasOutline(Entity entity, CallbackInfoReturnable cir) { + if (player.getComponent(WardenSensedComponent.KEY).isVisibleToWarden(entity)) { + cir.setReturnValue(true); + } + } +} diff --git a/src/main/java/ladysnake/requiem/mixin/common/possession/gameplay/ServerWorldMixin.java b/src/main/java/ladysnake/requiem/mixin/common/possession/gameplay/ServerWorldMixin.java new file mode 100644 index 000000000..a6e4603f9 --- /dev/null +++ b/src/main/java/ladysnake/requiem/mixin/common/possession/gameplay/ServerWorldMixin.java @@ -0,0 +1,103 @@ +/* + * Requiem + * Copyright (C) 2017-2024 Ladysnake + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Linking this mod statically or dynamically with other + * modules is making a combined work based on this mod. + * Thus, the terms and conditions of the GNU General Public License cover the whole combination. + * + * In addition, as a special exception, the copyright holders of + * this mod give you permission to combine this mod + * with free software programs or libraries that are released under the GNU LGPL + * and with code included in the standard release of Minecraft under All Rights Reserved (or + * modified versions of such code, with unchanged license). + * You may copy and distribute such a system following the terms of the GNU GPL for this mod + * and the licenses of the other code concerned. + * + * Note that people who make modified versions of this mod are not obligated to grant + * this special exception for their modified versions; it is their choice whether to do so. + * The GNU General Public License gives permission to release a modified version without this exception; + * this exception also makes it possible to release a modified version which carries forward this exception. + */ +package ladysnake.requiem.mixin.common.possession.gameplay; + +import ladysnake.requiem.Requiem; +import ladysnake.requiem.api.v1.possession.PossessionComponent; +import ladysnake.requiem.common.particle.RequiemParticleTypes; +import ladysnake.requiem.common.particle.RequiemSoundParticleEffect; +import net.minecraft.entity.mob.warden.WardenEntity; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.s2c.play.ParticleS2CPacket; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.tag.GameEventTags; +import net.minecraft.registry.tag.TagKey; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.event.GameEvent; +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 java.awt.*; +import java.util.List; + +@Mixin(ServerWorld.class) +public abstract class ServerWorldMixin { + + @Shadow + public abstract boolean sendToPlayerIfNearby(ServerPlayerEntity player, boolean force, double x, double y, double z, Packet packet); + + @Shadow + public abstract List getPlayers(); + + @Inject(method = "emitGameEvent(Lnet/minecraft/world/event/GameEvent;Lnet/minecraft/util/math/Vec3d;Lnet/minecraft/world/event/GameEvent$Context;)V",at=@At("HEAD")) + public void emitGameEvent(GameEvent event, Vec3d pos, GameEvent.Context context, CallbackInfo ci) { + if (event.isIn(GameEventTags.WARDEN_CAN_SENSE)) { + //TODO: by:Redfan2: maybe ask Tags for Color + + //Fallback + Color color = Color.white; + + if (event.isIn(TagKey.of(RegistryKeys.GAME_EVENT, new Identifier(Requiem.MOD_ID,"blocks")))) { + color = Color.green; + } + if (event.isIn(TagKey.of(RegistryKeys.GAME_EVENT,new Identifier(Requiem.MOD_ID,"entities")))) { + color = Color.cyan; + } + Packet packet = new ParticleS2CPacket( + new RequiemSoundParticleEffect(RequiemParticleTypes.SOUND, color.getRGB()), + true, + pos.getX() + .5f, + pos.getY() + .5f, + pos.getZ() + .5f, + 0, + 0, + 0, + 0, + 1 + ); + for (ServerPlayerEntity player : this.getPlayers()) { + if (PossessionComponent.get(player).isPossessionOngoing() && PossessionComponent.getHost(player) instanceof WardenEntity && !(context.sourceEntity() instanceof WardenEntity)) { + this.sendToPlayerIfNearby(player, true, pos.getX(), pos.getY(), pos.getZ(), packet); + } + } + } + } +} diff --git a/src/main/java/ladysnake/requiem/mixin/common/possession/gameplay/WardenMixin.java b/src/main/java/ladysnake/requiem/mixin/common/possession/gameplay/WardenMixin.java new file mode 100644 index 000000000..f505963e8 --- /dev/null +++ b/src/main/java/ladysnake/requiem/mixin/common/possession/gameplay/WardenMixin.java @@ -0,0 +1,129 @@ +/* + * Requiem + * Copyright (C) 2017-2024 Ladysnake + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Linking this mod statically or dynamically with other + * modules is making a combined work based on this mod. + * Thus, the terms and conditions of the GNU General Public License cover the whole combination. + * + * In addition, as a special exception, the copyright holders of + * this mod give you permission to combine this mod + * with free software programs or libraries that are released under the GNU LGPL + * and with code included in the standard release of Minecraft under All Rights Reserved (or + * modified versions of such code, with unchanged license). + * You may copy and distribute such a system following the terms of the GNU GPL for this mod + * and the licenses of the other code concerned. + * + * Note that people who make modified versions of this mod are not obligated to grant + * this special exception for their modified versions; it is their choice whether to do so. + * The GNU General Public License gives permission to release a modified version without this exception; + * this exception also makes it possible to release a modified version which carries forward this exception. + */ +package ladysnake.requiem.mixin.common.possession.gameplay; + +import ladysnake.requiem.common.entity.internal.WardenExtension; +import ladysnake.requiem.common.entity.warden.WardenSensedComponent; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.mob.HostileEntity; +import net.minecraft.entity.mob.warden.WardenEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; +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; + +import java.util.HashSet; +import java.util.Set; + +@Mixin(WardenEntity.class) +public abstract class WardenMixin extends HostileEntity implements WardenExtension { + + @Shadow + public abstract boolean isEnemy(@Nullable Entity entity); + + protected WardenMixin(EntityType entityType, World world) { + super(entityType, world); + } + + + @Unique + @Override + public Set requiem$getVisibleEntities() { + HashSet entities = new java.util.HashSet<>(); + ((WardenEntity)(Object) this).getAngerManager().getSuspects().forEach(entry -> { + if (entry.getSecond() > 0) { + entities.add(((ServerWorld) this.getWorld()).getEntity(entry.getFirst())); + } + }); + + return entities; + } + + @Unique + @Override + public Set requiem$getVisiblePlayers() { + HashSet visiblePlayers = new HashSet<>(); + requiem$getVisibleEntities().forEach(entity->{ + if (entity instanceof PlayerEntity) { + visiblePlayers.add((PlayerEntity) entity); + } + }); + return visiblePlayers; + + } + + @Inject( + method = "mobTick", + at=@At( + value= "TAIL" + ) + ) + public void tickEverySecond(CallbackInfo ci) { + //TODO: by:Redfan2: replace by Mixin + this.addStatusEffect(new StatusEffectInstance(StatusEffects.BLINDNESS,-1,5,false,false,false),this); + if (age % 200 == 0 ) { + this.requiem$syncSensedEntities(); + } + } + + @Unique + public void requiem$syncSensedEntities() { + if (!this.getWorld().isClient()) { + this.getWorld().getPlayers().forEach(player -> { + if (player.getComponent(WardenSensedComponent.KEY).shouldSyncWith((ServerPlayerEntity) player)){ + player.getComponent(WardenSensedComponent.KEY).setVisibile(requiem$getVisibleEntities()); + WardenSensedComponent.KEY.sync(player); + } + }); + } + } + + @Inject(at=@At("TAIL"),method = "increaseAngerAt(Lnet/minecraft/entity/Entity;IZ)V") + public void syncWhenAngerIncreased(Entity entity, int angerLevel, boolean playSound, CallbackInfo ci) { + if (this.isEnemy(entity)) { + this.requiem$syncSensedEntities(); + } + } +} diff --git a/src/main/resources/assets/requiem/particles/sound.json b/src/main/resources/assets/requiem/particles/sound.json new file mode 100644 index 000000000..d55ad5d79 --- /dev/null +++ b/src/main/resources/assets/requiem/particles/sound.json @@ -0,0 +1,12 @@ +{ + "textures": [ + "requiem:sound_0", + "requiem:sound_1", + "requiem:sound_2", + "requiem:sound_3", + "requiem:sound_4", + "requiem:sound_5", + "requiem:sound_6", + "requiem:sound_7" + ] +} diff --git a/src/main/resources/assets/requiem/shaders/post/warden.json b/src/main/resources/assets/requiem/shaders/post/warden.json new file mode 100644 index 000000000..9282238fb --- /dev/null +++ b/src/main/resources/assets/requiem/shaders/post/warden.json @@ -0,0 +1,17 @@ +{ + "targets": [ + "swap" + ], + "passes": [ + { + "name": "requiem:warden", + "intarget": "minecraft:main", + "outtarget": "swap" + }, + { + "name": "blit", + "intarget": "swap", + "outtarget": "minecraft:main" + } + ] +} diff --git a/src/main/resources/assets/requiem/shaders/program/warden.fsh b/src/main/resources/assets/requiem/shaders/program/warden.fsh new file mode 100644 index 000000000..e6dab3566 --- /dev/null +++ b/src/main/resources/assets/requiem/shaders/program/warden.fsh @@ -0,0 +1,191 @@ +#version 150 +// Author: @patriciogv - 2015 +// Tittle: Turbulence + +#ifdef GL_ES +precision mediump float; +#endif + +uniform sampler2D DiffuseSampler; + +uniform vec2 OutSize; +uniform float STime; + +in vec2 texCoord; + +out vec4 fragColor; + +// Simplex 3D Noise +// by Ian McEwan, Ashima Arts +// +vec4 permute(vec4 x){ return mod(((x*34.0)+1.0)*x, 289.0); } +vec4 taylorInvSqrt(vec4 r){ return 1.79284291400159 - 0.85373472095314 * r; } + +float snoise(vec3 v){ + const vec2 C = vec2(1.0/6.0, 1.0/3.0); + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + + // First corner + vec3 i = floor(v + dot(v, C.yyy)); + vec3 x0 = v - i + dot(i, C.xxx); + + // Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min(g.xyz, l.zxy); + vec3 i2 = max(g.xyz, l.zxy); + + // x0 = x0 - 0. + 0.0 * C + vec3 x1 = x0 - i1 + 1.0 * C.xxx; + vec3 x2 = x0 - i2 + 2.0 * C.xxx; + vec3 x3 = x0 - 1. + 3.0 * C.xxx; + + // Permutations + i = mod(i, 289.0); + vec4 p = permute(permute(permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0)) + + i.y + vec4(0.0, i1.y, i2.y, 1.0)) + + i.x + vec4(0.0, i1.x, i2.x, 1.0)); + + // Gradients + // ( N*N points uniformly over a square, mapped onto an octahedron.) + float n_ = 1.0/7.0;// N=7 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z *ns.z);// mod(p,N*N) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_);// mod(j,N) + + vec4 x = x_ *ns.x + ns.yyyy; + vec4 y = y_ *ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4(x.xy, y.xy); + vec4 b1 = vec4(x.zw, y.zw); + + vec4 s0 = floor(b0)*2.0 + 1.0; + vec4 s1 = floor(b1)*2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy; + vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww; + + vec3 p0 = vec3(a0.xy, h.x); + vec3 p1 = vec3(a0.zw, h.y); + vec3 p2 = vec3(a1.xy, h.z); + vec3 p3 = vec3(a1.zw, h.w); + + //Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); + m = m * m; + return 42.0 * dot(m*m, vec4(dot(p0, x0), dot(p1, x1), + dot(p2, x2), dot(p3, x3))); +} + +#define OCTAVES 3 +float turbulence (in vec2 st) { + // Initial values + float value = 0.0; + float amplitude = .5; + float frequency = 0.; + // + // Loop of octaves + for (int i = 0; i < OCTAVES; i++) { + value += amplitude * abs(snoise(vec3(st, STime/10.))); + st *= 2.; + amplitude *= .5; + } + return value; +} + +vec3 desaturate(vec3 color, float f) { + vec3 grayXfer = vec3(0.3, 0.59, 0.11); + vec3 gray = vec3(dot(grayXfer, color)); + return mix(color, gray, f); +} + +mat4 brightnessMatrix(float brightness) +{ + return mat4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + brightness, brightness, brightness, 1); +} + +mat4 contrastMatrix(float contrast) +{ + float t = (1.0 - contrast) / 2.0; + + return mat4(contrast, 0, 0, 0, + 0, contrast, 0, 0, + 0, 0, contrast, 0, + t, t, t, 1); + +} + +mat4 saturationMatrix(float saturation) +{ + vec3 luminance = vec3(0.3086, 0.6094, 0.0820); + + float oneMinusSat = 1.0 - saturation; + + vec3 red = vec3(luminance.x * oneMinusSat); + red+= vec3(saturation, 0, 0); + + vec3 green = vec3(luminance.y * oneMinusSat); + green += vec3(0, saturation, 0); + + vec3 blue = vec3(luminance.z * oneMinusSat); + blue += vec3(0, 0, saturation); + + return mat4(red, 0, + green, 0, + blue, 0, + 0, 0, 0, 1); +} + +void main() { + // vec2 st = gl_FragCoord.xy/OutSize.xy; + // vec3 color = texture(DiffuseSampler, st).rgb; + // st.x *= OutSize.x/OutSize.y; + // + // float t = turbulence(st*5.0); + // color *= 1. - pow(1. - t, 2. /* bigger number = better sight */); + // + // fragColor = vec4(color, 1.0); + + vec2 uv = gl_FragCoord.xy / OutSize.xy; + uv *= 1.0 - uv.yx;//vec2(1.0)- uv.yx; -> 1.-u.yx; Thanks FabriceNeyret ! + float vig = uv.x*uv.y * 50.0;// multiply with sth for intensity + vig = clamp(pow(vig, 0.25), 0., 1.);// change pow for modifying the extend of the vignette + + vec2 st = gl_FragCoord.xy/OutSize.xy; + vec3 color = texture(DiffuseSampler, st).rgb; + + // brighter and desaturated vision + if (!(color.r >= 50./255. && color.r <= 65./255. && color.g >= 205./255. && color.g <= 220./255. && color.b >= 215./255. && color.b <= 230./255.)) { + color *= 3.; + vec3 greyScale = vec3(.5, .5, .5); + color = mix(vec3(dot(color, greyScale)), color, .5); + + st.x *= OutSize.x/OutSize.y; + st = floor(st*100.)/75.; + + float t = turbulence(st*5.); + // float t2 = turbulence(st*10.); + + vec3 overlayColor = t * vec3(0.05, 0.07, 0.09)*5.; + vec3 sculkifiedColor = mix(color, vec3(0.0), clamp(overlayColor.g*10.*(1.-vig), 0., 1.)); + fragColor = vec4(sculkifiedColor, sculkifiedColor); + } else { + fragColor = vec4(color, 1.0); + } +} diff --git a/src/main/resources/assets/requiem/shaders/program/warden.json b/src/main/resources/assets/requiem/shaders/program/warden.json new file mode 100644 index 000000000..208f85def --- /dev/null +++ b/src/main/resources/assets/requiem/shaders/program/warden.json @@ -0,0 +1,59 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha" + }, + "vertex": "blit", + "fragment": "requiem:warden", + "attributes": [ + "Position" + ], + "samplers": [ + { + "name": "DiffuseSampler" + } + ], + "uniforms": [ + { + "name": "ProjMat", + "type": "matrix4x4", + "count": 16, + "values": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "name": "OutSize", + "type": "float", + "count": 2, + "values": [ + 1.0, + 1.0 + ] + }, + { + "name": "STime", + "type": "float", + "count": 1, + "values": [ + 0.0 + ] + } + ] +} diff --git a/src/main/resources/assets/requiem/textures/particle/sound_0.png b/src/main/resources/assets/requiem/textures/particle/sound_0.png new file mode 100644 index 000000000..9ed8a2775 Binary files /dev/null and b/src/main/resources/assets/requiem/textures/particle/sound_0.png differ diff --git a/src/main/resources/assets/requiem/textures/particle/sound_1.png b/src/main/resources/assets/requiem/textures/particle/sound_1.png new file mode 100644 index 000000000..ea0f9e8fb Binary files /dev/null and b/src/main/resources/assets/requiem/textures/particle/sound_1.png differ diff --git a/src/main/resources/assets/requiem/textures/particle/sound_2.png b/src/main/resources/assets/requiem/textures/particle/sound_2.png new file mode 100644 index 000000000..c4010d2ad Binary files /dev/null and b/src/main/resources/assets/requiem/textures/particle/sound_2.png differ diff --git a/src/main/resources/assets/requiem/textures/particle/sound_3.png b/src/main/resources/assets/requiem/textures/particle/sound_3.png new file mode 100644 index 000000000..77005cac4 Binary files /dev/null and b/src/main/resources/assets/requiem/textures/particle/sound_3.png differ diff --git a/src/main/resources/assets/requiem/textures/particle/sound_4.png b/src/main/resources/assets/requiem/textures/particle/sound_4.png new file mode 100644 index 000000000..b2f86c997 Binary files /dev/null and b/src/main/resources/assets/requiem/textures/particle/sound_4.png differ diff --git a/src/main/resources/assets/requiem/textures/particle/sound_5.png b/src/main/resources/assets/requiem/textures/particle/sound_5.png new file mode 100644 index 000000000..43885925f Binary files /dev/null and b/src/main/resources/assets/requiem/textures/particle/sound_5.png differ diff --git a/src/main/resources/assets/requiem/textures/particle/sound_6.png b/src/main/resources/assets/requiem/textures/particle/sound_6.png new file mode 100644 index 000000000..c3ad62e38 Binary files /dev/null and b/src/main/resources/assets/requiem/textures/particle/sound_6.png differ diff --git a/src/main/resources/assets/requiem/textures/particle/sound_7.png b/src/main/resources/assets/requiem/textures/particle/sound_7.png new file mode 100644 index 000000000..f068538ba Binary files /dev/null and b/src/main/resources/assets/requiem/textures/particle/sound_7.png differ diff --git a/src/main/resources/data/requiem/tags/game_events/blocks.json b/src/main/resources/data/requiem/tags/game_events/blocks.json new file mode 100644 index 000000000..67057b923 --- /dev/null +++ b/src/main/resources/data/requiem/tags/game_events/blocks.json @@ -0,0 +1,35 @@ +{ + "values": [ + "minecraft:block_attach", + "minecraft:block_change", + "minecraft:block_close", + "minecraft:block_destroy", + "minecraft:block_detach", + "minecraft:block_open", + "minecraft:block_place", + "minecraft:block_activate", + "minecraft:block_deactivate", + "minecraft:container_close", + "minecraft:container_open", + "minecraft:explode", + "minecraft:fluid_pickup", + "minecraft:fluid_place", + "minecraft:note_block_play", + "minecraft:resonate_1", + "minecraft:resonate_2", + "minecraft:resonate_3", + "minecraft:resonate_4", + "minecraft:resonate_5", + "minecraft:resonate_6", + "minecraft:resonate_7", + "minecraft:resonate_8", + "minecraft:resonate_9", + "minecraft:resonate_10", + "minecraft:resonate_11", + "minecraft:resonate_12", + "minecraft:resonate_13", + "minecraft:resonate_14", + "minecraft:resonate_15", + "minecraft:shriek" + ] +} diff --git a/src/main/resources/data/requiem/tags/game_events/entities.json b/src/main/resources/data/requiem/tags/game_events/entities.json new file mode 100644 index 000000000..a43bf0b30 --- /dev/null +++ b/src/main/resources/data/requiem/tags/game_events/entities.json @@ -0,0 +1,28 @@ +{ + "values": [ + "minecraft:drink", + "minecraft:eat", + "minecraft:elytra_glide", + "minecraft:entity_damage", + "minecraft:entity_die", + "minecraft:entity_dismount", + "minecraft:entity_interact", + "minecraft:entity_mount", + "minecraft:entity_place", + "minecraft:entity_roar", + "minecraft:entity_shake", + "minecraft:equip", + "minecraft:hit_ground", + "minecraft:instrument_play", + "minecraft:item_interact_finish", + "minecraft:lightning_strike", + "minecraft:prime_fuse", + "minecraft:projectile_land", + "minecraft:projectile_shoot", + "minecraft:shear", + "minecraft:splash", + "minecraft:step", + "minecraft:swim", + "minecraft:teleport" + ] +} diff --git a/src/main/resources/mixins.requiem.client.json b/src/main/resources/mixins.requiem.client.json index e04c707d1..34ccc8dbe 100644 --- a/src/main/resources/mixins.requiem.client.json +++ b/src/main/resources/mixins.requiem.client.json @@ -42,5 +42,9 @@ "remnant.MinecraftClientMixin", "remnant.PlayerRendererLayerMixin", "rift.MouseMixin" + ], + "client": [ + "possession.wardenvision.BackgroundRendererMixin", + "possession.wardenvision.MinecraftClientMixin" ] } diff --git a/src/main/resources/mixins.requiem.common.json b/src/main/resources/mixins.requiem.common.json index 80fc7ff75..1a5dfd897 100644 --- a/src/main/resources/mixins.requiem.common.json +++ b/src/main/resources/mixins.requiem.common.json @@ -36,6 +36,8 @@ "inventory.balance.EntityPredicatesEquipableMixin", "opus.LecternBlockEntityMixin", "possession.PlayerManagerMixin", + "possession.gameplay.ServerWorldMixin", + "possession.gameplay.WardenMixin", "possession.gameplay.AbstractPiglinEntityMixin", "possession.gameplay.BatEntityMixin", "possession.gameplay.BlockItemMixin", diff --git a/src/main/resources/requiem.accesswidener b/src/main/resources/requiem.accesswidener new file mode 100644 index 000000000..455602a3e --- /dev/null +++ b/src/main/resources/requiem.accesswidener @@ -0,0 +1,10 @@ +accessWidener v1 named + +accessible method net/minecraft/entity/mob/warden/AngerManager getSuspects ()Ljava/util/List; +accessible class net/minecraft/client/render/BackgroundRenderer$DarknessFogEffect +accessible class net/minecraft/client/render/BackgroundRenderer$FogEffect +accessible class net/minecraft/client/render/BackgroundRenderer$DarknessFogEffect +accessible class net/minecraft/client/render/BackgroundRenderer$FogParameters +accessible field net/minecraft/client/render/BackgroundRenderer$FogParameters fogStart F +accessible field net/minecraft/client/render/BackgroundRenderer$FogParameters fogEnd F +accessible field net/minecraft/client/render/BackgroundRenderer FOG_EFFECTS Ljava/util/List;