Skip to content

Instantly share code, notes, and snippets.

@21Joakim
Created August 27, 2024 15:39
Show Gist options
  • Select an option

  • Save 21Joakim/b5eb46bd9acb117349e9d76d3971f34e to your computer and use it in GitHub Desktop.

Select an option

Save 21Joakim/b5eb46bd9acb117349e9d76d3971f34e to your computer and use it in GitHub Desktop.
CS2: Fog example (env_fog_controller)
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Memory;
using System.Drawing;
using System.Reflection;
namespace CS2Plugin;
// Example of how to use env_fog_controller
// to set the fog on a per player basis.
public class FogPlugin : BasePlugin
{
public override string ModuleName => "FogPlugin";
public override string ModuleVersion => "0.0.1";
public override void Load(bool hotReload)
{
RegisterListener<Listeners.OnTick>(OnTick);
}
public void OnTick()
{
foreach (CCSPlayerController player in Utilities.GetPlayers())
{
CCSPlayerPawn? pawn = player.PlayerPawn.Value;
if (pawn == null)
{
continue;
}
CFogController? fogController = pawn.CameraServices?.PlayerFog?.Ctrl.Value;
if (fogController == null)
{
continue;
}
// We have to set this every tick, I am not sure why it always gets reset
CopyValues(pawn.Skybox3d.Fog, fogController.Fog);
SetStateChangeFogparams(pawn, "CBasePlayerPawn", "m_skybox3d", Schema.GetSchemaOffset("sky3dparams_t", "fog"));
}
}
[ConsoleCommand("fog")]
public void FogCommand(CCSPlayerController? player, CommandInfo command)
{
CCSPlayerPawn? pawn = player?.PlayerPawn.Value;
if (player == null || pawn == null)
{
command.ReplyToCommand("Only a player can run this command");
return;
}
// Re-use the fog controller because it does not get removed after each round,
// we don't want a fog controller leak :^)
CFogController? GetOrCreateFogController()
{
string fogControllerName = $"PlayerFogController{player.Slot}";
foreach (CFogController? fogController in Utilities.FindAllEntitiesByDesignerName<CFogController>("env_fog_controller"))
{
if (fogController.Entity!.Name == fogControllerName)
{
return fogController;
}
}
CFogController? newFogController = Utilities.CreateEntityByName<CFogController>("env_fog_controller");
if (newFogController == null)
{
return null;
}
newFogController.Entity!.Name = fogControllerName;
newFogController.DispatchSpawn();
return newFogController;
}
CFogController? fogController = GetOrCreateFogController();
if (fogController == null)
{
return;
}
// The fog properties you want
fogparams_t fog = fogController.Fog;
fog.Enable = true;
fog.ColorPrimary = Color.DarkOrange;
fog.Exponent = 0.30f;
fog.Maxdensity = 0.9f;
fog.End = 10000;
// If you want players to be affected by the fog you need to set the FogMaxDensityMultiplier value
bool updatePlayerVisibility = true;
if (updatePlayerVisibility)
{
CPlayerVisibility? playerVisibility = Utilities.FindAllEntitiesByDesignerName<CPlayerVisibility>("env_player_visibility")
.FirstOrDefault();
if (playerVisibility != null)
{
playerVisibility.FogMaxDensityMultiplier = 0.9f; // Default 0
Utilities.SetStateChanged(playerVisibility, "CPlayerVisibility", "m_flFogMaxDensityMultiplier");
}
}
// Set the active fog controller
pawn.AcceptInput("SetFogController", activator: fogController, value: "!activator");
// State change the values to make sure they are updated properly
SetStateChangeFogparams(fogController, "CFogController", "m_fog");
}
public static void SetStateChangeFogparams(CBaseEntity entity, string className, string fieldName, int extraOffset = 0)
{
// These are all the fogparam values except for the ones related to lerp
string[] fogparamFields = [
"dirPrimary", "colorPrimary", "colorSecondary",
"start", "end", "farz", "maxdensity", "exponent",
"HDRColorScale", "skyboxFogFactor", "blendtobackground",
"scattering", "locallightscale", "enable", "blend",
"m_bNoReflectionFog"
];
foreach (string fogparamField in fogparamFields)
{
Utilities.SetStateChanged(entity, className, fieldName, extraOffset + Schema.GetSchemaOffset("fogparams_t", fogparamField));
}
}
public static void CopyValues<T>(T self, T other) where T : NativeObject
{
foreach (PropertyInfo property in self.GetType().GetProperties())
{
if (property.CanRead && property.CanWrite)
{
property.SetValue(self, property.GetValue(other));
continue;
}
Type propertyType = property.PropertyType;
if (!propertyType.IsByRef)
{
continue;
}
SchemaMemberAttribute? schemaAttribute = property.GetCustomAttribute<SchemaMemberAttribute>();
if (schemaAttribute == null)
{
continue;
}
ref object selfValue = ref Schema.GetRef<object>(self.Handle, schemaAttribute.ClassName, schemaAttribute.MemberName);
ref object otherValue = ref Schema.GetRef<object>(other.Handle, schemaAttribute.ClassName, schemaAttribute.MemberName);
selfValue = otherValue;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment