Skip to content

Commit b58dfeb

Browse files
committed
Some new handlers and an item module
1 parent f2f20c8 commit b58dfeb

File tree

7 files changed

+172
-34
lines changed

7 files changed

+172
-34
lines changed

.rustfmt.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
max_width = 100
1+
max_width = 108
22
newline_style = "Unix"
33
use_field_init_shorthand = true
44
overflow_delimited_expr = true

Cargo.lock

Lines changed: 75 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,13 @@ features = ["single_threaded"]
3232
[dependencies.egui-hook]
3333
git = "https://github.com/jac3km4/egui-hook"
3434
rev = "v0.0.4"
35+
36+
[dependencies.memhack]
37+
git = "https://github.com/jac3km4/memhack"
38+
package = "memhack"
39+
rev = "v0.0.1"
40+
41+
[dependencies.memhack-derive]
42+
git = "https://github.com/jac3km4/memhack"
43+
package = "memhack-derive"
44+
rev = "v0.0.1"

doc/FUNCTIONS.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ All game functions are in a `game` namespace.
66
// give yourself 1 XP
77
game::give_xp(1)
88
9+
// give player 10 energy ammo
10+
item::give(entity::get_player(), item::resolve("It_Ammo_Energy"), 10, 0, true)
11+
912
// add the NPC you're looking at to the party
1013
game::join_player_party(entity::get_look_at())
1114
@@ -28,13 +31,17 @@ game::on_quest_success_player_traitor_to_humanity()
2831
### function list
2932
- `advance_time(hours: i64)`
3033
- `auto_loot(looter: Entity, target: Entity)`
34+
- `dismiss_player_party(npc: Entity)`
3135
- `give_quest_xp(amount: i64)`
3236
- `give_xp(amount: i64)`
3337
- `join_player_party(npc: Entity)`
3438
- `kill(instigator: Entity, target: Entity)`
3539
- `on_info_advance_playing_time_by_hours(hours: i64)`
40+
- `place_summoned_party_member(leader: Entity, member: Entity)`
41+
- `remove_npc(npc: Entity)`
3642
- `set_player_rank(rank: i64)`
3743
- `set_target_hour(hour: i64)`
44+
- `spawn_new_entity(pos: Entity, entity: Entity)`
3845
- `movement_callback()`
3946
- `movement_sneaking_callback()`
4047
- `movement_blocked_callback()`
@@ -3811,7 +3818,6 @@ game::on_quest_success_player_traitor_to_humanity()
38113818
- `can_wait_player_party()`
38123819
- `is_party_under_attack()`
38133820
- `can_dismiss_player_party()`
3814-
- `dismiss_player_party()`
38153821
- `dismiss_party_member()`
38163822
- `can_join_player_party()`
38173823
- `is_not_summoned()`
@@ -3847,8 +3853,6 @@ game::on_quest_success_player_traitor_to_humanity()
38473853
- `set_routine_continue_routine()`
38483854
- `set_human_rtn_dead()`
38493855
- `on_quest_lock_ai_result()`
3850-
- `spawn_new_entity()`
3851-
- `remove_npc()`
38523856
- `rtn_teleport_to_location()`
38533857
- `teleport_player_with_routine()`
38543858
- `teleport_player()`
@@ -4113,7 +4117,6 @@ game::on_quest_success_player_traitor_to_humanity()
41134117
- `on_process_projection()`
41144118
- `on_end_projection()`
41154119
- `routine_power_projection()`
4116-
- `place_summoned_party_member()`
41174120
- `can_cast_power_projection()`
41184121
- `power_projection()`
41194122
- `spell_camouflage_on_ui_info()`

src/elex.rs

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,46 @@
11
use std::borrow::Cow;
2+
use std::ffi::CString;
23
use std::{mem, ptr};
34

4-
use egui_hook::import_foreign;
5+
use memhack_derive::foreign_fn;
56
use pelite::pe64::{Pe, PeView};
67

78
pub fn get_all_functions<'a>() -> impl Iterator<Item = (Cow<'a, str>, FunctionPtr)> {
8-
unsafe { &*get_function_registry() }
9+
get_function_registry()
910
.functions()
1011
.map(|fun| (fun.name(), fun.ptr()))
1112
}
1213

13-
#[inline]
14-
pub fn get_player() -> Entity {
15-
Entity(get_player_ptr())
16-
}
17-
18-
#[inline]
1914
pub fn get_player_look_at() -> Entity {
2015
let player = get_player();
21-
let mut entity = Entity(ptr::null());
22-
get_player_look_at_ptr(&player, &mut entity);
16+
let mut entity = Entity::null();
17+
get_player_look_at_ref(&player, &mut entity);
2318
entity
2419
}
2520

26-
import_foreign!(0x0867080, get_function_registry() -> *const FunctionRegistry);
27-
import_foreign!(0x040B710, get_player_ptr() -> *const GameObject);
28-
import_foreign!(0x0B17FF0, get_player_look_at_ptr(player: *const Entity, entity: *mut Entity) -> ());
21+
pub fn resolve_item(name: &str) -> Entity {
22+
let mut item = Entity::null();
23+
if let Ok(str) = CString::new(name) {
24+
resolve_item_by_cstr(&mut item, str.as_ptr());
25+
}
26+
item
27+
}
28+
29+
#[inline]
30+
#[foreign_fn(0x040B710)]
31+
pub fn get_player() -> Entity {}
32+
#[inline]
33+
#[foreign_fn(0x0867080)]
34+
fn get_function_registry<'a>() -> &'a FunctionRegistry {}
35+
#[inline]
36+
#[foreign_fn(0x0B17FF0)]
37+
fn get_player_look_at_ref(player: &Entity, entity: &mut Entity) -> () {}
38+
#[inline]
39+
#[foreign_fn(0x0B30C00)]
40+
fn resolve_item_by_cstr(item: &mut Entity, name: *const i8) -> () {}
41+
#[inline]
42+
#[foreign_fn(0x0B13020)]
43+
pub fn give_item(target: &Entity, item: &Entity, quantity: u32, x: u32, notify: Notify) -> () {}
2944

3045
#[derive(Debug, Clone, Copy)]
3146
#[repr(C)]
@@ -36,6 +51,28 @@ impl Entity {
3651
pub fn null() -> Entity {
3752
Entity(std::ptr::null())
3853
}
54+
55+
#[inline]
56+
pub fn is_null(&self) -> bool {
57+
self.0.is_null()
58+
}
59+
}
60+
61+
#[repr(u32)]
62+
pub enum Notify {
63+
Never = 0,
64+
Always = 2,
65+
}
66+
67+
impl From<bool> for Notify {
68+
#[inline]
69+
fn from(notify: bool) -> Self {
70+
if notify {
71+
Notify::Always
72+
} else {
73+
Notify::Never
74+
}
75+
}
3976
}
4077

4178
#[derive(Debug)]

src/handlers.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,16 @@ static CUSTOM_HANDLERS: phf::Map<&'static str, CustomHandler> = phf_map! {
2929
"join_player_party" => custom_handler! { |ptr: FunctionPtr|
3030
move |entity: Entity| ptr.invoke_with(entity, Entity::null(), ())
3131
},
32+
"dismiss_player_party" => custom_handler! { |ptr: FunctionPtr|
33+
move |entity: Entity| ptr.invoke_with(entity, Entity::null(), ())
34+
},
35+
"spawn_new_entity" => custom_handler! { |ptr: FunctionPtr|
36+
move |pos: Entity, entity: Entity| ptr.invoke_with(pos, entity, ())
37+
},
38+
"remove_npc" => custom_handler! { |ptr: FunctionPtr|
39+
move |npc: Entity| ptr.invoke_with(npc, Entity::null(), ())
40+
},
41+
"place_summoned_party_member" => custom_handler! { |ptr: FunctionPtr|
42+
move |leader: Entity, member: Entity| ptr.invoke_with(leader, member, ())
43+
},
3244
};

src/host.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ impl Default for ScriptHost {
2727

2828
engine.register_static_module("game", ScriptHost::create_game_module().into());
2929
engine.register_static_module("entity", ScriptHost::create_entity_module().into());
30+
engine.register_static_module("item", ScriptHost::create_item_module().into());
3031

3132
engine.register_fn("log", move |val: Dynamic| {
3233
tx.send(val.to_string()).ok();
@@ -86,6 +87,20 @@ impl ScriptHost {
8687
module.set_native_fn("get_player", || Ok(elex::get_player()));
8788
module.set_native_fn("get_look_at", || Ok(elex::get_player_look_at()));
8889
module.set_native_fn("none", || Ok(elex::Entity::null()));
90+
module.set_native_fn("is_none", |entity: elex::Entity| Ok(entity.is_null()));
91+
module
92+
}
93+
94+
fn create_item_module() -> Module {
95+
let mut module = Module::new();
96+
module.set_native_fn("resolve", |name: &str| Ok(elex::resolve_item(name)));
97+
module.set_native_fn(
98+
"give",
99+
|target: elex::Entity, item: elex::Entity, quantity: i64, x: i64, notify: bool| {
100+
elex::give_item(&target, &item, quantity as u32, x as u32, notify.into());
101+
Ok(())
102+
},
103+
);
89104
module
90105
}
91106
}
@@ -105,8 +120,7 @@ impl egui_hook::App for ScriptHost {
105120
Window::new("CRONY GUI")
106121
.default_size(DEFAULT_SIZE)
107122
.show(ctx, |ui| {
108-
let (resp, painter) =
109-
ui.allocate_painter(DEFAULT_SIZE, Sense::focusable_noninteractive());
123+
let (resp, painter) = ui.allocate_painter(DEFAULT_SIZE, Sense::focusable_noninteractive());
110124

111125
painter.rect_filled(resp.rect, Rounding::same(4.), Color32::BLACK);
112126
painter.text(
@@ -139,9 +153,7 @@ impl egui_hook::App for ScriptHost {
139153
}
140154

141155
fn init() -> bool {
142-
let log_file = FileSpec::default()
143-
.directory("plugins/logs")
144-
.basename("crony");
156+
let log_file = FileSpec::default().directory("plugins/logs").basename("crony");
145157
Logger::with(LogSpecification::info())
146158
.log_to_file(log_file)
147159
.write_mode(WriteMode::BufferAndFlush)

0 commit comments

Comments
 (0)