Skip to content

Commit

Permalink
Change the mod to an ASI plugin (#2)
Browse files Browse the repository at this point in the history
Change the mod to an ASI plugin to improve compatibility with other DLL-based mods
  • Loading branch information
descawed authored Aug 18, 2023
1 parent f876565 commit 11c12c1
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 193 deletions.
7 changes: 3 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
[package]
name = "re0box"
version = "0.2.0"
version = "0.3.0"
authors = ["descawed <[email protected]>"]
edition = "2021"
description = "An item box mod for Resident Evil 0"
readme = "README.md"
homepage = "https://github.com/descawed/re0box"
homepage = "https://www.nexusmods.com/residentevil0biohazard0hdremaster/mods/39"
repository = "https://github.com/descawed/re0box"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
name = "dinput8"
crate-type = ["cdylib"]

[profile.release]
Expand All @@ -23,7 +22,7 @@ panic = "abort"
anyhow = "1.0"
binrw = "0.11"
configparser = "3.0"
windows = { version = "0.48", features = [ "Win32_Foundation", "Win32_System_LibraryLoader", "Win32_System_Memory", "Win32_System_SystemServices" ] }
windows = { version = "0.51", features = [ "Win32_Foundation", "Win32_System_Memory", "Win32_System_SystemServices", "Win32_System_Threading" ] }

[build-dependencies]
winresource = "0.1"
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ running; you'll need to restart the game for it to pick up any changes.
access the item box.

## Uninstall
Delete dinput8.dll from the Resident Evil 0 folder. None of the other mod files will have any effect once that's gone,
but if you want to purge everything, this is the full list of files added by the mod:
- dinput8.dll
Delete scripts\re0box.asi from the Resident Evil 0 folder. None of the other mod files will have any effect once that's
gone, but if you want to purge everything, this is the full list of files added by the mod:
- dinput8.dll (note that other mods may need this file. if you have anything in your scripts folder besides re0box.asi,
you should leave this one alone.)
- re0box.ini
- re0box_readme.txt
- nativePC\arc\message\msg_chS_box.arc
Expand All @@ -54,12 +55,15 @@ but if you want to purge everything, this is the full list of files added by the
- nativePC\arc\message\msg_ita_box.arc
- nativePC\arc\message\msg_jpn_box.arc
- nativePC\arc\message\msg_spa_box.arc
- scripts\re0box.asi

## Build
This mod is written in Rust and works via DLL injection. The default target is i686-windows-pc-gnu because RE0 is a
32-bit game and I'm cross-compiling from Linux. I imagine the MSVC toolchain would also work, but you might need to
change how the build script handles the .def file. As long as Rust and the appropriate toolchain are installed, you
should just be able to do a `cargo build`.
This mod is written in Rust. The default target is i686-windows-pc-gnu because RE0 is a 32-bit game and I'm
cross-compiling from Linux. I imagine the MSVC toolchain would also work but I haven't tested it. As long as Rust and
the appropriate toolchain are installed, you should just be able to do a `cargo build`. The mod is currently distributed
as an ASI plugin using [Ultimate-ASI-Loader](https://github.com/ThirteenAG/Ultimate-ASI-Loader) as the loader. This
helps ensure compatibility with other DLL-based mods. Just rename re0box.dll to re0box.asi and put it in the scripts
folder.

Aside from the DLL itself, we also have to edit the game's message files so typewriters prompt to use the box. These are
found in nativePC\arc\message. There's one file for each language the game supports, named in the format
Expand All @@ -78,5 +82,6 @@ value. Repack the arc file and your edits should show up in game.
## Credits
This mod was made by descawed. I used a number of existing tools in the making of this mod; special thanks to:
- hasherezade for [dll_injector](https://github.com/hasherezade/dll_injector)
- ThirteenAG for [Ultimate ASI Loader](https://github.com/ThirteenAG/Ultimate-ASI-Loader)
- FluffyQuack for [ARCtool](https://residentevilmodding.boards.net/thread/481/)
- onepiecefreak3 for [GMDConverter](https://github.com/onepiecefreak3/GMDConverter)
1 change: 0 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
fn main() {
println!("cargo:rustc-cdylib-link-arg=build/dinput8.def");
let res = winresource::WindowsResource::new();
res.compile().unwrap();
}
8 changes: 0 additions & 8 deletions build/dinput8.def

This file was deleted.

119 changes: 0 additions & 119 deletions src/dinput8.rs

This file was deleted.

25 changes: 25 additions & 0 deletions src/game.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
use std::arch::asm;
use std::ffi::c_void;
use std::io::Cursor;
use std::path::PathBuf;

use anyhow::{anyhow, Result};
use binrw::{binrw, BinReaderExt, BinWrite};
use windows::core::PWSTR;
use windows::Win32::Foundation::MAX_PATH;
use windows::Win32::System::Threading::{
GetCurrentProcess, QueryFullProcessImageNameW, PROCESS_NAME_FORMAT,
};

use super::inventory::{Bag, Item};

Expand Down Expand Up @@ -266,4 +272,23 @@ impl Game {

Ok(())
}

pub unsafe fn get_game_dir() -> PathBuf {
let mut path_buf = [0u16; MAX_PATH as usize];
let wstr = PWSTR::from_raw(path_buf.as_mut_ptr());
let mut size = MAX_PATH;
match QueryFullProcessImageNameW(
GetCurrentProcess(),
PROCESS_NAME_FORMAT::default(),
wstr,
&mut size,
)
.ok()
.and_then(|_| wstr.to_string().ok())
.and_then(|s| PathBuf::from(s).parent().map(PathBuf::from))
{
Some(p) => p,
None => PathBuf::from("../"), // if we can't get the executable directory, just return the parent directory
}
}
}
59 changes: 6 additions & 53 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@ use std::str;

use anyhow::Result;
use configparser::ini::Ini;
use windows::core::{IUnknown, GUID, HRESULT};
use windows::Win32::Foundation::{BOOL, HMODULE};
use windows::Win32::System::SystemServices::DLL_PROCESS_ATTACH;

mod patch;
use patch::*;

mod dinput8;
use dinput8::*;

mod game;
use game::*;

Expand Down Expand Up @@ -259,7 +255,6 @@ static mut NEW_GAME_TRAMPOLINE: [u8; 17] = [

static mut BOX: ItemBox = ItemBox::new();
static mut GAME: Game = Game::new();
static mut DINPUT8: DInput8 = DInput8::new();

unsafe extern "C" fn new_game() {
// reset the box when starting a new game
Expand Down Expand Up @@ -425,9 +420,10 @@ unsafe extern "fastcall" fn get_partner_bag(unknown: *mut c_void) -> *mut Bag {

fn main(reason: u32) -> Result<()> {
if reason == DLL_PROCESS_ATTACH {
let config_path = unsafe { Game::get_game_dir() }.join("re0box.ini");
let mut config = Ini::new();
// we don't care if the config fails to load, we'll just use the defaults
let _ = config.load("re0box.ini");
let _ = config.load(config_path);
let is_enabled = config
.getboolcoerce("Enable", "Mod")
.ok()
Expand All @@ -446,7 +442,10 @@ fn main(reason: u32) -> Result<()> {
// when the game tries to display the partner's inventory, show the box instead if it's open
let bag_jump = jmp(GET_PARTNER_BAG, get_partner_bag as usize);
patch(GET_PARTNER_BAG, &bag_jump)?;
let org_jump = jmp(GET_PARTNER_BAG_ORG, PARTNER_BAG_ORG_TRAMPOLINE.as_ptr() as usize);
let org_jump = jmp(
GET_PARTNER_BAG_ORG,
PARTNER_BAG_ORG_TRAMPOLINE.as_ptr() as usize,
);
set_trampoline(&mut PARTNER_BAG_ORG_TRAMPOLINE, 0, get_box_if_open as usize)?;
patch(GET_PARTNER_BAG_ORG, &org_jump)?;

Expand Down Expand Up @@ -617,52 +616,6 @@ fn main(reason: u32) -> Result<()> {
Ok(())
}

#[no_mangle]
#[allow(non_snake_case)]
unsafe extern "system" fn DirectInput8Create(
hinst: HMODULE,
version: u32,
riidltf: *const GUID,
ppv_out: *mut *const c_void,
punk_outer: *const IUnknown,
) -> HRESULT {
DINPUT8.direct_input8_create(hinst, version, riidltf, ppv_out, punk_outer)
}

#[no_mangle]
#[allow(non_snake_case)]
unsafe extern "system" fn DllCanUnloadNow() -> HRESULT {
DINPUT8.dll_can_unload_now()
}

#[no_mangle]
#[allow(non_snake_case)]
unsafe extern "system" fn DllGetClassObject(
rclsid: *const GUID,
riid: *const GUID,
ppv: *mut *const c_void,
) -> HRESULT {
DINPUT8.dll_get_class_object(rclsid, riid, ppv)
}

#[no_mangle]
#[allow(non_snake_case)]
unsafe extern "system" fn DllRegisterServer() -> HRESULT {
DINPUT8.dll_register_server()
}

#[no_mangle]
#[allow(non_snake_case)]
unsafe extern "system" fn DllUnregisterServer() -> HRESULT {
DINPUT8.dll_unregister_server()
}

#[no_mangle]
#[allow(non_snake_case)]
unsafe extern "system" fn GetdfDIJoystick() -> *const c_void {
DINPUT8.get_df_di_joystick()
}

#[no_mangle]
#[allow(non_snake_case)]
extern "system" fn DllMain(_dll_module: HMODULE, reason: u32, _reserved: *const c_void) -> BOOL {
Expand Down
2 changes: 1 addition & 1 deletion src/patch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn jge(from: usize, to: usize) -> [u8; 6] {

pub unsafe fn unprotect(ptr: *const c_void, size: usize) -> Result<()> {
let mut old_protect = PAGE_PROTECTION_FLAGS::default();
VirtualProtect(ptr, size, PAGE_EXECUTE_READWRITE, &mut old_protect).ok()?;
VirtualProtect(ptr, size, PAGE_EXECUTE_READWRITE, &mut old_protect)?;

Ok(())
}
Expand Down

0 comments on commit 11c12c1

Please sign in to comment.