Compare commits
15 commits
feat/updat
...
master
Author | SHA1 | Date | |
---|---|---|---|
8bbc2184e0 | |||
c1a18cb613 | |||
cf3fdcc3f2 | |||
d5924c3860 | |||
0a9c32adc7 | |||
6f4a5e90e7 | |||
8cffb11df1 | |||
3c2c8ee154 | |||
1e0ff96220 | |||
18300de7f4 | |||
cc03eacb71 | |||
c3f7d54626 | |||
1aa84e3618 | |||
09ac35394e | |||
22906f1065 |
14 changed files with 250 additions and 96 deletions
|
@ -4,12 +4,16 @@ resource_types:
|
||||||
- name: gitea-package
|
- name: gitea-package
|
||||||
type: registry-image
|
type: registry-image
|
||||||
source:
|
source:
|
||||||
repository: registry.local:5000/gitea-package
|
repository: registry.sclu1034.dev/gitea-package
|
||||||
|
username: ((registry_user))
|
||||||
|
password: ((registry_password))
|
||||||
|
|
||||||
- name: gitea-status
|
- name: gitea-status
|
||||||
type: registry-image
|
type: registry-image
|
||||||
source:
|
source:
|
||||||
repository: registry.local:5000/gitea-status
|
repository: registry.sclu1034.dev/gitea-status
|
||||||
|
username: ((registry_user))
|
||||||
|
password: ((registry_password))
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
- name: repo
|
- name: repo
|
||||||
|
@ -84,6 +88,8 @@ jobs:
|
||||||
file: repo/.ci/tasks/clippy.yml
|
file: repo/.ci/tasks/clippy.yml
|
||||||
vars:
|
vars:
|
||||||
forgejo_api_key: ((forgejo_api_key))
|
forgejo_api_key: ((forgejo_api_key))
|
||||||
|
registry_user: ((registry_user))
|
||||||
|
registry_password: ((registry_password))
|
||||||
|
|
||||||
|
|
||||||
- name: build
|
- name: build
|
||||||
|
@ -124,6 +130,8 @@ jobs:
|
||||||
pr: ((pr))
|
pr: ((pr))
|
||||||
forgejo_url: ((forgejo_url))
|
forgejo_url: ((forgejo_url))
|
||||||
forgejo_api_key: ((forgejo_api_key))
|
forgejo_api_key: ((forgejo_api_key))
|
||||||
|
registry_user: ((registry_user))
|
||||||
|
registry_password: ((registry_password))
|
||||||
|
|
||||||
- load_var: version_number
|
- load_var: version_number
|
||||||
reveal: true
|
reveal: true
|
||||||
|
|
|
@ -5,17 +5,23 @@ resource_types:
|
||||||
- name: gitea-package
|
- name: gitea-package
|
||||||
type: registry-image
|
type: registry-image
|
||||||
source:
|
source:
|
||||||
repository: registry.local:5000/gitea-package
|
repository: registry.sclu1034.dev/gitea-package
|
||||||
|
username: ((registry_user))
|
||||||
|
password: ((registry_password))
|
||||||
|
|
||||||
- name: gitea-status
|
- name: gitea-status
|
||||||
type: registry-image
|
type: registry-image
|
||||||
source:
|
source:
|
||||||
repository: registry.local:5000/gitea-status
|
repository: registry.sclu1034.dev/gitea-status
|
||||||
|
username: ((registry_user))
|
||||||
|
password: ((registry_password))
|
||||||
|
|
||||||
- name: gitea-pr
|
- name: gitea-pr
|
||||||
type: registry-image
|
type: registry-image
|
||||||
source:
|
source:
|
||||||
repository: registry.local:5000/gitea-pr
|
repository: registry.sclu1034.dev/gitea-pr
|
||||||
|
username: ((registry_user))
|
||||||
|
password: ((registry_password))
|
||||||
|
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
|
@ -75,6 +81,8 @@ jobs:
|
||||||
forgejo_url: ((forgejo_url))
|
forgejo_url: ((forgejo_url))
|
||||||
owner: ((owner))
|
owner: ((owner))
|
||||||
repo: ((repo))
|
repo: ((repo))
|
||||||
|
registry_user: ((registry_user))
|
||||||
|
registry_password: ((registry_password))
|
||||||
instance_vars:
|
instance_vars:
|
||||||
number: ((.:pr.number))
|
number: ((.:pr.number))
|
||||||
|
|
||||||
|
@ -115,6 +123,8 @@ jobs:
|
||||||
pr: ""
|
pr: ""
|
||||||
forgejo_url: ((forgejo_url))
|
forgejo_url: ((forgejo_url))
|
||||||
forgejo_api_key: ((forgejo_api_key))
|
forgejo_api_key: ((forgejo_api_key))
|
||||||
|
registry_user: ((registry_user))
|
||||||
|
registry_password: ((registry_password))
|
||||||
|
|
||||||
- load_var: version_number
|
- load_var: version_number
|
||||||
reveal: true
|
reveal: true
|
||||||
|
|
|
@ -6,8 +6,10 @@ image_resource:
|
||||||
name: rust-xwin
|
name: rust-xwin
|
||||||
type: registry-image
|
type: registry-image
|
||||||
source:
|
source:
|
||||||
repository: registry.local:5000/rust-xwin-ci
|
repository: registry.sclu1034.dev/rust-xwin-ci
|
||||||
tag: latest
|
tag: latest
|
||||||
|
username: ((registry_user))
|
||||||
|
password: ((registry_password))
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
- name: repo
|
- name: repo
|
||||||
|
|
|
@ -6,8 +6,10 @@ image_resource:
|
||||||
name: rust-xwin-ci
|
name: rust-xwin-ci
|
||||||
type: registry-image
|
type: registry-image
|
||||||
source:
|
source:
|
||||||
repository: registry.local:5000/rust-xwin-ci
|
repository: registry.sclu1034.dev/rust-xwin-ci
|
||||||
tag: latest
|
tag: latest
|
||||||
|
username: ((registry_user))
|
||||||
|
password: ((registry_password))
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
- name: repo
|
- name: repo
|
||||||
|
|
17
.renovaterc
17
.renovaterc
|
@ -1,11 +1,10 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": [
|
"extends": [
|
||||||
"config:recommended",
|
"config:recommended",
|
||||||
":combinePatchMinorReleases",
|
":combinePatchMinorReleases",
|
||||||
":enableVulnerabilityAlerts",
|
":enableVulnerabilityAlerts"
|
||||||
":rebaseStalePrs"
|
],
|
||||||
],
|
"prConcurrentLimit": 10,
|
||||||
"prConcurrentLimit": 10,
|
"branchPrefix": "renovate/"
|
||||||
"branchPrefix": "renovate/"
|
|
||||||
}
|
}
|
||||||
|
|
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -13,9 +13,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bindgen"
|
name = "bindgen"
|
||||||
version = "0.71.1"
|
version = "0.72.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
|
checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cexpr",
|
"cexpr",
|
||||||
|
@ -69,6 +69,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen",
|
"bindgen",
|
||||||
"libc",
|
"libc",
|
||||||
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -94,9 +95,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.172"
|
version = "0.2.174"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
|
@ -110,9 +111,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.22"
|
version = "0.4.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
|
|
|
@ -7,9 +7,10 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.144"
|
libc = "0.2.144"
|
||||||
|
log = { version = "0.4.27", features = ["release_max_level_info"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = "0.71.0"
|
bindgen = "0.72.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib", "lib"]
|
crate-type = ["cdylib", "lib"]
|
||||||
|
|
|
@ -24,7 +24,7 @@ RUN set -eux; \
|
||||||
# And to keep that to a minimum, we still delete the stuff we don't need.
|
# And to keep that to a minimum, we still delete the stuff we don't need.
|
||||||
rm -rf /root/.xwin-cache;
|
rm -rf /root/.xwin-cache;
|
||||||
|
|
||||||
FROM rust:slim-bullseye AS final
|
FROM rust:1.87.0-slim-bullseye AS final
|
||||||
|
|
||||||
ARG LLVM_VERSION=18
|
ARG LLVM_VERSION=18
|
||||||
ENV KEYRINGS=/usr/local/share/keyrings
|
ENV KEYRINGS=/usr/local/share/keyrings
|
||||||
|
@ -37,6 +37,7 @@ RUN set -eux; \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
gpg \
|
gpg \
|
||||||
|
make \
|
||||||
; \
|
; \
|
||||||
mkdir -p $KEYRINGS; \
|
mkdir -p $KEYRINGS; \
|
||||||
gpg --dearmor > $KEYRINGS/llvm.gpg < /root/llvm-snapshot.gpg.key; \
|
gpg --dearmor > $KEYRINGS/llvm.gpg < /root/llvm-snapshot.gpg.key; \
|
||||||
|
@ -69,7 +70,6 @@ RUN set -eux; \
|
||||||
update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 100; \
|
update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 100; \
|
||||||
update-alternatives --install /usr/bin/ld ld /usr/bin/ld.lld 100; \
|
update-alternatives --install /usr/bin/ld ld /usr/bin/ld.lld 100; \
|
||||||
rustup target add x86_64-pc-windows-msvc; \
|
rustup target add x86_64-pc-windows-msvc; \
|
||||||
rustup default stable-x86_64-pc-windows-msvc; \
|
|
||||||
rustup component add rust-src; \
|
rustup component add rust-src; \
|
||||||
rustup update; \
|
rustup update; \
|
||||||
apt-get remove -y --auto-remove \
|
apt-get remove -y --auto-remove \
|
||||||
|
|
110
Justfile
110
Justfile
|
@ -1,11 +1,111 @@
|
||||||
image:
|
set dotenv-load
|
||||||
docker build -t dt-plugin-builder .
|
set dotenv-filename := '.envrc'
|
||||||
|
set dotenv-required
|
||||||
|
set allow-duplicate-variables
|
||||||
|
|
||||||
build:
|
fly_target := "main"
|
||||||
|
image_name := "dt-plugin-builder"
|
||||||
|
|
||||||
|
steam_library := env("steam_library")
|
||||||
|
game_dir := steam_library / "steamapps" / "common" / "Warhammer 40,000 DARKTIDE"
|
||||||
|
log_dir := env("APPDATA") / "Fatshark" / "Darktide" / "console_logs"
|
||||||
|
|
||||||
|
game_dir := if path_exists(game_dir) == true {
|
||||||
|
game_dir
|
||||||
|
} else {
|
||||||
|
error("Game directory does not exist, please set correct library path: " + game_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
proton_dir := home_directory() / ".steam" / "steam"
|
||||||
|
|
||||||
|
export STEAM_COMPAT_DATA_PATH := steam_library / "steamapps" / "compatdata" / "1361210"
|
||||||
|
export SteamAppId := "1361210"
|
||||||
|
|
||||||
|
release := env("RELEASE", "false")
|
||||||
|
|
||||||
|
image:
|
||||||
|
docker build -t {{image_name}} .
|
||||||
|
|
||||||
|
# Compile the Windows DLL through a Docker image
|
||||||
|
[unix]
|
||||||
|
compile:
|
||||||
docker run \
|
docker run \
|
||||||
--rm \
|
--rm \
|
||||||
-t \
|
-t \
|
||||||
--user "$(id -u):$(id -g)" \
|
--user "$(id -u):$(id -g)" \
|
||||||
|
-v $HOME/.cargo/registry:/usr/local/cargo/registry \
|
||||||
|
-v $HOME/.cargo/git:/usr/local/cargo/git \
|
||||||
|
-v $HOME/.rustup/toolchains:/usr/local/rustup/toolchains \
|
||||||
-v ./:/src/plugin \
|
-v ./:/src/plugin \
|
||||||
dt-plugin-builder \
|
{{image_name}} \
|
||||||
cargo build -Zbuild-std --target x86_64-pc-windows-msvc
|
cargo build -Zbuild-std --target x86_64-pc-windows-msvc {{ if release != "false" { "--release" } else { "" } }}
|
||||||
|
|
||||||
|
# Compile the DLL and install it to the game's plugin directory
|
||||||
|
[unix]
|
||||||
|
build: compile
|
||||||
|
cp target/x86_64-pc-windows-msvc/{{ if release != "false" { "release" } else { "debug" } }}/dt_p2p.dll "{{game_dir}}/binaries/plugins/dt_p2p_pluginw64_release.dll"
|
||||||
|
|
||||||
|
# Open the newest game log file
|
||||||
|
[unix]
|
||||||
|
log:
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
file="$(\ls "{{log_dir}}" | tail -1)"
|
||||||
|
echo "$(tput bold)Opening log file $file$(tput sgr0)"
|
||||||
|
exec bat "{{log_dir}}/$file"
|
||||||
|
|
||||||
|
# Run the game through Proton
|
||||||
|
[unix]
|
||||||
|
game:
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
cd "{{game_dir / "binaries"}}"
|
||||||
|
proton waitforexitandrun ./Darktide.exe \
|
||||||
|
-eac-untrusted \
|
||||||
|
--bundle-dir ../bundle \
|
||||||
|
--ini settings \
|
||||||
|
--backend-auth-service-url https://bsp-auth-prod.atoma.cloud \
|
||||||
|
--backend-title-service-url https://bsp-td-prod.atoma.cloud \
|
||||||
|
-game \
|
||||||
|
-launcher_verification_passed_crashify_property false
|
||||||
|
|
||||||
|
# Run the game
|
||||||
|
#
|
||||||
|
# Untested!
|
||||||
|
[windows]
|
||||||
|
game:
|
||||||
|
#!cmd.exe
|
||||||
|
cd "{{game_dir / "binaries"}}"
|
||||||
|
./Darktide.exe \
|
||||||
|
-eac-untrusted \
|
||||||
|
--bundle-dir ../bundle \
|
||||||
|
--ini settings \
|
||||||
|
--backend-auth-service-url https://bsp-auth-prod.atoma.cloud \
|
||||||
|
--backend-title-service-url https://bsp-td-prod.atoma.cloud \
|
||||||
|
-game \
|
||||||
|
-launcher_verification_passed_crashify_property false
|
||||||
|
|
||||||
|
# Compile the plugin through a Docker image
|
||||||
|
#
|
||||||
|
# Make sure to run `just image` first, to build the image.
|
||||||
|
# Untested: I don't know, if this works with Windows' Docker Desktop.
|
||||||
|
# I also don't know if/where cargo and rustup keep their caches on Windows.
|
||||||
|
[windows]
|
||||||
|
compile-docker:
|
||||||
|
docker run \
|
||||||
|
--rm \
|
||||||
|
-t \
|
||||||
|
-v ./:/src/plugin \
|
||||||
|
{{image_name}} \
|
||||||
|
cargo build -Zbuild-std --target x86_64-pc-windows-msvc {{ if release != "false" { "--release" } else { "" } }}
|
||||||
|
|
||||||
|
set-base-pipeline:
|
||||||
|
fly -t {{fly_target}} set-pipeline \
|
||||||
|
--pipeline dt-plugin-template-pr \
|
||||||
|
--config .ci/pipelines/set-pr-pipelines.yml \
|
||||||
|
-v forgejo_url=https://git.sclu1034.dev \
|
||||||
|
-v forgejo_api_key=${FORGEJO_API_KEY} \
|
||||||
|
-v registry_user=${REGISTRY_USER} \
|
||||||
|
-v registry_password=${REGISTRY_PASSWORD} \
|
||||||
|
-v owner=bitsquid_dt \
|
||||||
|
-v repo=dt-plugin-template
|
||||||
|
|
36
src/lib.rs
36
src/lib.rs
|
@ -1,11 +1,12 @@
|
||||||
use std::ffi::{c_char, CString};
|
use std::ffi::{c_char, CString};
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
mod lua;
|
||||||
mod plugin;
|
mod plugin;
|
||||||
mod stingray_sdk;
|
mod stingray_sdk;
|
||||||
|
|
||||||
use plugin::Plugin;
|
use plugin::Plugin;
|
||||||
use stingray_sdk::{GetApiFunction, PluginApi, PluginApiID};
|
use stingray_sdk::{GetApiFunction, LoggingApi, LuaApi, PluginApi, PluginApiID};
|
||||||
|
|
||||||
// TODO: Change these
|
// TODO: Change these
|
||||||
/// The name that the plugin is registered to the engine as.
|
/// The name that the plugin is registered to the engine as.
|
||||||
|
@ -15,6 +16,20 @@ pub const PLUGIN_NAME: &str = "dt-plugin-template";
|
||||||
pub const MODULE_NAME: &str = "DTPluginTemplate";
|
pub const MODULE_NAME: &str = "DTPluginTemplate";
|
||||||
|
|
||||||
static PLUGIN: OnceLock<Plugin> = OnceLock::new();
|
static PLUGIN: OnceLock<Plugin> = OnceLock::new();
|
||||||
|
static LOGGER: OnceLock<LoggingApi> = OnceLock::new();
|
||||||
|
static LUA: OnceLock<LuaApi> = OnceLock::new();
|
||||||
|
|
||||||
|
/// A macro to make accessing global statics a little more convenient.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! global {
|
||||||
|
($name:ident) => {{
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
$name.get().expect("global has not been initialized")
|
||||||
|
} else {
|
||||||
|
unsafe { $name.get().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn get_name() -> *const c_char {
|
pub extern "C" fn get_name() -> *const c_char {
|
||||||
|
@ -24,26 +39,25 @@ pub extern "C" fn get_name() -> *const c_char {
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn setup_game(get_engine_api: GetApiFunction) {
|
pub extern "C" fn setup_game(get_engine_api: GetApiFunction) {
|
||||||
let plugin = Plugin::new(get_engine_api);
|
let logger = LOGGER.get_or_init(|| LoggingApi::get(get_engine_api));
|
||||||
|
log::set_logger(logger).expect("Failed to set global logger.");
|
||||||
|
log::set_max_level(log::LevelFilter::Info);
|
||||||
|
|
||||||
|
let _ = LUA.get_or_init(|| LuaApi::get(get_engine_api));
|
||||||
|
|
||||||
|
let plugin = PLUGIN.get_or_init(Plugin::new);
|
||||||
plugin.setup_game();
|
plugin.setup_game();
|
||||||
PLUGIN
|
|
||||||
.set(plugin)
|
|
||||||
.expect("Failed to initalize global plugin object.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn shutdown_game() {
|
pub extern "C" fn shutdown_game() {
|
||||||
// Safety: The engine ensures that `setup_game` was called before this, so `PLUGIN` has been
|
let plugin = global!(PLUGIN);
|
||||||
// initialized.
|
|
||||||
let plugin = unsafe { PLUGIN.get().unwrap_unchecked() };
|
|
||||||
plugin.shutdown_game();
|
plugin.shutdown_game();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn update_game(dt: f32) {
|
pub extern "C" fn update_game(dt: f32) {
|
||||||
// Safety: The engine ensures that `setup_game` was called before this, so `PLUGIN` has been
|
let plugin = global!(PLUGIN);
|
||||||
// initialized.
|
|
||||||
let plugin = unsafe { PLUGIN.get().unwrap_unchecked() };
|
|
||||||
plugin.update_game(dt);
|
plugin.update_game(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
src/lua.rs
Normal file
16
src/lua.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use crate::stingray_sdk::lua_State;
|
||||||
|
use crate::{LUA, global};
|
||||||
|
|
||||||
|
pub extern "C" fn do_something(l: *mut lua_State) -> i32 {
|
||||||
|
let lua = global!(LUA);
|
||||||
|
|
||||||
|
if let Some(name) = lua.tolstring(l, 1) {
|
||||||
|
lua.pushstring(
|
||||||
|
l,
|
||||||
|
format!("[do_something] Hello from Rust, {}", name.to_string_lossy()),
|
||||||
|
);
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,47 +1,23 @@
|
||||||
use crate::stingray_sdk::{lua_State, GetApiFunction, LoggingApi, LuaApi};
|
use log::info;
|
||||||
use crate::{MODULE_NAME, PLUGIN, PLUGIN_NAME};
|
|
||||||
|
|
||||||
pub(crate) struct Plugin {
|
use crate::{LUA, MODULE_NAME, PLUGIN_NAME, global, lua};
|
||||||
pub log: LoggingApi,
|
|
||||||
pub lua: LuaApi,
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn do_something(l: *mut lua_State) -> i32 {
|
pub(crate) struct Plugin {}
|
||||||
// Safety: Plugin must have been initialized for this to be registered as module
|
|
||||||
// function.
|
|
||||||
let plugin = unsafe { PLUGIN.get().unwrap_unchecked() };
|
|
||||||
|
|
||||||
if let Some(name) = plugin.lua.tolstring(l, 1) {
|
|
||||||
plugin.lua.pushstring(
|
|
||||||
l,
|
|
||||||
format!("[do_something] Hello from Rust, {}", name.to_string_lossy()),
|
|
||||||
);
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Plugin {
|
impl Plugin {
|
||||||
pub fn new(get_engine_api: GetApiFunction) -> Self {
|
pub fn new() -> Self {
|
||||||
let log = LoggingApi::get(get_engine_api);
|
Self {}
|
||||||
let lua = LuaApi::get(get_engine_api);
|
|
||||||
Self { log, lua }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_game(&self) {
|
pub fn setup_game(&self) {
|
||||||
self.log.info(
|
info!("[setup_game] Hello, world! This is {}!", PLUGIN_NAME);
|
||||||
PLUGIN_NAME,
|
|
||||||
format!("[setup_game] Hello, world! This is {}!", PLUGIN_NAME),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.lua
|
let lua = global!(LUA);
|
||||||
.add_module_function(MODULE_NAME, "do_something", do_something);
|
lua.add_module_function(MODULE_NAME, "do_something", lua::do_something);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shutdown_game(&self) {
|
pub fn shutdown_game(&self) {
|
||||||
self.log
|
info!("[shutdown_game] Goodbye, world!");
|
||||||
.info(PLUGIN_NAME, "[shutdown_game] Goodbye, world!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_game(&self, _dt: f32) {}
|
pub fn update_game(&self, _dt: f32) {}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
// This is a manually updated and minified PluginApi based on the publicly
|
// This is manually updated and minified PluginApi based on the publicly
|
||||||
// available sources at: https://github.com/AutodeskGames/stingray-plugin
|
// available sources at: https://github.com/AutodeskGames/stingray-plugin
|
||||||
// From
|
// From
|
||||||
// https://github.com/thewhitegoatcb/rawray/blob/master/rawray/PluginApi128.h
|
// https://github.com/thewhitegoatcb/rawray/blob/master/rawray/PluginApi128.h
|
||||||
|
@ -59,7 +59,7 @@ enum PluginApiID {
|
||||||
CAMERA_API_ID = 38,
|
CAMERA_API_ID = 38,
|
||||||
END_OF_ENGINE_RESERVED_RANGE = 65535,
|
END_OF_ENGINE_RESERVED_RANGE = 65535,
|
||||||
|
|
||||||
/* API IDs in the range 0-65535 are reserved by the engine. If you want to
|
/* API IDs in the range 0--65535 are reserved by the engine. If you want to
|
||||||
provide your own API in your plugin, we suggest using a hash of the API's
|
provide your own API in your plugin, we suggest using a hash of the API's
|
||||||
name as ID. */
|
name as ID. */
|
||||||
};
|
};
|
||||||
|
@ -83,13 +83,19 @@ struct PluginApi {
|
||||||
loaded. */
|
loaded. */
|
||||||
void (*loaded)(GetApiFunction get_engine_api);
|
void (*loaded)(GetApiFunction get_engine_api);
|
||||||
|
|
||||||
|
// Seemingly not called by current versions of the engine, at least in release
|
||||||
|
// mode.
|
||||||
/* Called at the start of a "hot reload" of the plugin DLL. Should return a
|
/* Called at the start of a "hot reload" of the plugin DLL. Should return a
|
||||||
pointer to a serialized "state" for the plugin.*/
|
pointer to a serialized "state" for the plugin.*/
|
||||||
void *(*start_reload)(GetApiFunction get_engine_api);
|
void *(*start_reload)(GetApiFunction get_engine_api);
|
||||||
|
|
||||||
|
// Seemingly not called by current versions of the engine, at least in release
|
||||||
|
// mode.
|
||||||
/* Called just before the plugin is unloaded. */
|
/* Called just before the plugin is unloaded. */
|
||||||
void (*unloaded)();
|
void (*unloaded)();
|
||||||
|
|
||||||
|
// Seemingly not called by current versions of the engine, at least in release
|
||||||
|
// mode.
|
||||||
/* Called to finalized the "hot reload" after the plugin has been reloaded
|
/* Called to finalized the "hot reload" after the plugin has been reloaded
|
||||||
with the new code. Should restore the state from the serialized state data.
|
with the new code. Should restore the state from the serialized state data.
|
||||||
Note that it is the responsibility of the plugin to free the state data. */
|
Note that it is the responsibility of the plugin to free the state data. */
|
||||||
|
@ -223,9 +229,8 @@ struct LuaApi {
|
||||||
int (*checkstack)(lua_State *L, int sz);
|
int (*checkstack)(lua_State *L, int sz);
|
||||||
void (*xmove)(lua_State *from, lua_State *to, int n);
|
void (*xmove)(lua_State *from, lua_State *to, int n);
|
||||||
|
|
||||||
const void *(*fnx1)(lua_State *L, int idx);
|
|
||||||
|
|
||||||
/* Access functions */
|
/* Access functions */
|
||||||
|
int (*isnil)(lua_State *L, int idx);
|
||||||
int (*isnumber)(lua_State *L, int idx);
|
int (*isnumber)(lua_State *L, int idx);
|
||||||
int (*isstring)(lua_State *L, int idx);
|
int (*isstring)(lua_State *L, int idx);
|
||||||
int (*iscfunction)(lua_State *L, int idx);
|
int (*iscfunction)(lua_State *L, int idx);
|
||||||
|
@ -313,8 +318,6 @@ struct LuaApi {
|
||||||
int (*gethookmask)(lua_State *L);
|
int (*gethookmask)(lua_State *L);
|
||||||
int (*gethookcount)(lua_State *L);
|
int (*gethookcount)(lua_State *L);
|
||||||
|
|
||||||
// int (*fnx3) (lua_State* L);
|
|
||||||
|
|
||||||
/* Library functions */
|
/* Library functions */
|
||||||
void (*lib_openlib)(lua_State *L, const char *libname, const luaL_Reg *l,
|
void (*lib_openlib)(lua_State *L, const char *libname, const luaL_Reg *l,
|
||||||
int nup);
|
int nup);
|
||||||
|
@ -399,6 +402,8 @@ struct LuaApi {
|
||||||
/* Gets a Unit at the specified index. */
|
/* Gets a Unit at the specified index. */
|
||||||
CApiUnit *(*getunit)(lua_State *L, int i);
|
CApiUnit *(*getunit)(lua_State *L, int i);
|
||||||
|
|
||||||
|
void *(*getunknown)(lua_State *L, int i);
|
||||||
|
|
||||||
/* Gets the Lua state where the main scripts execute. */
|
/* Gets the Lua state where the main scripts execute. */
|
||||||
lua_State *(*getscriptenvironmentstate)();
|
lua_State *(*getscriptenvironmentstate)();
|
||||||
|
|
||||||
|
@ -423,8 +428,10 @@ struct LuaApi {
|
||||||
/* Returns true if the stack entry is a UnitReference. */
|
/* Returns true if the stack entry is a UnitReference. */
|
||||||
int (*isunitreference)(lua_State *L, int i);
|
int (*isunitreference)(lua_State *L, int i);
|
||||||
|
|
||||||
|
size_t (*objlen2)(lua_State *L, int idx);
|
||||||
|
|
||||||
/* Reserved for expansion of the API. */
|
/* Reserved for expansion of the API. */
|
||||||
void *reserved[32];
|
// void *reserved[30];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LoggingApi {
|
struct LoggingApi {
|
||||||
|
|
|
@ -13,22 +13,18 @@ use std::ffi::CString;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
use bindings::lua_CFunction;
|
|
||||||
pub use bindings::lua_State;
|
|
||||||
pub use bindings::GetApiFunction;
|
pub use bindings::GetApiFunction;
|
||||||
pub use bindings::PluginApi;
|
pub use bindings::PluginApi;
|
||||||
pub use bindings::PluginApiID;
|
pub use bindings::PluginApiID;
|
||||||
|
use bindings::lua_CFunction;
|
||||||
// The API version. This must match with the game you're building the plugin for.
|
pub use bindings::lua_State;
|
||||||
const STINGRAY_PLUGIN_VERSION: u32 = 69;
|
use log::Level;
|
||||||
// A set of bitflags. The value `3` is known to work for Lua plugins.
|
|
||||||
const STINGRAY_PLUGIN_FLAGS: u32 = 3;
|
|
||||||
|
|
||||||
impl std::default::Default for PluginApi {
|
impl std::default::Default for PluginApi {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
version: STINGRAY_PLUGIN_VERSION,
|
version: 69,
|
||||||
flags: STINGRAY_PLUGIN_FLAGS,
|
flags: 3,
|
||||||
setup_game: None,
|
setup_game: None,
|
||||||
update_game: None,
|
update_game: None,
|
||||||
shutdown_game: None,
|
shutdown_game: None,
|
||||||
|
@ -58,12 +54,11 @@ fn get_engine_api(f: GetApiFunction, id: PluginApiID) -> *mut c_void {
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
fn get_engine_api(f: GetApiFunction, id: PluginApiID) -> *mut c_void {
|
fn get_engine_api(f: GetApiFunction, id: PluginApiID) -> *mut c_void {
|
||||||
unsafe {
|
// `Option::unwrap` still generates several instructions in
|
||||||
// `Option::unwrap` still generates several instructions in
|
// optimized code.
|
||||||
// optimized code.
|
let f = unsafe { f.unwrap_unchecked() };
|
||||||
let f = f.unwrap_unchecked();
|
|
||||||
f(id as u32)
|
unsafe { f(id as u32) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LoggingApi {
|
pub struct LoggingApi {
|
||||||
|
@ -113,6 +108,29 @@ impl LoggingApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl log::Log for LoggingApi {
|
||||||
|
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(&self, record: &log::Record) {
|
||||||
|
if !self.enabled(record.metadata()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let line = if let Some(s) = record.args().as_str() {
|
||||||
|
format!("[{}] {}", record.level(), s)
|
||||||
|
} else {
|
||||||
|
format!("[{}] {}", record.level(), record.args())
|
||||||
|
};
|
||||||
|
|
||||||
|
self.info(record.target(), line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The engine does not expose a method to flush the log
|
||||||
|
fn flush(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum LuaType {
|
pub enum LuaType {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue