11use std:: { fs, io:: prelude:: * , sync:: atomic:: Ordering } ;
22
33use crate :: sys:: {
4- util:: { self , getAutorunHandle, getClientState , setClientState} ,
4+ util:: { getAutorunHandle, setClientState} ,
55 runlua:: runLuaEnv, statics:: *
66} ;
77
88use rglua:: {
99 lua_shared:: { self , * } ,
1010 types:: * ,
11- rstring,
12- interface:: IPanel
11+ rstring
1312} ;
1413
15- use detour:: static_detour;
16-
1714const LUA_BOOL : i32 = rglua:: globals:: Lua :: Type :: Bool as i32 ;
1815const LUA_STRING : i32 = rglua:: globals:: Lua :: Type :: String as i32 ;
1916
20- static_detour ! {
21- pub static luaL_newstate_h: extern "C" fn ( ) -> LuaState ;
22- pub static luaL_loadbufferx_h: extern "C" fn ( LuaState , * const i8 , SizeT , * const i8 , * const i8 ) -> CInt ;
23- pub static joinserver_h: extern "C" fn ( LuaState ) -> CInt ;
24- pub static paint_traverse_h: extern "thiscall" fn ( & ' static IPanel , usize , bool , bool ) ;
17+ #[ macro_use]
18+ pub mod lazy;
19+
20+ // Make our own static detours because detours.rs is lame and locked theirs behind nightly. :)
21+ lazy_detour ! {
22+ pub static LUAL_NEWSTATE_H : extern "C" fn ( ) -> LuaState = ( * lua_shared:: luaL_newstate, luaL_newstate) ;
23+ pub static LUAL_LOADBUFFERX_H : extern "C" fn ( LuaState , * const i8 , SizeT , * const i8 , * const i8 ) -> CInt = ( * lua_shared:: luaL_loadbufferx, luaL_loadbufferx) ;
24+ pub static JOINSERVER_H : extern "C" fn ( LuaState ) -> CInt ;
25+ }
26+
27+ #[ cfg( feature = "runner" ) ]
28+ use rglua:: interface:: IPanel ;
29+
30+ #[ cfg( feature = "runner" ) ]
31+ lazy_detour ! {
32+ static PAINT_TRAVERSE_H : extern "fastcall" fn ( & ' static IPanel , usize , bool , bool ) ;
2533}
2634
27- fn luaL_newstate ( ) -> LuaState {
28- let state = luaL_newstate_h . call ( ) ;
35+ extern "C" fn luaL_newstate ( ) -> LuaState {
36+ let state = LUAL_NEWSTATE_H . call ( ) ;
2937 debug ! ( "Got client state through luaL_newstate" ) ;
3038 setClientState ( state) ;
3139 state
3240}
3341
34- fn luaL_loadbufferx ( state : LuaState , mut code : * const i8 , mut size : SizeT , identifier : * const i8 , mode : * const i8 ) -> CInt {
42+ extern "C" fn luaL_loadbufferx ( state : LuaState , mut code : * const i8 , mut size : SizeT , identifier : * const i8 , mode : * const i8 ) -> CInt {
3543 use crate :: sys:: util:: initMenuState;
3644 if MENU_STATE . get ( ) . is_none ( ) {
37- initMenuState ( state)
38- . expect ( "Couldn't initialize menu state" ) ;
45+ if let Err ( why) = initMenuState ( state) {
46+ error ! ( "Couldn't initialize menu state. {}" , why) ;
47+ }
3948 }
4049
4150 // Todo: Check if you're in menu state (Not by checking MENU_DLL because that can be modified by lua) and if so, don't dump files.
@@ -44,18 +53,16 @@ fn luaL_loadbufferx(state: LuaState, mut code: *const i8, mut size: SizeT, ident
4453 let server_ip = CURRENT_SERVER_IP . load ( Ordering :: Relaxed ) ;
4554
4655 let mut do_run = true ;
47- if raw_path == "lua/includes/init.lua" {
48- if HAS_AUTORAN . compare_exchange ( false , true , Ordering :: Relaxed , Ordering :: Relaxed ) . is_ok ( ) {
49- // This will only run once when HAS_AUTORAN is false, setting it to true.
50- // Will be reset by JoinServer.
51- if let Ok ( script) = fs:: read_to_string ( & * AUTORUN_SCRIPT_PATH ) {
52- // Try to run here
53- if let Err ( why) = runLuaEnv ( & script, identifier, code, server_ip, true ) {
54- error ! ( "{}" , why) ;
55- }
56- } else {
57- error ! ( "Couldn't read your autorun script file at {}/{}" , SAUTORUN_DIR . display( ) , AUTORUN_SCRIPT_PATH . display( ) ) ;
56+ if raw_path == "lua/includes/init.lua" && HAS_AUTORAN . compare_exchange ( false , true , Ordering :: Relaxed , Ordering :: Relaxed ) . is_ok ( ) {
57+ // This will only run once when HAS_AUTORAN is false, setting it to true.
58+ // Will be reset by JoinServer.
59+ if let Ok ( script) = fs:: read_to_string ( & * AUTORUN_SCRIPT_PATH ) {
60+ // Try to run here
61+ if let Err ( why) = runLuaEnv ( & script, identifier, code, server_ip, true ) {
62+ error ! ( "{}" , why) ;
5863 }
64+ } else {
65+ error ! ( "Couldn't read your autorun script file at [{}]" , AUTORUN_SCRIPT_PATH . display( ) ) ;
5966 }
6067 }
6168
@@ -91,87 +98,98 @@ fn luaL_loadbufferx(state: LuaState, mut code: *const i8, mut size: SizeT, ident
9198
9299 if do_run {
93100 // Call the original function and return the value.
94- return luaL_loadbufferx_h . call ( state, code, size, identifier, mode ) ;
101+ return LUAL_LOADBUFFERX_H . call ( state, code, size, identifier, mode ) ;
95102 }
96103 0
97104}
98105
99106// Since the first lua state will always be the menu state, just keep a variable for whether joinserver has been hooked or not,
100107// If not, then hook it.
101- pub fn joinserver ( state : LuaState ) -> CInt {
102- let ip = rstring ! ( lua_tolstring( state, 1 , 0 ) ) ;
108+ pub extern "C" fn joinserver ( state : LuaState ) -> CInt {
109+ let ip = rstring ! ( lua_tolstring( state, 1 , 0 ) ) ;
103110 info ! ( "Joining Server with IP {}!" , ip) ;
104111
105112 CURRENT_SERVER_IP . store ( ip, Ordering :: Relaxed ) ; // Set the IP so we know where to write files in loadbufferx.
106113 HAS_AUTORAN . store ( false , Ordering :: Relaxed ) ;
107114
108- joinserver_h . call ( state)
115+ JOINSERVER_H . get ( ) . unwrap ( ) . call ( state)
109116}
110117
111- fn paint_traverse ( this : & ' static IPanel , panel_id : usize , force_repaint : bool , force_allow : bool ) {
112- paint_traverse_h. call ( this, panel_id, force_repaint, force_allow) ;
118+ #[ cfg( feature = "runner" ) ]
119+ extern "fastcall" fn paint_traverse ( this : & ' static IPanel , panel_id : usize , force_repaint : bool , force_allow : bool ) {
120+ use crate :: sys:: util:: { self , getClientState} ;
121+
122+ PAINT_TRAVERSE_H . get ( ) . unwrap ( ) . call ( this, panel_id, force_repaint, force_allow) ;
113123
114124 let script_queue = & mut * LUA_SCRIPTS
115125 . lock ( )
116126 . unwrap ( ) ;
117127
118- if script_queue. len ( ) > 0 {
128+ if ! script_queue. is_empty ( ) {
119129 let ( realm, script) = script_queue. remove ( 0 ) ;
120130
121131 let state = match realm {
122132 REALM_MENU => MENU_STATE . get ( ) . unwrap ( ) . load ( Ordering :: Acquire ) , // Code will never get into the queue without a menu state already existing.
123133 REALM_CLIENT => getClientState ( )
124134 } ;
125135
126- if state == std :: ptr :: null_mut ( ) { return ; }
136+ if state. is_null ( ) { return ; }
127137
128138 match util:: lua_dostring ( state, & script) {
129139 Err ( why) => {
130140 error ! ( "{}" , why) ;
131141 } ,
132142 Ok ( _) => {
133- info ! ( "Code [ #{}] ran successfully." , script. len( ) )
143+ info ! ( "Script of len #{} ran successfully." , script. len( ) )
134144 }
135145 }
136146 }
137147}
138148
139- pub unsafe fn init ( ) -> Result < ( ) , detour:: Error > {
140- luaL_loadbufferx_h
141- . initialize ( * lua_shared:: luaL_loadbufferx, luaL_loadbufferx) ?
142- . enable ( ) ?;
143-
144- luaL_newstate_h
145- . initialize ( * lua_shared:: luaL_newstate, luaL_newstate) ?
146- . enable ( ) ?;
147-
149+ #[ cfg( feature = "runner" ) ]
150+ unsafe fn init_paint_traverse ( ) -> Result < ( ) , detour:: Error > {
148151 use rglua:: interface:: * ;
149152
150153 let vgui_interface = get_from_interface ( "VGUI_Panel009" , get_interface_handle ( "vgui2.dll" ) . unwrap ( ) )
151154 . unwrap ( ) as * mut IPanel ;
152155
153156 let panel_interface = vgui_interface. as_ref ( ) . unwrap ( ) ;
154157
155- type PaintTraverseFn = extern "thiscall " fn ( & ' static IPanel , usize , bool , bool ) ;
158+ type PaintTraverseFn = extern "fastcall " fn ( & ' static IPanel , usize , bool , bool ) ;
156159 // Get painttraverse raw function object to detour.
157160 let painttraverse: PaintTraverseFn = std:: mem:: transmute (
158161 ( panel_interface. vtable as * mut * mut CVoid )
159162 . offset ( 41 )
160163 . read ( )
161164 ) ;
162165
163- paint_traverse_h
164- . initialize ( painttraverse, paint_traverse ) ?
165- . enable ( ) ?;
166+ let detour = detour:: GenericDetour :: new ( painttraverse, paint_traverse) ?;
167+
168+ PAINT_TRAVERSE_H . set ( detour) ;
169+ PAINT_TRAVERSE_H . get ( ) . unwrap ( ) . enable ( ) ?;
170+
171+ Ok ( ( ) )
172+ }
173+
174+ pub unsafe fn init ( ) -> Result < ( ) , detour:: Error > {
175+ use once_cell:: sync:: Lazy ;
176+
177+ Lazy :: force ( & LUAL_LOADBUFFERX_H ) ;
178+ Lazy :: force ( & LUAL_NEWSTATE_H ) ;
179+
180+ #[ cfg( feature = "runner" ) ]
181+ init_paint_traverse ( ) ?;
166182
167183 Ok ( ( ) )
168184}
169185
170186pub unsafe fn cleanup ( ) -> Result < ( ) , detour:: Error > {
171- luaL_loadbufferx_h. disable ( ) ?;
172- luaL_newstate_h. disable ( ) ?;
173- joinserver_h. disable ( ) ?;
174- paint_traverse_h. disable ( ) ?;
187+ LUAL_LOADBUFFERX_H . disable ( ) ?;
188+ LUAL_NEWSTATE_H . disable ( ) ?;
189+ JOINSERVER_H . get ( ) . unwrap ( ) . disable ( ) ?;
190+
191+ #[ cfg( feature = "runner" ) ]
192+ PAINT_TRAVERSE_H . get ( ) . unwrap ( ) . disable ( ) ?;
175193
176194 Ok ( ( ) )
177195}
0 commit comments