Files
BarotraumaModServer/LocalMods/Complete Global Darkness Reboot/CSharp/Client/CompleteDarknessMod.cs
2026-06-09 00:42:10 +03:00

366 lines
19 KiBLFS
C#
Executable File

using System;
using System.Reflection;
using Barotrauma;
using HarmonyLib;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
using System.Linq;
using System;
using Barotrauma.Items.Components;
using Barotrauma.Particles;
using Barotrauma.Lights;
using FarseerPhysics.Fluids;
using Barotrauma.Extensions;
using System.Threading;
using Barotrauma.Lights;
// patching this method https://github.com/evilfactory/LuaCsForBarotrauma/blob/5e89e2ea118cb5dbafa3214227ed2eaf57a77901/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs#L246
namespace CompleteDarkness
{
class CompleteDarknessMod : IAssemblyPlugin
{
public Harmony harmony;
public void Initialize()
{
harmony = new Harmony("nohalo.mod");
harmony.Patch(
original: typeof(Barotrauma.Lights.LightManager).GetMethod("RenderLightMap"),
prefix: new HarmonyMethod(typeof(CompleteDarknessMod).GetMethod("RenderLightMap"))
);
}
public void OnLoadCompleted() { }
public void PreInitPatching() { }
public void Dispose()
{
harmony.UnpatchSelf();
harmony = null;
}
public static bool RenderLightMap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam, Barotrauma.Lights.LightManager __instance, RenderTarget2D backgroundObstructor = null)
{
Barotrauma.Lights.LightManager _ = __instance;
if (!_.LightingEnabled) { return false; }
if (Math.Abs(_.currLightMapScale - GameSettings.CurrentConfig.Graphics.LightMapScale) > 0.01f)
{
//lightmap scale has changed -> recreate render targets
_.CreateRenderTargets(graphics);
}
Matrix spriteBatchTransform = cam.Transform * Matrix.CreateScale(new Vector3(GameSettings.CurrentConfig.Graphics.LightMapScale, GameSettings.CurrentConfig.Graphics.LightMapScale, 1.0f));
Matrix transform = cam.ShaderTransform
* Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;
bool highlightsVisible = _.UpdateHighlights(graphics, spriteBatch, spriteBatchTransform, cam);
Rectangle viewRect = cam.WorldView;
viewRect.Y -= cam.WorldView.Height;
//check which lights need to be drawn
_.recalculationCount = 0;
_.activeLights.Clear();
foreach (LightSource light in _.lights)
{
if (!light.Enabled) { continue; }
if ((light.Color.A < 1 || light.Range < 1.0f) && !light.LightSourceParams.OverrideLightSpriteAlpha.HasValue) { continue; }
if (light.ParentBody != null)
{
light.ParentBody.UpdateDrawPosition();
Vector2 pos = light.ParentBody.DrawPosition + light.OffsetFromBody;
if (light.ParentSub != null) { pos -= light.ParentSub.DrawPosition; }
light.Position = pos;
}
//above the top boundary of the level (in an inactive respawn shuttle?)
if (Level.IsPositionAboveLevel(light.WorldPosition)) { continue; }
float range = light.LightSourceParams.TextureRange;
if (light.LightSprite != null)
{
float spriteRange = Math.Max(
light.LightSprite.size.X * light.SpriteScale.X * (0.5f + Math.Abs(light.LightSprite.RelativeOrigin.X - 0.5f)),
light.LightSprite.size.Y * light.SpriteScale.Y * (0.5f + Math.Abs(light.LightSprite.RelativeOrigin.Y - 0.5f)));
float targetSize = Math.Max(light.LightTextureTargetSize.X, light.LightTextureTargetSize.Y);
range = Math.Max(Math.Max(spriteRange, targetSize), range);
}
if (!MathUtils.CircleIntersectsRectangle(light.WorldPosition, range, viewRect)) { continue; }
light.Priority = lightPriority(range, light);
int i = 0;
while (i < _.activeLights.Count && light.Priority < _.activeLights[i].Priority)
{
i++;
}
_.activeLights.Insert(i, light);
}
Barotrauma.Lights.LightManager.ActiveLightCount = _.activeLights.Count;
float lightPriority(float range, LightSource light)
{
return
range *
((Character.Controlled?.Submarine != null && light.ParentSub == Character.Controlled?.Submarine) ? 2.0f : 1.0f) *
(light.CastShadows ? 10.0f : 1.0f) *
(light.LightSourceParams.OverrideLightSpriteAlpha ?? (light.Color.A / 255.0f)) *
light.PriorityMultiplier;
}
//find the lights with an active light volume
_.activeShadowCastingLights.Clear();
foreach (var activeLight in _.activeLights)
{
if (!activeLight.CastShadows) { continue; }
if (activeLight.Range < 1.0f || activeLight.Color.A < 1 || activeLight.CurrentBrightness <= 0.0f) { continue; }
_.activeShadowCastingLights.Add(activeLight);
}
//remove some lights with a light volume if there's too many of them
if (_.activeShadowCastingLights.Count > GameSettings.CurrentConfig.Graphics.VisibleLightLimit && Screen.Selected is { IsEditor: false })
{
for (int i = GameSettings.CurrentConfig.Graphics.VisibleLightLimit; i < _.activeShadowCastingLights.Count; i++)
{
_.activeLights.Remove(_.activeShadowCastingLights[i]);
}
}
_.activeLights.Sort((l1, l2) => l1.LastRecalculationTime.CompareTo(l2.LastRecalculationTime));
//draw light sprites attached to characters
//render into a separate rendertarget using alpha blending (instead of on top of everything else with alpha blending)
//to prevent the lights from showing through other characters or other light sprites attached to the same character
//---------------------------------------------------------------------------------------------------
graphics.SetRenderTarget(_.LimbLightMap);
graphics.Clear(Color.Black);
graphics.BlendState = BlendState.NonPremultiplied;
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
foreach (LightSource light in _.activeLights)
{
if (light.IsBackground || light.CurrentBrightness <= 0.0f) { continue; }
//draw limb lights at this point, because they were skipped over previously to prevent them from being obstructed
if (light.ParentBody?.UserData is Limb limb && !limb.Hide) { light.DrawSprite(spriteBatch, cam); }
}
spriteBatch.End();
//draw background lights
//---------------------------------------------------------------------------------------------------
graphics.SetRenderTarget(_.LightMap);
graphics.Clear(_.AmbientLight);
graphics.BlendState = BlendState.Additive;
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
Level.Loaded?.BackgroundCreatureManager?.DrawLights(spriteBatch, cam);
foreach (LightSource light in _.activeLights)
{
if (!light.IsBackground || light.CurrentBrightness <= 0.0f) { continue; }
light.DrawLightVolume(spriteBatch, _.lightEffect, transform, _.recalculationCount < 5, ref _.recalculationCount); // 5 in here is const int MaxLightVolumeRecalculationsPerFrame
light.DrawSprite(spriteBatch, cam);
}
//List<FluidParticle> Particles = new List<FluidParticle>();
GameMain.ParticleManager.Draw(spriteBatch, true, null, ParticleBlendState.Additive);
spriteBatch.End();
//draw a black rectangle on hulls to hide background lights behind subs
//---------------------------------------------------------------------------------------------------
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, transformMatrix: spriteBatchTransform);
Dictionary<Hull, Rectangle> visibleHulls = _.GetVisibleHulls(cam);
foreach (KeyValuePair<Hull, Rectangle> hull in visibleHulls)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(hull.Value.X, -hull.Value.Y),
new Vector2(hull.Value.Width, hull.Value.Height),
hull.Key.AmbientLight == Color.TransparentBlack ? Color.Black : hull.Key.AmbientLight.Multiply(hull.Key.AmbientLight.A / 255.0f), true);
}
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
Vector3 glowColorHSV = ToolBox.RGBToHSV(_.AmbientLight);
glowColorHSV.Z = Math.Max(glowColorHSV.Z, 0.4f);
Color glowColor = ToolBoxCore.HSVToRGB(glowColorHSV.X, glowColorHSV.Y, glowColorHSV.Z);
Vector2 glowSpriteSize = new Vector2(_.gapGlowTexture.Width, _.gapGlowTexture.Height);
foreach (var gap in Gap.GapList)
{
if (gap.IsRoomToRoom || gap.Open <= 0.0f || gap.ConnectedWall == null) { continue; }
float a = MathHelper.Lerp(0.5f, 1.0f,
PerlinNoise.GetPerlin((float)Timing.TotalTime * 0.05f, gap.GlowEffectT));
float scale = MathHelper.Lerp(0.5f, 2.0f,
PerlinNoise.GetPerlin((float)Timing.TotalTime * 0.01f, gap.GlowEffectT));
float rot = PerlinNoise.GetPerlin((float)Timing.TotalTime * 0.001f, gap.GlowEffectT) * MathHelper.TwoPi;
Vector2 spriteScale = new Vector2(gap.Rect.Width, gap.Rect.Height) / glowSpriteSize;
Vector2 drawPos = new Vector2(gap.DrawPosition.X, -gap.DrawPosition.Y);
spriteBatch.Draw(_.gapGlowTexture,
drawPos,
null,
glowColor * a,
rot,
glowSpriteSize / 2,
scale: Math.Max(spriteScale.X, spriteScale.Y) * scale,
SpriteEffects.None,
layerDepth: 0);
}
spriteBatch.End();
if (backgroundObstructor != null)
{
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.LinearWrap, transformMatrix: Matrix.Identity, effect: GameMain.GameScreen.DamageEffect);
spriteBatch.Draw(backgroundObstructor, new Rectangle(0, 0,
(int)(GameMain.GraphicsWidth * _.currLightMapScale), (int)(GameMain.GraphicsHeight * _.currLightMapScale)), Color.Black);
spriteBatch.End();
}
else
{
GameMain.GameScreen.DamageEffect.CurrentTechnique = GameMain.GameScreen.DamageEffect.Techniques["StencilShaderSolidColor"];
GameMain.GameScreen.DamageEffect.Parameters["solidColor"].SetValue(Color.Black.ToVector4());
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, SamplerState.LinearWrap, transformMatrix: spriteBatchTransform, effect: GameMain.GameScreen.DamageEffect);
Submarine.DrawDamageable(spriteBatch, GameMain.GameScreen.DamageEffect);
spriteBatch.End();
}
graphics.BlendState = BlendState.Additive;
//draw the focused item and character to highlight them,
//and light sprites (done before drawing the actual light volumes so we can make characters obstruct the highlights and sprites)
//---------------------------------------------------------------------------------------------------
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
foreach (LightSource light in _.activeLights)
{
//don't draw limb lights at this point, they need to be drawn after lights have been obstructed by characters
if (light.IsBackground || light.ParentBody?.UserData is Limb || light.CurrentBrightness <= 0.0f) { continue; }
light.DrawSprite(spriteBatch, cam);
}
spriteBatch.End();
if (highlightsVisible)
{
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
spriteBatch.Draw(_.HighlightMap, Vector2.Zero, Color.White);
spriteBatch.End();
}
//draw characters to obstruct the highlighted items/characters and light sprites
//---------------------------------------------------------------------------------------------------
if (cam.Zoom > Barotrauma.Lights.LightManager.ObstructLightsBehindCharactersZoomThreshold)
{
_.SolidColorEffect.CurrentTechnique = _.SolidColorEffect.Techniques["SolidVertexColor"];
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: _.SolidColorEffect, transformMatrix: spriteBatchTransform);
DrawCharacters(spriteBatch, cam, drawDeformSprites: false);
spriteBatch.End();
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShaderSolidVertexColor"];
DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
DrawCharacters(spriteBatch, cam, drawDeformSprites: true);
spriteBatch.End();
}
static void DrawCharacters(SpriteBatch spriteBatch, Camera cam, bool drawDeformSprites)
{
foreach (Character character in Character.CharacterList)
{
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible || character.InvisibleTimer > 0.0f) { continue; }
if (Character.Controlled?.FocusedCharacter == character) { continue; }
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
Color.Black :
character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
foreach (Limb limb in character.AnimController.Limbs)
{
if (drawDeformSprites == (limb.DeformSprite == null)) { continue; }
limb.Draw(spriteBatch, cam, lightColor);
}
foreach (var heldItem in character.HeldItems)
{
heldItem.Draw(spriteBatch, editing: false, overrideColor: Color.Black);
}
}
}
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShader"];
graphics.BlendState = BlendState.Additive;
//draw the actual light volumes, additive particles, hull ambient lights and the halo around the player
//---------------------------------------------------------------------------------------------------
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, transformMatrix: spriteBatchTransform);
spriteBatch.Draw(_.LimbLightMap, new Rectangle(cam.WorldView.X, -cam.WorldView.Y, cam.WorldView.Width, cam.WorldView.Height), Color.White);
foreach (ElectricalDischarger discharger in ElectricalDischarger.List)
{
discharger.DrawElectricity(spriteBatch);
}
foreach (LightSource light in _.activeLights)
{
if (light.IsBackground || light.CurrentBrightness <= 0.0f) { continue; }
light.DrawLightVolume(spriteBatch, _.lightEffect, transform, _.recalculationCount < Barotrauma.Lights.LightManager.MaxLightVolumeRecalculationsPerFrame, ref _.recalculationCount);
}
if (ConnectionPanel.ShouldDebugDrawWiring)
{
foreach (MapEntity e in (Submarine.VisibleEntities ?? MapEntity.MapEntityList))
{
if (e is Item item && !item.IsHidden && item.GetComponent<Wire>() is Wire wire)
{
wire.DebugDraw(spriteBatch, alpha: 0.4f);
}
}
}
_.lightEffect.World = transform;
GameMain.ParticleManager.Draw(spriteBatch, false, null, ParticleBlendState.Additive);
//----------------------- Code removed by Heelge, part 2 -----------------------
/*if (Character.Controlled != null)
{
DrawHalo(Character.Controlled);
}
else
{
foreach (Character character in Character.CharacterList)
{
if (character.Submarine == null || character.IsDead || !character.IsHuman) { continue; }
DrawHalo(character);
}
}
void DrawHalo(Character character)
{
if (character == null || character.Removed) { return; }
Vector2 haloDrawPos = character.DrawPosition;
haloDrawPos.Y = -haloDrawPos.Y;
//ambient light decreases the brightness of the halo (no need for a bright halo if the ambient light is bright enough)
float ambientBrightness = (AmbientLight.R + AmbientLight.B + AmbientLight.G) / 255.0f / 3.0f;
Color haloColor = Color.White.Multiply(0.3f - ambientBrightness);
if (haloColor.A > 0)
{
float scale = 512.0f / LightSource.LightTexture.Width;
spriteBatch.Draw(
LightSource.LightTexture, haloDrawPos, null, haloColor, 0.0f,
new Vector2(LightSource.LightTexture.Width, LightSource.LightTexture.Height) / 2, scale, SpriteEffects.None, 0.0f);
}
}*/
spriteBatch.End();
//draw the actual light volumes, additive particles, hull ambient lights and the halo around the player
//---------------------------------------------------------------------------------------------------
graphics.SetRenderTarget(null);
graphics.BlendState = BlendState.NonPremultiplied;
return false;
}
}
}