Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
16 changes: 13 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sanny_builder_core"
version = "0.4.1"
version = "0.4.2"
authors = ["Seemann <mail@sannybuilder.com>"]
edition = "2021"

Expand Down Expand Up @@ -33,4 +33,5 @@ normpath = "1.2"
lines_lossy = "0.1.0"
zip = { git = "https://github.com/x87/zip.git" }
const_format = "0.2.32"
cached = "0.50.0"
cached = "0.50.0"
gta-ide-parser = "0.0.4"
67 changes: 67 additions & 0 deletions src/ide/ffi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use libc::c_char;

use super::model_list::ModelList;

use crate::common_ffi::*;

#[no_mangle]
pub extern "C" fn model_list_new() -> *mut ModelList {
ptr_new(ModelList::new())
}

#[no_mangle]
pub unsafe extern "C" fn model_list_free(list: *mut ModelList) {
ptr_free(list)
}

#[no_mangle]
pub unsafe extern "C" fn model_list_load_from_file(list: *mut ModelList, file_name: PChar) -> bool {
boolclosure!({
list.as_mut()?.load_from_file(pchar_to_str(file_name)?);
Some(())
})
}

#[no_mangle]
pub unsafe extern "C" fn model_list_get_by_id(
list: *mut ModelList,
id: i32,
out: *mut PChar,
) -> bool {
boolclosure!({
*out = list.as_mut()?.find_by_id(id)?.as_ptr();
Some(())
})
}

#[no_mangle]
pub unsafe extern "C" fn model_list_get_by_name(
list: *mut ModelList,
name: PChar,
out_id: *mut i32,
out_type: *mut u8,
) -> bool {
boolclosure!({
let name = pchar_to_str(name)?;
let model = list.as_mut()?.find_by_name(&name)?;
*out_id = model.id;
*out_type = model.r#type as u8;
Some(())
})
}

#[no_mangle]
pub unsafe extern "C" fn model_list_filter_names(
list: *mut ModelList,
needle: PChar,
dict: *mut crate::dictionary::dictionary_str_by_num::DictStrByNum,
) -> bool {
boolclosure!({
let needle = pchar_to_str(needle)?;
let results = list.as_mut()?.filter_by_name(&needle);
for (name, id) in results {
dict.as_mut()?.add(id, name);
}
Some(())
})
}
2 changes: 2 additions & 0 deletions src/ide/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod model_list;
pub mod ffi;
127 changes: 127 additions & 0 deletions src/ide/model_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use ctor::ctor;
use simplelog::*;
use std::{
collections::HashMap,
ffi::{c_char, CString},
path::Path,
};

#[repr(C)]
#[derive(Copy, Clone, PartialEq)]
pub enum ModelType {
Object,
Vehicle,
Ped,
Weapon,
Hier,
}

#[repr(C)]
pub struct Model {
pub id: i32,
pub r#type: ModelType,
}

pub struct ModelList {
pub _by_id: HashMap<i32, CString>,
pub _by_name: HashMap<String, Model>,
pub model_names: Vec<String>,
}

impl ModelList {
pub fn new() -> Self {
Self {
_by_id: HashMap::new(),
_by_name: HashMap::new(),
model_names: Vec::new(),
}
}

pub fn load_from_file(&mut self, file_name: &str) {
let Ok(content) = std::fs::read_to_string(file_name) else {
log::error!("Failed to read file: {}", file_name);
return;
};
let Ok(ide) = gta_ide_parser::parse(&content) else {
log::error!("Failed to parse IDE: {}", file_name);
return;
};
for (section_name, lines) in ide {
if ["txdp", "path", "2dfx"].contains(&section_name.as_str()) {
continue;
}
for line in lines {
let Ok(id) = line[0].parse::<i32>() else {
log::error!("Failed to parse ID: {} in {}", line[0], file_name);
continue;
};
let name = line[1].to_string();
let r#type = match section_name.as_str() {
"objs" | "tobj" | "anim" | "tanm" => ModelType::Object,
"cars" => ModelType::Vehicle,
"peds" => ModelType::Ped,
"weap" => ModelType::Weapon,
"hier" => ModelType::Hier,
_ => {
continue;
}
};

self.model_names.push(name.to_uppercase());
self._by_id
.insert(id, CString::new(name.to_uppercase()).unwrap());
self._by_name
.insert(name.to_ascii_lowercase(), Model { id, r#type });
}
}
}

pub fn find_by_id(&self, id: i32) -> Option<&CString> {
self._by_id.get(&id)
}

pub fn find_by_name(&self, name: &str) -> Option<&Model> {
let needle = &name.to_ascii_lowercase();
match needle.as_str() {
// old parser did not properly handle missing commas, resulting in broken names
"emperoremperor" => {
return Some(&Model {
id: 585,
r#type: ModelType::Vehicle,
})
}
"wayfarerwayfarer" => {
return Some(&Model {
id: 586,
r#type: ModelType::Vehicle,
})
}
"dodododo" => {
return Some(&Model {
id: 593,
r#type: ModelType::Vehicle,
})
}
_ => self._by_name.get(needle),
}
}

pub fn filter_by_name(&self, needle: &str) -> Vec<(CString, i32)> {
let needle = needle.to_ascii_uppercase();
let mut results = Vec::new();
for name in self.model_names.iter() {
if name.contains(&needle) {
if let Some(model) = self.find_by_name(name) {
if model.r#type == ModelType::Object {
continue; // Skip objects
}
results.push((CString::new(name.clone()).unwrap(), model.id));
// if results.len() >= 200 {
// break; // Limit results to 200
// }
}
}
}
results
}
}
7 changes: 7 additions & 0 deletions src/language_service/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ pub unsafe extern "C" fn language_service_format_function_signature(
.map(|param|{
let type_token = token_str(line, &param._type);
let name_token = param.name.as_ref().map(|name| token_str(line, name));
let size_token = param.size.as_ref().map(|size| token_str(line, size));

let type_token = if let Some(size) = size_token {
format!("{}[{}]", type_token, size)
} else {
type_token.to_string()
};

match name_token {
Some(name) => format!("\"{}: {}\"", name, type_token),
Expand Down
7 changes: 6 additions & 1 deletion src/language_service/scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,13 +731,18 @@ fn function_params_and_return_types(line: &str, signature: &FunctionSignature) -
.map(|param| {
let type_token = token_str(line, &param._type);
let name_token = param.name.as_ref().map(|name| token_str(line, name));
let size_token = param.size.as_ref().map(|size| token_str(line, size));

let type_token = if let Some(size) = size_token {
format!("{}[{}]", type_token, size)
} else {
type_token.to_string()
};
match name_token {
Some(name) => format!("{}: {}", name, type_token),
None => format!("{}", type_token),
}
})
// .map(|param| [token_str(line, &param.name), token_str(line, &param._type)].join(": "))
.collect::<Vec<String>>()
.join(", ");

Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod v4;
pub mod source_map;
pub mod preprocessor;
pub mod sanny_update;
pub mod ide;

#[ctor]
fn main() {
Expand All @@ -37,5 +38,5 @@ fn main() {
std::fs::File::create(cwd.join("core.log")).unwrap(),
);

log::info!("core library loaded");
log::info!("core library {} loaded", env!("CARGO_PKG_VERSION"));
}
13 changes: 12 additions & 1 deletion src/namespaces/namespaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,18 @@ impl Namespaces {
use crate::namespaces::enum_parser::{parse_enums, EnumItems};

let content = std::fs::read_to_string(file_name).ok()?;
let (_, enums) = parse_enums(&content).ok()?;
let enums = match parse_enums(&content) {
Ok((rest, enums)) => {
if !rest.is_empty() {
log::warn!("Some enums could not be parsed: {rest} in file: {file_name}");
}
enums
}
Err(e) => {
log::error!("Failed on parsing file {file_name}: {e}");
return None;
}
};
for e in enums {
let mut members = HashMap::new();
match e.items {
Expand Down
Loading
Loading