-
-
Notifications
You must be signed in to change notification settings - Fork 217
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add highlight and outline feature for rare sea creatures (#439)
Add highlight and outline feature for rare sea creatures #439
- Loading branch information
1 parent
5d2f4ea
commit 6be7873
Showing
13 changed files
with
735 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
118 changes: 118 additions & 0 deletions
118
src/main/java/at/hannibal2/skyhanni/events/RenderEntityOutlineEvent.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package at.hannibal2.skyhanni.events | ||
|
||
import net.minecraft.client.Minecraft | ||
import net.minecraft.entity.Entity | ||
import net.minecraft.entity.item.EntityArmorStand | ||
import net.minecraft.entity.item.EntityItemFrame | ||
import java.util.function.Consumer | ||
|
||
class RenderEntityOutlineEvent(theType: Type?, potentialEntities: HashSet<Entity>?) : | ||
LorenzEvent() { | ||
|
||
/** | ||
* The phase of the event (see [Type] | ||
*/ | ||
var type: Type? = null | ||
|
||
/** | ||
* The entities to outline. This is progressively cumulated from [.entitiesToChooseFrom] | ||
*/ | ||
var entitiesToOutline: HashMap<Entity, Int>? = null | ||
|
||
/** | ||
* The entities we can outline. Note that this set and [.entitiesToOutline] are disjoint at all times. | ||
*/ | ||
var entitiesToChooseFrom: HashSet<Entity>? = null | ||
|
||
/** | ||
* Constructs the event, given the type and optional entities to outline. | ||
* | ||
* | ||
* This will modify {@param potentialEntities} internally, so make a copy before passing it if necessary. | ||
* | ||
* @param theType of the event (see [Type] | ||
*/ | ||
init { | ||
type = theType | ||
entitiesToChooseFrom = potentialEntities | ||
if (potentialEntities != null) { | ||
entitiesToOutline = HashMap(potentialEntities.size) | ||
} | ||
} | ||
|
||
/** | ||
* Conditionally queue entities around which to render entities | ||
* Selects from the pool of [.entitiesToChooseFrom] to speed up the predicate testing on subsequent calls. | ||
* Is more efficient (theoretically) than calling [.queueEntityToOutline] for each entity because lists are handled internally. | ||
* | ||
* | ||
* This function loops through all entities and so is not very efficient. | ||
* It's advisable to encapsulate calls to this function with global checks (those not dependent on an individual entity) for efficiency purposes. | ||
* | ||
* @param outlineColor a function to test | ||
*/ | ||
fun queueEntitiesToOutline(outlineColor: ((entity: Entity) -> Int?)? = null) { | ||
if (outlineColor == null) { | ||
return | ||
} | ||
if (entitiesToChooseFrom == null) { | ||
computeAndCacheEntitiesToChooseFrom() | ||
} | ||
val itr: MutableIterator<Entity> = entitiesToChooseFrom!!.iterator() | ||
while (itr.hasNext()) { | ||
val e: Entity = itr.next() | ||
val i: Int? = outlineColor(e) | ||
if (i != null) { | ||
entitiesToOutline!![e] = i | ||
itr.remove() | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Adds a single entity to the list of the entities to outline | ||
* | ||
* @param entity the entity to add | ||
* @param outlineColor the color with which to outline | ||
*/ | ||
fun queueEntityToOutline(entity: Entity?, outlineColor: Int) { | ||
if (entity == null) { | ||
return | ||
} | ||
if (entitiesToChooseFrom == null) { | ||
computeAndCacheEntitiesToChooseFrom() | ||
} | ||
if (!entitiesToChooseFrom!!.contains(entity)) { | ||
return | ||
} | ||
entitiesToOutline!![entity] = outlineColor | ||
entitiesToChooseFrom!!.remove(entity) | ||
} | ||
|
||
/** | ||
* Used for on-the-fly generation of entities. Driven by event handlers in a decentralized fashion | ||
*/ | ||
private fun computeAndCacheEntitiesToChooseFrom() { | ||
val entities: List<Entity> = Minecraft.getMinecraft().theWorld.getLoadedEntityList() | ||
// Only render outlines around non-null entities within the camera frustum | ||
entitiesToChooseFrom = HashSet(entities.size) | ||
// Only consider entities that aren't invisible armorstands to increase FPS significantly | ||
entities.forEach(Consumer<Entity> { e: Entity? -> | ||
if (e != null && !(e is EntityArmorStand && e.isInvisible()) && e !is EntityItemFrame) { | ||
entitiesToChooseFrom!!.add(e) | ||
} | ||
}) | ||
entitiesToOutline = HashMap(entitiesToChooseFrom!!.size) | ||
} | ||
|
||
/** | ||
* The phase of the event. | ||
* [.XRAY] means that this directly precedes entities whose outlines are rendered through walls (Vanilla 1.9+) | ||
* [.NO_XRAY] means that this directly precedes entities whose outlines are rendered only when visible to the client | ||
*/ | ||
enum class Type { | ||
XRAY, | ||
NO_XRAY | ||
} | ||
|
||
} |
100 changes: 100 additions & 0 deletions
100
src/main/java/at/hannibal2/skyhanni/features/fishing/SeaCreatureFeatures.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package at.hannibal2.skyhanni.features.fishing | ||
|
||
import at.hannibal2.skyhanni.SkyHanniMod | ||
import at.hannibal2.skyhanni.events.EntityMaxHealthUpdateEvent | ||
import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent | ||
import at.hannibal2.skyhanni.events.RenderEntityOutlineEvent | ||
import at.hannibal2.skyhanni.events.withAlpha | ||
import at.hannibal2.skyhanni.features.damageindicator.DamageIndicatorManager | ||
import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper | ||
import at.hannibal2.skyhanni.utils.* | ||
import at.hannibal2.skyhanni.utils.EntityUtils.getSkinTexture | ||
import at.hannibal2.skyhanni.utils.EntityUtils.hasMaxHealth | ||
import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer | ||
import at.hannibal2.skyhanni.utils.LorenzUtils.baseMaxHealth | ||
import at.hannibal2.skyhanni.utils.LorenzUtils.editCopy | ||
import net.minecraft.client.Minecraft | ||
import net.minecraft.client.entity.EntityOtherPlayerMP | ||
import net.minecraft.client.gui.FontRenderer | ||
import net.minecraft.entity.Entity | ||
import net.minecraft.entity.EntityLivingBase | ||
import net.minecraft.entity.item.EntityItem | ||
import net.minecraft.entity.monster.EntityGuardian | ||
import net.minecraft.entity.monster.EntitySkeleton | ||
import net.minecraft.entity.monster.EntityZombie | ||
import net.minecraft.entity.player.EntityPlayer | ||
import net.minecraft.scoreboard.ScorePlayerTeam | ||
import net.minecraft.scoreboard.Team.EnumVisible | ||
import net.minecraftforge.client.event.RenderWorldLastEvent | ||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent | ||
import java.awt.Color | ||
|
||
|
||
class SeaCreatureFeatures { | ||
private val config get() = SkyHanniMod.feature.fishing | ||
private var rareSeaCreatures = listOf<EntityLivingBase>() | ||
|
||
@SubscribeEvent | ||
fun onEntityHealthUpdate(event: EntityMaxHealthUpdateEvent) { | ||
if (!isEnabled()) return | ||
val entity = event.entity as? EntityLivingBase ?: return | ||
if (DamageIndicatorManager.isBoss(entity)) return | ||
|
||
val maxHealth = event.maxHealth | ||
for (creatureType in RareSeaCreatureType.entries) { | ||
if (EntityGuardian::class.java.isInstance(entity) && entity.baseMaxHealth > 1000) { | ||
LorenzUtils.consoleLog("FISHING CREATURE NAME: ${entity.baseMaxHealth} ${(entity as EntityGuardian).customNameTag}") | ||
} | ||
|
||
if (!creatureType.health.any { entity.hasMaxHealth(it, false, maxHealth) }) continue | ||
if (!creatureType.clazz.isInstance(entity)) continue | ||
|
||
if (EntityPlayer::class.java.isInstance(entity)) { | ||
LorenzUtils.consoleLog("FISHING CREATURE NAME: ${(entity as EntityPlayer).customNameTag}") | ||
} | ||
|
||
if (creatureType.nametag.isNotBlank() && EntityPlayer::class.java.isInstance(entity) && (entity as EntityPlayer).name != creatureType.nametag) { | ||
continue | ||
} | ||
|
||
rareSeaCreatures = rareSeaCreatures.editCopy { add(entity) } | ||
RenderLivingEntityHelper.setEntityColor(entity, LorenzColor.RED.toColor().withAlpha(50)) | ||
{ config.rareSeaCreatureHighlight } | ||
RenderLivingEntityHelper.setNoHurtTime(entity) { config.rareSeaCreatureHighlight } | ||
} | ||
} | ||
|
||
@SubscribeEvent | ||
fun onWorldChange(event: LorenzWorldChangeEvent) { | ||
rareSeaCreatures = emptyList() | ||
} | ||
|
||
@SubscribeEvent | ||
fun onRenderEntityOutlines(event: RenderEntityOutlineEvent) { | ||
if (isEnabled() && config.rareSeaCreatureHighlight && event.type === RenderEntityOutlineEvent.Type.XRAY) { | ||
event.queueEntitiesToOutline(getEntityOutlineColor) | ||
} | ||
} | ||
|
||
private fun isEnabled() = LorenzUtils.inSkyBlock && !LorenzUtils.inDungeons && !LorenzUtils.inKuudraFight | ||
|
||
private val getEntityOutlineColor: (entity: Entity) -> Int? = { e -> | ||
if (EntityLivingBase::class.java.isInstance(e) && e in rareSeaCreatures && e.distanceToPlayer() < 30) { | ||
LorenzColor.GREEN.toColor().rgb | ||
} else { | ||
null | ||
} | ||
} | ||
|
||
enum class RareSeaCreatureType(val clazz: Class<out EntityLivingBase>, val nametag: String, vararg val health: Int) { | ||
WATER_HYDRA(EntityZombie::class.java, "Water Hydra", 500_000, 1_500_000), | ||
SEA_EMPEROR(EntityGuardian::class.java, "The Sea Emperors", 750_000, 800_000, 2_250_000, 2_400_000), | ||
ZOMBIE_MINER(EntityPlayer::class.java, "", 2_000_000, 6_000_000), | ||
PHANTOM_FISHERMAN(EntityPlayer::class.java, "Phantom Fisher", 1_000_000, 3_000_000), | ||
GRIM_REAPER(EntityPlayer::class.java, "Grim Reaper", 3_000_000, 9_000_000), | ||
YETI(EntityPlayer::class.java, "", 2_000_000, 6_000_000), | ||
NUTCRACKER(EntityPlayer::class.java, "", 4_000_000, 12_000_000), | ||
GREAT_WHITE_SHARK(EntityPlayer::class.java, "GWS ", 1_500_000, 4_500_000), | ||
; | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/main/java/at/hannibal2/skyhanni/mixins/hooks/RenderGlobalHook.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package at.hannibal2.skyhanni.mixins.hooks | ||
|
||
import at.hannibal2.skyhanni.utils.EntityOutlineRenderer | ||
import at.hannibal2.skyhanni.utils.RenderUtils | ||
import net.minecraft.client.Minecraft | ||
import net.minecraft.client.renderer.culling.ICamera | ||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable | ||
|
||
class RenderGlobalHook { | ||
fun renderEntitiesOutlines(camera: ICamera?, partialTicks: Float): Boolean { | ||
val vec = RenderUtils.exactLocation(Minecraft.getMinecraft().renderViewEntity, partialTicks) | ||
return EntityOutlineRenderer.renderEntityOutlines(camera!!, partialTicks, vec) | ||
} | ||
|
||
fun shouldRenderEntityOutlines(cir: CallbackInfoReturnable<Boolean?>) { | ||
if (EntityOutlineRenderer.shouldRenderEntityOutlines()) { | ||
cir.returnValue = true | ||
} | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/main/java/at/hannibal2/skyhanni/mixins/hooks/RendererLivingEntityHook.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package at.hannibal2.skyhanni.mixins.hooks | ||
|
||
import at.hannibal2.skyhanni.utils.EntityOutlineRenderer | ||
import net.minecraft.client.renderer.GlStateManager | ||
import net.minecraft.entity.EntityLivingBase | ||
|
||
class RendererLivingEntityHook { | ||
fun setOutlineColor(red: Float, green: Float, blue: Float, alpha: Float, entity: EntityLivingBase) { | ||
val color = EntityOutlineRenderer.getCustomOutlineColor(entity); | ||
|
||
if (color != null) { | ||
val colorRed = (color shr 16 and 255).toFloat() / 255.0f | ||
val colorGreen = (color shr 8 and 255).toFloat() / 255.0f | ||
val colorBlue = (color and 255).toFloat() / 255.0f | ||
GlStateManager.color(colorRed, colorGreen, colorBlue, alpha); | ||
} else { | ||
GlStateManager.color(red, green, blue, alpha); | ||
} | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/main/java/at/hannibal2/skyhanni/mixins/transformers/CustomRenderGlobal.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package at.hannibal2.skyhanni.mixins.transformers; | ||
|
||
import net.minecraft.client.renderer.RenderGlobal; | ||
import net.minecraft.client.shader.Framebuffer; | ||
import net.minecraft.client.shader.ShaderGroup; | ||
import org.spongepowered.asm.mixin.Mixin; | ||
import org.spongepowered.asm.mixin.gen.Accessor; | ||
|
||
@Mixin(RenderGlobal.class) | ||
public interface CustomRenderGlobal { | ||
@Accessor("entityOutlineFramebuffer") | ||
Framebuffer getEntityOutlineFramebuffer_skyhanni(); | ||
|
||
@Accessor("entityOutlineShader") | ||
ShaderGroup getEntityOutlineShader_skyhanni(); | ||
|
||
} |
42 changes: 42 additions & 0 deletions
42
src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinRenderGlobal.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package at.hannibal2.skyhanni.mixins.transformers; | ||
|
||
import at.hannibal2.skyhanni.mixins.hooks.RenderGlobalHook; | ||
import net.minecraft.client.renderer.GlStateManager; | ||
import net.minecraft.client.renderer.RenderGlobal; | ||
import at.hannibal2.skyhanni.utils.EntityOutlineRenderer; | ||
import net.minecraft.client.Minecraft; | ||
import net.minecraft.client.renderer.culling.ICamera; | ||
import net.minecraft.entity.Entity; | ||
import org.spongepowered.asm.mixin.Mixin; | ||
import org.spongepowered.asm.mixin.Shadow; | ||
import org.spongepowered.asm.mixin.Unique; | ||
import org.spongepowered.asm.mixin.injection.At; | ||
import org.spongepowered.asm.mixin.injection.Inject; | ||
import org.spongepowered.asm.mixin.injection.Redirect; | ||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; | ||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; | ||
|
||
@Mixin(RenderGlobal.class) | ||
public abstract class MixinRenderGlobal { | ||
|
||
@Shadow | ||
abstract boolean isRenderEntityOutlines(); | ||
|
||
@Unique | ||
private final RenderGlobalHook skyHanni$hook = new RenderGlobalHook(); | ||
|
||
@Redirect(method = "renderEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;isRenderEntityOutlines()Z")) | ||
public boolean renderEntitiesOutlines(RenderGlobal self, Entity renderViewEntity, ICamera camera, float partialTicks) { | ||
return skyHanni$hook.renderEntitiesOutlines(camera, partialTicks) && this.isRenderEntityOutlines(); | ||
} | ||
|
||
@Inject(method = "isRenderEntityOutlines", at = @At(value = "HEAD"), cancellable = true) | ||
public void isRenderEntityOutlinesWrapper(CallbackInfoReturnable<Boolean> cir) { | ||
skyHanni$hook.shouldRenderEntityOutlines(cir); | ||
} | ||
|
||
@Inject(method = "renderEntityOutlineFramebuffer", at = @At(value = "RETURN")) | ||
public void afterFramebufferDraw(CallbackInfo callbackInfo) { | ||
GlStateManager.enableDepth(); | ||
} | ||
} |
Oops, something went wrong.