Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Native Bindings #93

Merged
merged 3 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["simulator", "solvers", "game_data", "raphael-cli"]
members = ["simulator", "solvers", "game_data", "raphael-cli", "bindings"]

[package]
name = "raphael-xiv"
Expand Down
16 changes: 16 additions & 0 deletions bindings/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "bindings"
version = "0.1.0"
edition = "2021"

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

[dependencies]
simulator = { path = "../simulator" }
solvers = { path = "../solvers" }

[build-dependencies]
cbindgen = "0.27.0"
csbindgen = "1.9.3"
82 changes: 82 additions & 0 deletions bindings/NativeMethods.g.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// <auto-generated>
// This code is generated by csbindgen.
// DON'T CHANGE THIS DIRECTLY.
// </auto-generated>
#pragma warning disable CS8500
#pragma warning disable CS8981
using System;
using System.Runtime.InteropServices;


namespace Raphael
{
public static unsafe partial class NativeMethods
{
const string __DllName = "raphael_bindings";



[DllImport(__DllName, EntryPoint = "solve", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern void solve(SolveArgs* args);


}

[StructLayout(LayoutKind.Sequential)]
public unsafe partial struct SolveArgs
{
public delegate* unmanaged[Cdecl]<bool*, void> on_start;
public delegate* unmanaged[Cdecl]<Action*, nuint, void> on_finish;
public delegate* unmanaged[Cdecl]<Action*, nuint, void> on_suggest_solution;
public delegate* unmanaged[Cdecl]<nuint, void> on_progress;
public ulong action_mask;
public ushort progress;
public ushort quality;
public ushort base_progress;
public ushort base_quality;
public short cp;
public sbyte durability;
public byte job_level;
[MarshalAs(UnmanagedType.U1)] public bool adversarial;
[MarshalAs(UnmanagedType.U1)] public bool backload_progress;
[MarshalAs(UnmanagedType.U1)] public bool unsound_branch_pruning;
}


public enum Action : byte
{
BasicSynthesis,
BasicTouch,
MasterMend,
Observe,
TricksOfTheTrade,
WasteNot,
Veneration,
StandardTouch,
GreatStrides,
Innovation,
WasteNot2,
ByregotsBlessing,
PreciseTouch,
MuscleMemory,
CarefulSynthesis,
Manipulation,
PrudentTouch,
AdvancedTouch,
Reflect,
PreparatoryTouch,
Groundwork,
DelicateSynthesis,
IntensiveSynthesis,
TrainedEye,
HeartAndSoul,
PrudentSynthesis,
TrainedFinesse,
RefinedTouch,
QuickInnovation,
ImmaculateMend,
TrainedPerfection,
}


}
64 changes: 64 additions & 0 deletions bindings/bindings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <ostream>
#include <new>

enum class Action : uint8_t {
BasicSynthesis,
BasicTouch,
MasterMend,
Observe,
TricksOfTheTrade,
WasteNot,
Veneration,
StandardTouch,
GreatStrides,
Innovation,
WasteNot2,
ByregotsBlessing,
PreciseTouch,
MuscleMemory,
CarefulSynthesis,
Manipulation,
PrudentTouch,
AdvancedTouch,
Reflect,
PreparatoryTouch,
Groundwork,
DelicateSynthesis,
IntensiveSynthesis,
TrainedEye,
HeartAndSoul,
PrudentSynthesis,
TrainedFinesse,
RefinedTouch,
QuickInnovation,
ImmaculateMend,
TrainedPerfection,
};

struct SolveArgs {
void (*on_start)(bool*);
void (*on_finish)(const Action*, size_t);
void (*on_suggest_solution)(const Action*, size_t);
void (*on_progress)(size_t);
uint64_t action_mask;
uint16_t progress;
uint16_t quality;
uint16_t base_progress;
uint16_t base_quality;
int16_t cp;
int8_t durability;
uint8_t job_level;
bool adversarial;
bool backload_progress;
bool unsound_branch_pruning;
};

extern "C" {

void solve(const SolveArgs *args);

} // extern "C"
24 changes: 24 additions & 0 deletions bindings/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use cbindgen::Config;
use std::env;

fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

cbindgen::Builder::new()
.with_config(Config {
usize_is_size_t: true,
..Default::default()
})
.with_crate(crate_dir)
.generate()
.expect("Unable to generate C++ bindings")
.write_to_file("bindings.h");

csbindgen::Builder::default()
.input_extern_file("src/lib.rs")
.csharp_dll_name("raphael_bindings")
.csharp_namespace("Raphael")
.csharp_class_accessibility("public")
.generate_csharp_file("NativeMethods.g.cs")
.expect("Unable to generate C# bindings");
}
150 changes: 150 additions & 0 deletions bindings/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
use simulator::{ActionMask, Settings, SimulationState};
use solvers::{AtomicFlag, MacroSolver};

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct SolveArgs {
pub on_start: extern "C" fn(*mut bool),
pub on_finish: extern "C" fn(*const Action, usize),
pub on_suggest_solution: Option<extern "C" fn(*const Action, usize)>,
pub on_progress: Option<extern "C" fn(usize)>,
pub action_mask: u64,
pub progress: u16,
pub quality: u16,
pub base_progress: u16,
pub base_quality: u16,
pub cp: i16,
pub durability: i8,
pub job_level: u8,
pub adversarial: bool,
pub backload_progress: bool,
pub unsound_branch_pruning: bool,
}

// repr should be identical to simulator::Action
#[repr(u8)]
pub enum Action {
BasicSynthesis,
BasicTouch,
MasterMend,
Observe,
TricksOfTheTrade,
WasteNot,
Veneration,
StandardTouch,
GreatStrides,
Innovation,
WasteNot2,
ByregotsBlessing,
PreciseTouch,
MuscleMemory,
CarefulSynthesis,
Manipulation,
PrudentTouch,
AdvancedTouch,
Reflect,
PreparatoryTouch,
Groundwork,
DelicateSynthesis,
IntensiveSynthesis,
TrainedEye,
HeartAndSoul,
PrudentSynthesis,
TrainedFinesse,
RefinedTouch,
QuickInnovation,
ImmaculateMend,
TrainedPerfection,
}

// This should produce an error if simulator::Action is changed
impl From<simulator::Action> for Action {
fn from(value: simulator::Action) -> Self {
match value {
simulator::Action::BasicSynthesis => Self::BasicSynthesis,
simulator::Action::BasicTouch => Self::BasicTouch,
simulator::Action::MasterMend => Self::MasterMend,
simulator::Action::Observe => Self::Observe,
simulator::Action::TricksOfTheTrade => Self::TricksOfTheTrade,
simulator::Action::WasteNot => Self::WasteNot,
simulator::Action::Veneration => Self::Veneration,
simulator::Action::StandardTouch => Self::StandardTouch,
simulator::Action::GreatStrides => Self::GreatStrides,
simulator::Action::Innovation => Self::Innovation,
simulator::Action::WasteNot2 => Self::WasteNot2,
simulator::Action::ByregotsBlessing => Self::ByregotsBlessing,
simulator::Action::PreciseTouch => Self::PreciseTouch,
simulator::Action::MuscleMemory => Self::MuscleMemory,
simulator::Action::CarefulSynthesis => Self::CarefulSynthesis,
simulator::Action::Manipulation => Self::Manipulation,
simulator::Action::PrudentTouch => Self::PrudentTouch,
simulator::Action::AdvancedTouch => Self::AdvancedTouch,
simulator::Action::Reflect => Self::Reflect,
simulator::Action::PreparatoryTouch => Self::PreparatoryTouch,
simulator::Action::Groundwork => Self::Groundwork,
simulator::Action::DelicateSynthesis => Self::DelicateSynthesis,
simulator::Action::IntensiveSynthesis => Self::IntensiveSynthesis,
simulator::Action::TrainedEye => Self::TrainedEye,
simulator::Action::HeartAndSoul => Self::HeartAndSoul,
simulator::Action::PrudentSynthesis => Self::PrudentSynthesis,
simulator::Action::TrainedFinesse => Self::TrainedFinesse,
simulator::Action::RefinedTouch => Self::RefinedTouch,
simulator::Action::QuickInnovation => Self::QuickInnovation,
simulator::Action::ImmaculateMend => Self::ImmaculateMend,
simulator::Action::TrainedPerfection => Self::TrainedPerfection,
}
}
}

impl From<SolveArgs> for Settings {
fn from(value: SolveArgs) -> Self {
Self {
max_cp: value.cp,
max_durability: value.durability,
max_progress: value.progress,
max_quality: value.quality,
base_progress: value.base_progress,
base_quality: value.base_quality,
job_level: value.job_level,
allowed_actions: ActionMask::from_bits(value.action_mask),
adversarial: value.adversarial,
}
}
}

#[no_mangle]
pub extern "C" fn solve(args: &SolveArgs) {
let flag = AtomicFlag::new();
(args.on_start)(flag.as_ptr());

let settings = Settings::from(*args);
let solution_callback: Box<dyn Fn(&[simulator::Action])> =
if let Some(cb) = args.on_suggest_solution {
Box::new(move |actions| {
cb(actions.as_ptr() as *const Action, actions.len());
})
} else {
Box::new(|_| {})
};
let progress_callback: Box<dyn Fn(usize)> = if let Some(cb) = args.on_progress {
Box::new(move |progress| {
cb(progress);
})
} else {
Box::new(|_| {})
};

let state = SimulationState::new(&settings);

let mut solver = MacroSolver::new(
settings,
args.backload_progress,
args.unsound_branch_pruning,
solution_callback,
progress_callback,
flag.clone(),
);

let actions = solver.solve(state).unwrap_or_default();
(args.on_finish)(actions.as_ptr() as *const Action, actions.len());
}
8 changes: 8 additions & 0 deletions simulator/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ pub struct ActionMask {
}

impl ActionMask {
pub const fn from_bits(mask: u64) -> Self {
Self { mask }
}

pub const fn to_bits(self) -> u64 {
self.mask
}

pub const fn none() -> Self {
Self { mask: 0 }
}
Expand Down
2 changes: 1 addition & 1 deletion solvers/src/macro_solver/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl<'a> MacroSolver<'a> {
}

popped += 1;
if popped % (1 << 14) == 0 {
if popped % (1 << 6) == 0 {
WorkingRobot marked this conversation as resolved.
Show resolved Hide resolved
(self.progress_callback)(popped);
}

Expand Down
4 changes: 4 additions & 0 deletions solvers/src/utils/atomic_flag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ impl AtomicFlag {
}
}

pub fn as_ptr(&self) -> *mut bool {
self.flag.as_ptr()
}

pub fn set(&self) {
self.flag.store(true, Ordering::Relaxed);
}
Expand Down