Skip to content

Commit

Permalink
Add bxt_lightstyle (#92)
Browse files Browse the repository at this point in the history
* add bxt_lightstyle

* forgot to commit

* make sure not to override light style when cvar is not set

* changes suggested

* changes requested
  • Loading branch information
khanghugo committed Feb 15, 2024
1 parent 2c301dc commit 349d7ca
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 0 deletions.
37 changes: 37 additions & 0 deletions src/hooks/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ pub static CL_GameDir_f: Pointer<unsafe extern "C" fn()> = Pointer::empty_patter
]),
null_mut(),
);
pub static cl_lightstyle: Pointer<*mut [lightstyle_t; 64]> = Pointer::empty(b"cl_lightstyle\0");
pub static CL_Move: Pointer<unsafe extern "C" fn()> = Pointer::empty_patterns(
b"CL_Move\0",
// To find, search for "Client Move".
Expand All @@ -108,6 +109,15 @@ pub static CL_Move: Pointer<unsafe extern "C" fn()> = Pointer::empty_patterns(
]),
my_CL_Move as _,
);
pub static CL_Parse_LightStyle: Pointer<unsafe extern "C" fn()> = Pointer::empty_patterns(
b"CL_Parse_LightStyle\0",
// To find, search for "svc_lightstyle > MAX_LIGHTSTYLES"
Patterns(&[
// 8684
pattern!(56 57 E8 ?? ?? ?? ?? 8B ?? 83 ?? ?? ?? ?? 68),
]),
my_CL_Parse_LightStyle as _,
);
pub static CL_PlayDemo_f: Pointer<unsafe extern "C" fn()> = Pointer::empty_patterns(
b"CL_PlayDemo_f\0",
// To find, search for "playdemo <demoname> <replayspeed>: plays a demo".
Expand Down Expand Up @@ -908,7 +918,9 @@ static POINTERS: &[&dyn PointerTrait] = &[
&CL_Disconnect,
&cl_funcs,
&CL_GameDir_f,
&cl_lightstyle,
&CL_Move,
&CL_Parse_LightStyle,
&CL_PlayDemo_f,
&CL_ViewDemo_f,
&ClientDLL_Init,
Expand Down Expand Up @@ -1134,6 +1146,13 @@ pub struct client_static_s_demos {
pub demoplayback: c_int,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct lightstyle_t {
pub length: c_int,
pub map: [c_char; 64],
}

#[repr(C)]
pub struct movevars_s {
pub gravity: c_float,
Expand Down Expand Up @@ -1442,6 +1461,13 @@ pub unsafe fn find_pointers(marker: MainThreadMarker, base: *mut c_void, size: u
_ => (),
}

let ptr = &CL_Parse_LightStyle;
match ptr.pattern_index(marker) {
// 8684
Some(0) => cl_lightstyle.set(marker, ptr.by_offset(marker, 75)),
_ => (),
}

let ptr = &ClientDLL_Init;
match ptr.pattern_index(marker) {
// 6153
Expand Down Expand Up @@ -2422,6 +2448,17 @@ pub mod exported {
})
}

#[export_name = "CL_Parse_LightStyle"]
pub unsafe extern "C" fn my_CL_Parse_LightStyle() {
abort_on_panic(move || {
let marker = MainThreadMarker::new();

CL_Parse_LightStyle.get(marker)();

lightstyle::on_cl_parse_lightstyle(marker);
})
}

#[export_name = "CL_PlayDemo_f"]
pub unsafe extern "C" fn my_CL_PlayDemo_f() {
abort_on_panic(move || {
Expand Down
142 changes: 142 additions & 0 deletions src/modules/lightstyle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//! `bxt_lightstyle`

use byte_slice_cast::AsSliceOf;

use super::commands::Command;
use super::Module;
use crate::handler;
use crate::hooks::engine;
use crate::modules::cvars::CVar;
use crate::utils::*;

pub struct LightStyle;
impl Module for LightStyle {
fn name(&self) -> &'static str {
"bxt_lightstyle"
}

fn description(&self) -> &'static str {
"Change rendering light styles."
}

fn commands(&self) -> &'static [&'static Command] {
static COMMANDS: &[&Command] = &[&BXT_LIGHTSTYLE_APPLY];
COMMANDS
}

fn cvars(&self) -> &'static [&'static CVar] {
static CVARS: &[&CVar] = &[&BXT_LIGHTSTYLE_CUSTOM, &BXT_LIGHTSTYLE];
CVARS
}

fn is_enabled(&self, marker: MainThreadMarker) -> bool {
engine::cl_lightstyle.is_set(marker) && engine::CL_Parse_LightStyle.is_set(marker)
}
}

static BXT_LIGHTSTYLE: CVar = CVar::new(
b"bxt_lightstyle\0",
b"0\0",
"\
Preset controls. Must invoke apply command to take effects. Persists across level changes.
0: Off
1: Maximum brightness
2: Full bright
3: Maximum darkness
4: Mildy darker",
);
static BXT_LIGHTSTYLE_CUSTOM: CVar = CVar::new(
b"bxt_lightstyle_custom\0",
b"\0",
"\
Custom controls. Takes precedence over preset when using bxt_lightstyle_apply.
First value is effect. Second value is amount.
E.g.: bxt_lightstyle_custom \"1 nomnomnom\".
",
);

static BXT_LIGHTSTYLE_APPLY: Command = Command::new(
b"bxt_lightstyle_apply\0",
handler!(
"Apply lightstyle changes. Takes an optional argument for instantly applying a preset.",
apply_from_cvars as fn(_),
apply_preset as fn(_, _)
),
);

static ORIGINAL_LIGHTSTYLE: MainThreadRefCell<Vec<i8>> = MainThreadRefCell::new(vec![]);

fn apply_from_cvars(marker: MainThreadMarker) {
let input = BXT_LIGHTSTYLE_CUSTOM.to_string(marker);

if !input.is_empty() {
// 0 and "m" is default normal
let mut args = input.split_ascii_whitespace();
let index = args.next().and_then(|x| x.parse().ok()).unwrap_or(0);
let lightinfo = args.next().unwrap_or("m");

apply(marker, index, lightinfo);
} else {
apply_preset(marker, BXT_LIGHTSTYLE.as_u64(marker) as usize)
}
}

fn apply_preset(marker: MainThreadMarker, preset: usize) {
let lightinfo = match preset {
0 => "",
1 => "z",
2 => "#",
3 => "a",
4 => "g", // from someone else's personal preference
_ => "m", // m is the default normal lighting
};

apply(marker, 0, lightinfo);
}

fn apply(marker: MainThreadMarker, index: usize, lightinfo: &str) {
if !LightStyle.is_enabled(marker) {
return;
}

if index > 63 {
return;
}

if lightinfo.len() > 64 {
return;
}

unsafe {
let cl_lightstyle = &mut *engine::cl_lightstyle.get(marker);
let original = ORIGINAL_LIGHTSTYLE.borrow_mut(marker);

let slice: &[i8] = if lightinfo.is_empty() && !(*original).is_empty() && index == 0 {
(*original).as_slice()
} else {
lightinfo.as_slice_of().unwrap()
};

let slice_len = slice.len();

cl_lightstyle[index].map[..slice_len].copy_from_slice(slice);
cl_lightstyle[index].length = slice_len as i32;
}
}

pub fn on_cl_parse_lightstyle(marker: MainThreadMarker) {
// It is possible that the map has a preferred light style.
// Then, if we don't have any thing for our cvar, which is style is normal
// and no custom. THen we just don't do anything.
if BXT_LIGHTSTYLE.as_u64(marker) != 0 || !BXT_LIGHTSTYLE_CUSTOM.to_string(marker).is_empty() {
{
let cl_lightstyle = &mut unsafe { *engine::cl_lightstyle.get(marker) };
// More often a map's default lightstyle will be empty.
*ORIGINAL_LIGHTSTYLE.borrow_mut(marker) = cl_lightstyle[0].map.to_vec();
}

apply_from_cvars(marker);
}
}
2 changes: 2 additions & 0 deletions src/modules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub mod force_fov;
pub mod help;
pub mod hud;
pub mod hud_scale;
pub mod lightstyle;
pub mod novis;
pub mod player_movement_tracing;
pub mod remote_forbid;
Expand Down Expand Up @@ -100,6 +101,7 @@ pub static MODULES: &[&dyn Module] = &[
&help::Help,
&hud::Hud,
&hud_scale::HudScale,
&lightstyle::LightStyle,
&novis::NoVis,
&player_movement_tracing::PlayerMovementTracing,
&remote_forbid::RemoteForbid,
Expand Down

0 comments on commit 349d7ca

Please sign in to comment.