mirror of
https://github.com/jugeeya/UltimateTrainingModpack.git
synced 2024-11-24 02:44:17 +00:00
Convert line separators from CRLF to LF (#499)
This commit is contained in:
parent
e0fec0039e
commit
c3a36e78e5
10 changed files with 1605 additions and 1605 deletions
298
.github/workflows/rust.yml
vendored
298
.github/workflows/rust.yml
vendored
|
@ -1,149 +1,149 @@
|
|||
name: Rust
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
checker:
|
||||
name: Check, Clippy, Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install minimal nightly rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
components: rustfmt, clippy
|
||||
default: true
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
name: Rust Cache
|
||||
with:
|
||||
prefix-key: "checker"
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
continue-on-error: false
|
||||
with:
|
||||
command: clippy
|
||||
args: --all-targets --all-features --target=x86_64-unknown-linux-gnu -- -D warnings
|
||||
- name: TUI Test
|
||||
uses: actions-rs/cargo@v1
|
||||
continue-on-error: false
|
||||
with:
|
||||
working-directory: training_mod_tui
|
||||
plugin:
|
||||
name: Plugin NRO
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: jugeeya/cargo-skyline:3.2.0-no-dkp
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
name: Rust Cache
|
||||
with:
|
||||
prefix-key: "plugin"
|
||||
- name: Build release NRO
|
||||
id: build_release
|
||||
run: cargo-skyline skyline build --release
|
||||
env:
|
||||
HOME: /root
|
||||
- name: Upload plugin artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: plugin
|
||||
path: target/aarch64-skyline-switch/release/libtraining_modpack.nro
|
||||
plugin_outside_training_mode:
|
||||
name: Plugin NRO (Outside Training Mode)
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: jugeeya/cargo-skyline:3.2.0-no-dkp
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
name: Rust Cache
|
||||
with:
|
||||
prefix-key: "plugin"
|
||||
- name: Build outside_training_mode NRO
|
||||
run: |
|
||||
cargo-skyline skyline build --release --features outside_training_mode
|
||||
env:
|
||||
HOME: /root
|
||||
- name: Upload plugin (outside training mode) artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: plugin_outside_training_mode
|
||||
path: target/aarch64-skyline-switch/release/libtraining_modpack.nro
|
||||
upload:
|
||||
name: Upload Beta Release
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/main'
|
||||
needs:
|
||||
- plugin
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
- name: Prepare zip
|
||||
id: prepare_zip
|
||||
env:
|
||||
SMASH_PLUGIN_DIR: atmosphere/contents/01006A800016E000/romfs/skyline/plugins
|
||||
run: |
|
||||
mkdir -p ${{env.SMASH_PLUGIN_DIR}}
|
||||
cp plugin/libtraining_modpack.nro ${{env.SMASH_PLUGIN_DIR}}/libtraining_modpack.nro
|
||||
wget https://github.com/ultimate-research/params-hook-plugin/releases/download/v13.0.1/libparam_hook.nro
|
||||
wget https://github.com/ultimate-research/nro-hook-plugin/releases/download/v0.4.0/libnro_hook.nro
|
||||
wget https://github.com/jugeeya/nn-hid-hook/releases/download/beta/libnn_hid_hook.nro
|
||||
cp libparam_hook.nro ${{env.SMASH_PLUGIN_DIR}}/libparam_hook.nro
|
||||
cp libnro_hook.nro ${{env.SMASH_PLUGIN_DIR}}/libnro_hook.nro
|
||||
cp libnn_hid_hook.nro ${{env.SMASH_PLUGIN_DIR}}/libnn_hid_hook.nro
|
||||
zip -r training_modpack_beta.zip atmosphere
|
||||
- name: Delete Release
|
||||
uses: dev-drprasad/delete-tag-and-release@v0.2.0
|
||||
with:
|
||||
tag_name: beta
|
||||
delete_release: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Update Release
|
||||
uses: meeDamian/github-release@2.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
prerelease: true
|
||||
allow_override: true
|
||||
gzip: false
|
||||
tag: beta
|
||||
commitish: main
|
||||
name: beta
|
||||
body: >
|
||||
Beta built off of the latest code in the repository.
|
||||
|
||||
# Changelog
|
||||
|
||||
You can find the changelog here: https://github.com/jugeeya/UltimateTrainingModpack#beta-changelog
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
*For fuller instructions, please join the [Discord](https://discord.gg/xUZWJ5BWe7) and visit the #setup-and-download channel.*
|
||||
|
||||
- (*Console only*) Install Atmosphere to your hacked Switch. One great guide can be found at https://switch.homebrew.guide/
|
||||
|
||||
- Place the **contents** of the `training_modpack_beta.zip` on the root of your SD card. This means that you first unzip the file, then place its folder on the SD card root. The `atmosphere` folder should be **merged** onto the root of your SD card.
|
||||
|
||||
- *For Ryujinx*: Paste the `contents` folder inside `atmosphere` into `%AppData%/Ryujinx/mods/`
|
||||
|
||||
- Download Skyline: https://github.com/skyline-dev/skyline/releases. Place the `exefs` folder from the zip into `atmosphere/contents/01006A800016E000` on your SD card.
|
||||
|
||||
- *For Ryujinx*: Paste these files in `%AppData%/Ryujinx/mods/contents/01006a800016e000`
|
||||
files: >
|
||||
training_modpack_beta.zip
|
||||
- name: Upload zip as artifact
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: full_build
|
||||
path: training_modpack_beta.zip
|
||||
name: Rust
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
checker:
|
||||
name: Check, Clippy, Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install minimal nightly rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
components: rustfmt, clippy
|
||||
default: true
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
name: Rust Cache
|
||||
with:
|
||||
prefix-key: "checker"
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
continue-on-error: false
|
||||
with:
|
||||
command: clippy
|
||||
args: --all-targets --all-features --target=x86_64-unknown-linux-gnu -- -D warnings
|
||||
- name: TUI Test
|
||||
uses: actions-rs/cargo@v1
|
||||
continue-on-error: false
|
||||
with:
|
||||
working-directory: training_mod_tui
|
||||
plugin:
|
||||
name: Plugin NRO
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: jugeeya/cargo-skyline:3.2.0-no-dkp
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
name: Rust Cache
|
||||
with:
|
||||
prefix-key: "plugin"
|
||||
- name: Build release NRO
|
||||
id: build_release
|
||||
run: cargo-skyline skyline build --release
|
||||
env:
|
||||
HOME: /root
|
||||
- name: Upload plugin artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: plugin
|
||||
path: target/aarch64-skyline-switch/release/libtraining_modpack.nro
|
||||
plugin_outside_training_mode:
|
||||
name: Plugin NRO (Outside Training Mode)
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: jugeeya/cargo-skyline:3.2.0-no-dkp
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
name: Rust Cache
|
||||
with:
|
||||
prefix-key: "plugin"
|
||||
- name: Build outside_training_mode NRO
|
||||
run: |
|
||||
cargo-skyline skyline build --release --features outside_training_mode
|
||||
env:
|
||||
HOME: /root
|
||||
- name: Upload plugin (outside training mode) artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: plugin_outside_training_mode
|
||||
path: target/aarch64-skyline-switch/release/libtraining_modpack.nro
|
||||
upload:
|
||||
name: Upload Beta Release
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/main'
|
||||
needs:
|
||||
- plugin
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
- name: Prepare zip
|
||||
id: prepare_zip
|
||||
env:
|
||||
SMASH_PLUGIN_DIR: atmosphere/contents/01006A800016E000/romfs/skyline/plugins
|
||||
run: |
|
||||
mkdir -p ${{env.SMASH_PLUGIN_DIR}}
|
||||
cp plugin/libtraining_modpack.nro ${{env.SMASH_PLUGIN_DIR}}/libtraining_modpack.nro
|
||||
wget https://github.com/ultimate-research/params-hook-plugin/releases/download/v13.0.1/libparam_hook.nro
|
||||
wget https://github.com/ultimate-research/nro-hook-plugin/releases/download/v0.4.0/libnro_hook.nro
|
||||
wget https://github.com/jugeeya/nn-hid-hook/releases/download/beta/libnn_hid_hook.nro
|
||||
cp libparam_hook.nro ${{env.SMASH_PLUGIN_DIR}}/libparam_hook.nro
|
||||
cp libnro_hook.nro ${{env.SMASH_PLUGIN_DIR}}/libnro_hook.nro
|
||||
cp libnn_hid_hook.nro ${{env.SMASH_PLUGIN_DIR}}/libnn_hid_hook.nro
|
||||
zip -r training_modpack_beta.zip atmosphere
|
||||
- name: Delete Release
|
||||
uses: dev-drprasad/delete-tag-and-release@v0.2.0
|
||||
with:
|
||||
tag_name: beta
|
||||
delete_release: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Update Release
|
||||
uses: meeDamian/github-release@2.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
prerelease: true
|
||||
allow_override: true
|
||||
gzip: false
|
||||
tag: beta
|
||||
commitish: main
|
||||
name: beta
|
||||
body: >
|
||||
Beta built off of the latest code in the repository.
|
||||
|
||||
# Changelog
|
||||
|
||||
You can find the changelog here: https://github.com/jugeeya/UltimateTrainingModpack#beta-changelog
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
*For fuller instructions, please join the [Discord](https://discord.gg/xUZWJ5BWe7) and visit the #setup-and-download channel.*
|
||||
|
||||
- (*Console only*) Install Atmosphere to your hacked Switch. One great guide can be found at https://switch.homebrew.guide/
|
||||
|
||||
- Place the **contents** of the `training_modpack_beta.zip` on the root of your SD card. This means that you first unzip the file, then place its folder on the SD card root. The `atmosphere` folder should be **merged** onto the root of your SD card.
|
||||
|
||||
- *For Ryujinx*: Paste the `contents` folder inside `atmosphere` into `%AppData%/Ryujinx/mods/`
|
||||
|
||||
- Download Skyline: https://github.com/skyline-dev/skyline/releases. Place the `exefs` folder from the zip into `atmosphere/contents/01006A800016E000` on your SD card.
|
||||
|
||||
- *For Ryujinx*: Paste these files in `%AppData%/Ryujinx/mods/contents/01006a800016e000`
|
||||
files: >
|
||||
training_modpack_beta.zip
|
||||
- name: Upload zip as artifact
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: full_build
|
||||
path: training_modpack_beta.zip
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
pub use training_mod_consts::*;
|
||||
|
||||
pub use training_mod_consts::*;
|
||||
|
||||
|
|
|
@ -1,242 +1,242 @@
|
|||
use std::ops::Neg;
|
||||
|
||||
use smash::app;
|
||||
use smash::phx::{Hash40, Vector3f};
|
||||
|
||||
pub const RAYGUN_LENGTH: f32 = 8.0;
|
||||
pub const RAYGUN_HEIGHT: f32 = 6.0;
|
||||
pub const RAYGUN_HORIZ_OFFSET: f32 = 2.0;
|
||||
|
||||
/*
|
||||
segment data list : {Z, Y, X, ZRot, Size}
|
||||
segment labels :
|
||||
_
|
||||
|_| from top to top left, clockwise: a->f + g mid + \|/ from top mid to top left, clockwise: h->m + --two half g's: n, o
|
||||
|_| /|\
|
||||
*/
|
||||
|
||||
pub static SEGMENT_DICT: [[f32; 5]; 15] = [
|
||||
[0.0, RAYGUN_HEIGHT * 2.0, 0.0, 0.0, 0.25], // a
|
||||
[0.0, RAYGUN_HEIGHT, RAYGUN_LENGTH, 90.0, 0.25], // b
|
||||
[0.0, 0.0, RAYGUN_LENGTH, 90.0, 0.25], // c
|
||||
[0.0, 0.0, 0.0, 0.0, 0.25], // d
|
||||
[0.0, 0.0, 0.0, 90.0, 0.25], // e
|
||||
[0.0, RAYGUN_HEIGHT, 0.0, 90.0, 0.25], // f
|
||||
[0.0, RAYGUN_HEIGHT, 0.0, 0.0, 0.25], // g mid
|
||||
[0.0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2.0, 90.0, 0.25], // h
|
||||
[0.0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2.0, 52.0, 0.2], // i
|
||||
[0.0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2.0, -52.0, 0.2], // j
|
||||
[0.0, 0.0, RAYGUN_LENGTH / 2.0, 90.0, 0.25], // k
|
||||
[
|
||||
0.0,
|
||||
RAYGUN_HEIGHT / 2.0,
|
||||
RAYGUN_LENGTH * 3.0 / 16.0,
|
||||
52.0,
|
||||
0.2,
|
||||
], // l
|
||||
[
|
||||
0.0,
|
||||
RAYGUN_HEIGHT * 3.0 / 2.0,
|
||||
RAYGUN_LENGTH * 3.0 / 16.0,
|
||||
-52.0,
|
||||
0.2,
|
||||
], // m
|
||||
[0.0, RAYGUN_HEIGHT, 0.0, 0.0, 0.15], // n
|
||||
[0.0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2.0, 0.0, 0.15], // o
|
||||
];
|
||||
|
||||
/*
|
||||
Segments making up each character, each index corresponding to:
|
||||
'A' through 'Z', '0' through '9', ' ', '-', '+', '#' (where '#' is all segments)
|
||||
*/
|
||||
pub static ALPHABET: [&str; 40] = [
|
||||
"abcefg",
|
||||
"adefijn",
|
||||
"adef",
|
||||
"eflm",
|
||||
"adefn",
|
||||
"aefn",
|
||||
"acdefo",
|
||||
"bcefg",
|
||||
"adhk",
|
||||
"bcd",
|
||||
"efnij",
|
||||
"def",
|
||||
"bcefim",
|
||||
"bcefjm",
|
||||
"abcdef",
|
||||
"abefg",
|
||||
"abcdefj",
|
||||
"aefijn",
|
||||
"acdfg",
|
||||
"ahk",
|
||||
"bcdef",
|
||||
"efil",
|
||||
"bcefjl",
|
||||
"ijlm",
|
||||
"ikm",
|
||||
"adil",
|
||||
"abcdef",
|
||||
"ef",
|
||||
"abdeg",
|
||||
"abcdg",
|
||||
"bcfg",
|
||||
"acdfg",
|
||||
"acdefg",
|
||||
"abc",
|
||||
"abcdefg",
|
||||
"abcdfg",
|
||||
"",
|
||||
"g",
|
||||
"ghk",
|
||||
"abcdefhijklmno",
|
||||
];
|
||||
|
||||
// Each index is a segment's corresponding flipped segment, for when facing left
|
||||
pub static SEGMENT_REV: [char; 15] = [
|
||||
'a', 'f', 'e', 'd', 'c', 'b', 'g', 'h', 'm', 'l', 'k', 'j', 'i', 'o', 'n',
|
||||
];
|
||||
|
||||
fn show_segment(
|
||||
module_accessor: &mut app::BattleObjectModuleAccessor,
|
||||
z: f32,
|
||||
y: f32,
|
||||
x: f32,
|
||||
zrot: f32,
|
||||
size: f32,
|
||||
) {
|
||||
let pos = Vector3f { x, y, z };
|
||||
let rot = Vector3f {
|
||||
x: 0.0,
|
||||
y: 90.0,
|
||||
z: zrot,
|
||||
};
|
||||
let random = Vector3f {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
app::lua_bind::EffectModule::req_on_joint(
|
||||
module_accessor,
|
||||
Hash40::new("sys_raygun_bullet"),
|
||||
Hash40::new("top"),
|
||||
&pos,
|
||||
&rot,
|
||||
size,
|
||||
&random,
|
||||
&random,
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn alphabet_index(to_print: char) -> i32 {
|
||||
match to_print {
|
||||
'A'..='Z' => to_print as i32 - 'A' as i32,
|
||||
'0'..='9' => to_print as i32 - '0' as i32 + 'Z' as i32 - 'A' as i32 + 1,
|
||||
' ' => 36,
|
||||
'-' => 37,
|
||||
'+' => 38,
|
||||
'#' => 39,
|
||||
_ => -1,
|
||||
}
|
||||
}
|
||||
|
||||
fn print_char(
|
||||
module_accessor: &mut app::BattleObjectModuleAccessor,
|
||||
to_print: char,
|
||||
line_num: i32,
|
||||
horiz_offset: f32,
|
||||
facing_left: i32,
|
||||
) {
|
||||
let is_facing_left = facing_left == -1;
|
||||
let x_direction = facing_left as f32;
|
||||
|
||||
let alph_index = alphabet_index(to_print);
|
||||
if !(0..40).contains(&alph_index) {
|
||||
return;
|
||||
}
|
||||
let segment_str = ALPHABET[alph_index as usize];
|
||||
|
||||
let line_offset = 40.0 - ((line_num as f32) * 16.0);
|
||||
|
||||
for segment_char in segment_str.chars() {
|
||||
let mut index = segment_char as i32 - 'a' as i32;
|
||||
|
||||
if is_facing_left {
|
||||
index = SEGMENT_REV[index as usize] as i32 - 'a' as i32;
|
||||
}
|
||||
let segment = SEGMENT_DICT[index as usize];
|
||||
|
||||
const SIZE_MULT: f32 = 0.5;
|
||||
|
||||
let x = ((segment[2] + horiz_offset) * SIZE_MULT) + (x_direction * 5.0);
|
||||
let y = ((segment[1] + line_offset) * SIZE_MULT) + 5.0;
|
||||
let z = segment[0] * SIZE_MULT;
|
||||
|
||||
let zrot = segment[3];
|
||||
let zrot = if is_facing_left { zrot.neg() } else { zrot };
|
||||
|
||||
let size = segment[4] * SIZE_MULT;
|
||||
|
||||
show_segment(module_accessor, z, y, x, zrot, size);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_string(module_accessor: &mut app::BattleObjectModuleAccessor, to_write: &str) {
|
||||
// Delete any previous strings
|
||||
unsafe {
|
||||
app::lua_bind::EffectModule::kill_kind(
|
||||
module_accessor,
|
||||
Hash40::new("sys_raygun_bullet"),
|
||||
false,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
let mut line_num = 0;
|
||||
let mut horiz_offset = 0.0;
|
||||
let mut char_num = 0;
|
||||
|
||||
let facing_left = unsafe { app::lua_bind::PostureModule::lr(module_accessor) as i32 };
|
||||
let facing_direction = facing_left as f32;
|
||||
|
||||
if to_write.len() <= 8 && !to_write.contains('\n') {
|
||||
line_num = 1;
|
||||
}
|
||||
for curr_char in to_write.chars() {
|
||||
if curr_char == '\n' {
|
||||
horiz_offset = 0.0;
|
||||
char_num = 0;
|
||||
line_num += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
print_char(
|
||||
module_accessor,
|
||||
curr_char.to_uppercase().collect::<Vec<_>>()[0],
|
||||
line_num,
|
||||
horiz_offset,
|
||||
facing_left,
|
||||
);
|
||||
|
||||
char_num += 1;
|
||||
// short characters
|
||||
if curr_char == 'D' || curr_char == '1' {
|
||||
horiz_offset += facing_direction * (RAYGUN_LENGTH / 2.0 + 3.0);
|
||||
} else {
|
||||
horiz_offset += facing_direction * (RAYGUN_LENGTH + 3.0);
|
||||
}
|
||||
|
||||
if char_num > 8 {
|
||||
horiz_offset = 0.0;
|
||||
char_num = 0;
|
||||
line_num += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
use std::ops::Neg;
|
||||
|
||||
use smash::app;
|
||||
use smash::phx::{Hash40, Vector3f};
|
||||
|
||||
pub const RAYGUN_LENGTH: f32 = 8.0;
|
||||
pub const RAYGUN_HEIGHT: f32 = 6.0;
|
||||
pub const RAYGUN_HORIZ_OFFSET: f32 = 2.0;
|
||||
|
||||
/*
|
||||
segment data list : {Z, Y, X, ZRot, Size}
|
||||
segment labels :
|
||||
_
|
||||
|_| from top to top left, clockwise: a->f + g mid + \|/ from top mid to top left, clockwise: h->m + --two half g's: n, o
|
||||
|_| /|\
|
||||
*/
|
||||
|
||||
pub static SEGMENT_DICT: [[f32; 5]; 15] = [
|
||||
[0.0, RAYGUN_HEIGHT * 2.0, 0.0, 0.0, 0.25], // a
|
||||
[0.0, RAYGUN_HEIGHT, RAYGUN_LENGTH, 90.0, 0.25], // b
|
||||
[0.0, 0.0, RAYGUN_LENGTH, 90.0, 0.25], // c
|
||||
[0.0, 0.0, 0.0, 0.0, 0.25], // d
|
||||
[0.0, 0.0, 0.0, 90.0, 0.25], // e
|
||||
[0.0, RAYGUN_HEIGHT, 0.0, 90.0, 0.25], // f
|
||||
[0.0, RAYGUN_HEIGHT, 0.0, 0.0, 0.25], // g mid
|
||||
[0.0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2.0, 90.0, 0.25], // h
|
||||
[0.0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2.0, 52.0, 0.2], // i
|
||||
[0.0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2.0, -52.0, 0.2], // j
|
||||
[0.0, 0.0, RAYGUN_LENGTH / 2.0, 90.0, 0.25], // k
|
||||
[
|
||||
0.0,
|
||||
RAYGUN_HEIGHT / 2.0,
|
||||
RAYGUN_LENGTH * 3.0 / 16.0,
|
||||
52.0,
|
||||
0.2,
|
||||
], // l
|
||||
[
|
||||
0.0,
|
||||
RAYGUN_HEIGHT * 3.0 / 2.0,
|
||||
RAYGUN_LENGTH * 3.0 / 16.0,
|
||||
-52.0,
|
||||
0.2,
|
||||
], // m
|
||||
[0.0, RAYGUN_HEIGHT, 0.0, 0.0, 0.15], // n
|
||||
[0.0, RAYGUN_HEIGHT, RAYGUN_LENGTH / 2.0, 0.0, 0.15], // o
|
||||
];
|
||||
|
||||
/*
|
||||
Segments making up each character, each index corresponding to:
|
||||
'A' through 'Z', '0' through '9', ' ', '-', '+', '#' (where '#' is all segments)
|
||||
*/
|
||||
pub static ALPHABET: [&str; 40] = [
|
||||
"abcefg",
|
||||
"adefijn",
|
||||
"adef",
|
||||
"eflm",
|
||||
"adefn",
|
||||
"aefn",
|
||||
"acdefo",
|
||||
"bcefg",
|
||||
"adhk",
|
||||
"bcd",
|
||||
"efnij",
|
||||
"def",
|
||||
"bcefim",
|
||||
"bcefjm",
|
||||
"abcdef",
|
||||
"abefg",
|
||||
"abcdefj",
|
||||
"aefijn",
|
||||
"acdfg",
|
||||
"ahk",
|
||||
"bcdef",
|
||||
"efil",
|
||||
"bcefjl",
|
||||
"ijlm",
|
||||
"ikm",
|
||||
"adil",
|
||||
"abcdef",
|
||||
"ef",
|
||||
"abdeg",
|
||||
"abcdg",
|
||||
"bcfg",
|
||||
"acdfg",
|
||||
"acdefg",
|
||||
"abc",
|
||||
"abcdefg",
|
||||
"abcdfg",
|
||||
"",
|
||||
"g",
|
||||
"ghk",
|
||||
"abcdefhijklmno",
|
||||
];
|
||||
|
||||
// Each index is a segment's corresponding flipped segment, for when facing left
|
||||
pub static SEGMENT_REV: [char; 15] = [
|
||||
'a', 'f', 'e', 'd', 'c', 'b', 'g', 'h', 'm', 'l', 'k', 'j', 'i', 'o', 'n',
|
||||
];
|
||||
|
||||
fn show_segment(
|
||||
module_accessor: &mut app::BattleObjectModuleAccessor,
|
||||
z: f32,
|
||||
y: f32,
|
||||
x: f32,
|
||||
zrot: f32,
|
||||
size: f32,
|
||||
) {
|
||||
let pos = Vector3f { x, y, z };
|
||||
let rot = Vector3f {
|
||||
x: 0.0,
|
||||
y: 90.0,
|
||||
z: zrot,
|
||||
};
|
||||
let random = Vector3f {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
app::lua_bind::EffectModule::req_on_joint(
|
||||
module_accessor,
|
||||
Hash40::new("sys_raygun_bullet"),
|
||||
Hash40::new("top"),
|
||||
&pos,
|
||||
&rot,
|
||||
size,
|
||||
&random,
|
||||
&random,
|
||||
false,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn alphabet_index(to_print: char) -> i32 {
|
||||
match to_print {
|
||||
'A'..='Z' => to_print as i32 - 'A' as i32,
|
||||
'0'..='9' => to_print as i32 - '0' as i32 + 'Z' as i32 - 'A' as i32 + 1,
|
||||
' ' => 36,
|
||||
'-' => 37,
|
||||
'+' => 38,
|
||||
'#' => 39,
|
||||
_ => -1,
|
||||
}
|
||||
}
|
||||
|
||||
fn print_char(
|
||||
module_accessor: &mut app::BattleObjectModuleAccessor,
|
||||
to_print: char,
|
||||
line_num: i32,
|
||||
horiz_offset: f32,
|
||||
facing_left: i32,
|
||||
) {
|
||||
let is_facing_left = facing_left == -1;
|
||||
let x_direction = facing_left as f32;
|
||||
|
||||
let alph_index = alphabet_index(to_print);
|
||||
if !(0..40).contains(&alph_index) {
|
||||
return;
|
||||
}
|
||||
let segment_str = ALPHABET[alph_index as usize];
|
||||
|
||||
let line_offset = 40.0 - ((line_num as f32) * 16.0);
|
||||
|
||||
for segment_char in segment_str.chars() {
|
||||
let mut index = segment_char as i32 - 'a' as i32;
|
||||
|
||||
if is_facing_left {
|
||||
index = SEGMENT_REV[index as usize] as i32 - 'a' as i32;
|
||||
}
|
||||
let segment = SEGMENT_DICT[index as usize];
|
||||
|
||||
const SIZE_MULT: f32 = 0.5;
|
||||
|
||||
let x = ((segment[2] + horiz_offset) * SIZE_MULT) + (x_direction * 5.0);
|
||||
let y = ((segment[1] + line_offset) * SIZE_MULT) + 5.0;
|
||||
let z = segment[0] * SIZE_MULT;
|
||||
|
||||
let zrot = segment[3];
|
||||
let zrot = if is_facing_left { zrot.neg() } else { zrot };
|
||||
|
||||
let size = segment[4] * SIZE_MULT;
|
||||
|
||||
show_segment(module_accessor, z, y, x, zrot, size);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_string(module_accessor: &mut app::BattleObjectModuleAccessor, to_write: &str) {
|
||||
// Delete any previous strings
|
||||
unsafe {
|
||||
app::lua_bind::EffectModule::kill_kind(
|
||||
module_accessor,
|
||||
Hash40::new("sys_raygun_bullet"),
|
||||
false,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
let mut line_num = 0;
|
||||
let mut horiz_offset = 0.0;
|
||||
let mut char_num = 0;
|
||||
|
||||
let facing_left = unsafe { app::lua_bind::PostureModule::lr(module_accessor) as i32 };
|
||||
let facing_direction = facing_left as f32;
|
||||
|
||||
if to_write.len() <= 8 && !to_write.contains('\n') {
|
||||
line_num = 1;
|
||||
}
|
||||
for curr_char in to_write.chars() {
|
||||
if curr_char == '\n' {
|
||||
horiz_offset = 0.0;
|
||||
char_num = 0;
|
||||
line_num += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
print_char(
|
||||
module_accessor,
|
||||
curr_char.to_uppercase().collect::<Vec<_>>()[0],
|
||||
line_num,
|
||||
horiz_offset,
|
||||
facing_left,
|
||||
);
|
||||
|
||||
char_num += 1;
|
||||
// short characters
|
||||
if curr_char == 'D' || curr_char == '1' {
|
||||
horiz_offset += facing_direction * (RAYGUN_LENGTH / 2.0 + 3.0);
|
||||
} else {
|
||||
horiz_offset += facing_direction * (RAYGUN_LENGTH + 3.0);
|
||||
}
|
||||
|
||||
if char_num > 8 {
|
||||
horiz_offset = 0.0;
|
||||
char_num = 0;
|
||||
line_num += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,50 +1,50 @@
|
|||
use smash::app::{self, lua_bind::*};
|
||||
use smash::lib::lua_const::*;
|
||||
|
||||
use crate::common::*;
|
||||
use crate::training::frame_counter;
|
||||
use crate::training::ledge;
|
||||
use crate::training::mash;
|
||||
use crate::training::sdi;
|
||||
use crate::training::shield_tilt;
|
||||
use crate::training::throw;
|
||||
|
||||
pub fn check_reset(module_accessor: &mut app::BattleObjectModuleAccessor) {
|
||||
if !is_operation_cpu(module_accessor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !should_reset(module_accessor) {
|
||||
return;
|
||||
}
|
||||
|
||||
on_reset();
|
||||
}
|
||||
|
||||
fn should_reset(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||
if !is_idle(module_accessor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let prev_status;
|
||||
|
||||
unsafe {
|
||||
prev_status = StatusModule::prev_status_kind(module_accessor, 0);
|
||||
}
|
||||
|
||||
// Only reset automatically on training mode reset
|
||||
if prev_status != *FIGHTER_STATUS_KIND_NONE {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn on_reset() {
|
||||
mash::full_reset();
|
||||
sdi::roll_direction();
|
||||
frame_counter::reset_all();
|
||||
ledge::reset_ledge_delay();
|
||||
throw::reset_throw_delay();
|
||||
shield_tilt::roll_direction();
|
||||
}
|
||||
use smash::app::{self, lua_bind::*};
|
||||
use smash::lib::lua_const::*;
|
||||
|
||||
use crate::common::*;
|
||||
use crate::training::frame_counter;
|
||||
use crate::training::ledge;
|
||||
use crate::training::mash;
|
||||
use crate::training::sdi;
|
||||
use crate::training::shield_tilt;
|
||||
use crate::training::throw;
|
||||
|
||||
pub fn check_reset(module_accessor: &mut app::BattleObjectModuleAccessor) {
|
||||
if !is_operation_cpu(module_accessor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !should_reset(module_accessor) {
|
||||
return;
|
||||
}
|
||||
|
||||
on_reset();
|
||||
}
|
||||
|
||||
fn should_reset(module_accessor: &mut app::BattleObjectModuleAccessor) -> bool {
|
||||
if !is_idle(module_accessor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let prev_status;
|
||||
|
||||
unsafe {
|
||||
prev_status = StatusModule::prev_status_kind(module_accessor, 0);
|
||||
}
|
||||
|
||||
// Only reset automatically on training mode reset
|
||||
if prev_status != *FIGHTER_STATUS_KIND_NONE {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn on_reset() {
|
||||
mash::full_reset();
|
||||
sdi::roll_direction();
|
||||
frame_counter::reset_all();
|
||||
ledge::reset_ledge_delay();
|
||||
throw::reset_throw_delay();
|
||||
shield_tilt::roll_direction();
|
||||
}
|
||||
|
|
|
@ -1,155 +1,155 @@
|
|||
use smash::app::{self, lua_bind::*};
|
||||
use smash::lib::lua_const::*;
|
||||
|
||||
use crate::common::*;
|
||||
use crate::common::consts::*;
|
||||
use crate::training::frame_counter;
|
||||
use crate::training::mash;
|
||||
|
||||
const NOT_SET: u32 = 9001;
|
||||
static mut THROW_DELAY: u32 = NOT_SET;
|
||||
static mut THROW_DELAY_COUNTER: usize = 0;
|
||||
static mut THROW_CASE: ThrowOption = ThrowOption::empty();
|
||||
|
||||
static mut PUMMEL_DELAY: u32 = NOT_SET;
|
||||
static mut PUMMEL_DELAY_COUNTER: usize = 0;
|
||||
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
THROW_DELAY_COUNTER = frame_counter::register_counter();
|
||||
PUMMEL_DELAY_COUNTER = frame_counter::register_counter();
|
||||
}
|
||||
}
|
||||
|
||||
// Rolling Throw Delays and Pummel Delays separately
|
||||
|
||||
pub fn reset_throw_delay() {
|
||||
unsafe {
|
||||
if THROW_DELAY != NOT_SET {
|
||||
THROW_DELAY = NOT_SET;
|
||||
frame_counter::full_reset(THROW_DELAY_COUNTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_pummel_delay() {
|
||||
unsafe {
|
||||
if PUMMEL_DELAY != NOT_SET {
|
||||
PUMMEL_DELAY = NOT_SET;
|
||||
frame_counter::full_reset(PUMMEL_DELAY_COUNTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_throw_case() {
|
||||
unsafe {
|
||||
if THROW_CASE != ThrowOption::empty() {
|
||||
// Don't roll another throw option if one is already selected
|
||||
THROW_CASE = ThrowOption::empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn roll_throw_delay() {
|
||||
unsafe {
|
||||
if THROW_DELAY != NOT_SET {
|
||||
// Don't roll another throw delay if one is already selected
|
||||
return;
|
||||
}
|
||||
|
||||
THROW_DELAY = MENU.throw_delay.get_random().into_meddelay();
|
||||
}
|
||||
}
|
||||
|
||||
fn roll_pummel_delay() {
|
||||
unsafe {
|
||||
if PUMMEL_DELAY != NOT_SET {
|
||||
// Don't roll another pummel delay if one is already selected
|
||||
return;
|
||||
}
|
||||
|
||||
PUMMEL_DELAY = MENU.pummel_delay.get_random().into_meddelay();
|
||||
}
|
||||
}
|
||||
|
||||
fn roll_throw_case() {
|
||||
unsafe {
|
||||
// Don't re-roll if there is already a throw option selected
|
||||
if THROW_CASE != ThrowOption::empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
THROW_CASE = MENU.throw_state.get_random();
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn get_command_flag_throw_direction(
|
||||
module_accessor: &mut app::BattleObjectModuleAccessor,
|
||||
) -> i32 {
|
||||
if !is_operation_cpu(module_accessor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if StatusModule::status_kind(module_accessor) != *FIGHTER_STATUS_KIND_CATCH_WAIT
|
||||
&& StatusModule::status_kind(module_accessor) != *FIGHTER_STATUS_KIND_CATCH_PULL
|
||||
&& StatusModule::status_kind(module_accessor) != *FIGHTER_STATUS_KIND_CATCH_ATTACK
|
||||
{
|
||||
// No longer holding character, so re-roll the throw case and reset the delay counter for next time
|
||||
reset_throw_case();
|
||||
reset_throw_delay();
|
||||
|
||||
reset_pummel_delay();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if !WorkModule::is_enable_transition_term(
|
||||
// If you can't throw right now, don't bother
|
||||
module_accessor,
|
||||
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_THROW_HI,
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
roll_throw_delay();
|
||||
roll_throw_case();
|
||||
|
||||
roll_pummel_delay();
|
||||
|
||||
if THROW_CASE == ThrowOption::NONE {
|
||||
// Do nothing, but don't reroll the throw case.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if frame_counter::should_delay(THROW_DELAY, THROW_DELAY_COUNTER) {
|
||||
// Not yet time to perform the throw action
|
||||
if frame_counter::should_delay(PUMMEL_DELAY, PUMMEL_DELAY_COUNTER) {
|
||||
// And not yet time to pummel either, so don't do anything
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If no pummel delay is selected (default), then don't pummel
|
||||
if MENU.pummel_delay == MedDelay::empty() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// (this conditional would need to be changed to speed up pummelling)
|
||||
if StatusModule::status_kind(module_accessor) == *FIGHTER_STATUS_KIND_CATCH_WAIT {
|
||||
let status = *FIGHTER_STATUS_KIND_CATCH_ATTACK; //.unwrap_or(0);
|
||||
StatusModule::change_status_request_from_script(module_accessor, status, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If you can uthrow, then throw (since all throws should be possible at the same times)
|
||||
if WorkModule::is_enable_transition_term(
|
||||
module_accessor,
|
||||
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_THROW_HI,
|
||||
) {
|
||||
let cmd = THROW_CASE.into_cmd().unwrap_or(0);
|
||||
mash::buffer_menu_mash();
|
||||
return cmd;
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
use smash::app::{self, lua_bind::*};
|
||||
use smash::lib::lua_const::*;
|
||||
|
||||
use crate::common::*;
|
||||
use crate::common::consts::*;
|
||||
use crate::training::frame_counter;
|
||||
use crate::training::mash;
|
||||
|
||||
const NOT_SET: u32 = 9001;
|
||||
static mut THROW_DELAY: u32 = NOT_SET;
|
||||
static mut THROW_DELAY_COUNTER: usize = 0;
|
||||
static mut THROW_CASE: ThrowOption = ThrowOption::empty();
|
||||
|
||||
static mut PUMMEL_DELAY: u32 = NOT_SET;
|
||||
static mut PUMMEL_DELAY_COUNTER: usize = 0;
|
||||
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
THROW_DELAY_COUNTER = frame_counter::register_counter();
|
||||
PUMMEL_DELAY_COUNTER = frame_counter::register_counter();
|
||||
}
|
||||
}
|
||||
|
||||
// Rolling Throw Delays and Pummel Delays separately
|
||||
|
||||
pub fn reset_throw_delay() {
|
||||
unsafe {
|
||||
if THROW_DELAY != NOT_SET {
|
||||
THROW_DELAY = NOT_SET;
|
||||
frame_counter::full_reset(THROW_DELAY_COUNTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_pummel_delay() {
|
||||
unsafe {
|
||||
if PUMMEL_DELAY != NOT_SET {
|
||||
PUMMEL_DELAY = NOT_SET;
|
||||
frame_counter::full_reset(PUMMEL_DELAY_COUNTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_throw_case() {
|
||||
unsafe {
|
||||
if THROW_CASE != ThrowOption::empty() {
|
||||
// Don't roll another throw option if one is already selected
|
||||
THROW_CASE = ThrowOption::empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn roll_throw_delay() {
|
||||
unsafe {
|
||||
if THROW_DELAY != NOT_SET {
|
||||
// Don't roll another throw delay if one is already selected
|
||||
return;
|
||||
}
|
||||
|
||||
THROW_DELAY = MENU.throw_delay.get_random().into_meddelay();
|
||||
}
|
||||
}
|
||||
|
||||
fn roll_pummel_delay() {
|
||||
unsafe {
|
||||
if PUMMEL_DELAY != NOT_SET {
|
||||
// Don't roll another pummel delay if one is already selected
|
||||
return;
|
||||
}
|
||||
|
||||
PUMMEL_DELAY = MENU.pummel_delay.get_random().into_meddelay();
|
||||
}
|
||||
}
|
||||
|
||||
fn roll_throw_case() {
|
||||
unsafe {
|
||||
// Don't re-roll if there is already a throw option selected
|
||||
if THROW_CASE != ThrowOption::empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
THROW_CASE = MENU.throw_state.get_random();
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn get_command_flag_throw_direction(
|
||||
module_accessor: &mut app::BattleObjectModuleAccessor,
|
||||
) -> i32 {
|
||||
if !is_operation_cpu(module_accessor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if StatusModule::status_kind(module_accessor) != *FIGHTER_STATUS_KIND_CATCH_WAIT
|
||||
&& StatusModule::status_kind(module_accessor) != *FIGHTER_STATUS_KIND_CATCH_PULL
|
||||
&& StatusModule::status_kind(module_accessor) != *FIGHTER_STATUS_KIND_CATCH_ATTACK
|
||||
{
|
||||
// No longer holding character, so re-roll the throw case and reset the delay counter for next time
|
||||
reset_throw_case();
|
||||
reset_throw_delay();
|
||||
|
||||
reset_pummel_delay();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if !WorkModule::is_enable_transition_term(
|
||||
// If you can't throw right now, don't bother
|
||||
module_accessor,
|
||||
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_THROW_HI,
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
roll_throw_delay();
|
||||
roll_throw_case();
|
||||
|
||||
roll_pummel_delay();
|
||||
|
||||
if THROW_CASE == ThrowOption::NONE {
|
||||
// Do nothing, but don't reroll the throw case.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if frame_counter::should_delay(THROW_DELAY, THROW_DELAY_COUNTER) {
|
||||
// Not yet time to perform the throw action
|
||||
if frame_counter::should_delay(PUMMEL_DELAY, PUMMEL_DELAY_COUNTER) {
|
||||
// And not yet time to pummel either, so don't do anything
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If no pummel delay is selected (default), then don't pummel
|
||||
if MENU.pummel_delay == MedDelay::empty() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// (this conditional would need to be changed to speed up pummelling)
|
||||
if StatusModule::status_kind(module_accessor) == *FIGHTER_STATUS_KIND_CATCH_WAIT {
|
||||
let status = *FIGHTER_STATUS_KIND_CATCH_ATTACK; //.unwrap_or(0);
|
||||
StatusModule::change_status_request_from_script(module_accessor, status, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If you can uthrow, then throw (since all throws should be possible at the same times)
|
||||
if WorkModule::is_enable_transition_term(
|
||||
module_accessor,
|
||||
*FIGHTER_STATUS_TRANSITION_TERM_ID_CONT_THROW_HI,
|
||||
) {
|
||||
let cmd = THROW_CASE.into_cmd().unwrap_or(0);
|
||||
mash::buffer_menu_mash();
|
||||
return cmd;
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
[package]
|
||||
name = "training_mod_consts"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.2.1"
|
||||
strum = "0.21.0"
|
||||
strum_macros = "0.21.0"
|
||||
num = "0.4.0"
|
||||
num-derive = "0.3"
|
||||
num-traits = "0.2"
|
||||
paste = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_repr = "0.1.8"
|
||||
serde_json = "1"
|
||||
bitflags_serde_shim = "0.2"
|
||||
skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["smash"]
|
||||
[package]
|
||||
name = "training_mod_consts"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.2.1"
|
||||
strum = "0.21.0"
|
||||
strum_macros = "0.21.0"
|
||||
num = "0.4.0"
|
||||
num-derive = "0.3"
|
||||
num-traits = "0.2"
|
||||
paste = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_repr = "0.1.8"
|
||||
serde_json = "1"
|
||||
bitflags_serde_shim = "0.2"
|
||||
skyline_smash = { git = "https://github.com/ultimate-research/skyline-smash.git", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["smash"]
|
||||
smash = ["skyline_smash"]
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "training_mod_metrics"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
datafusion = "5.0.0"
|
||||
tokio = "1.11.0"
|
||||
plotters = "0.3.1"
|
||||
[package]
|
||||
name = "training_mod_metrics"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
datafusion = "5.0.0"
|
||||
tokio = "1.11.0"
|
||||
plotters = "0.3.1"
|
||||
chrono = "0.4.19"
|
|
@ -1,144 +1,144 @@
|
|||
use datafusion::prelude::*;
|
||||
use datafusion::arrow::record_batch::RecordBatch;
|
||||
use datafusion::datasource::json::NdJsonFile;
|
||||
use datafusion::physical_plan::json::NdJsonReadOptions;
|
||||
use datafusion::arrow::datatypes::{Schema, Field, DataType};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
// export.json is relative to /event/
|
||||
// cat export.json | jq -c '.SMASH_OPEN.device[][][]' > smash_open.json
|
||||
#[derive(Debug)]
|
||||
struct Event {
|
||||
device_id: String,
|
||||
event_name: String,
|
||||
event_time: i64,
|
||||
menu_settings: String,
|
||||
mod_version: String,
|
||||
session_id: String,
|
||||
smash_version: String,
|
||||
user_id: String
|
||||
}
|
||||
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
fn timestamp_secs_to_datetime(ts: i64) -> DateTime<Utc> {
|
||||
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(ts, 0), Utc)
|
||||
}
|
||||
|
||||
use plotters::prelude::*;
|
||||
const OUT_FILE_NAME: &'static str = "boxplot.svg";
|
||||
fn draw_chart(results: Vec<RecordBatch>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let num_devices_idx = results[0].schema().column_with_name("num_devices").unwrap().0;
|
||||
let num_sessions_idx = results[0].schema().column_with_name("num_sessions").unwrap().0;
|
||||
let timestamps_idx = results[0].schema().column_with_name("date").unwrap().0;
|
||||
|
||||
let num_devices = results[0].column(num_devices_idx).as_any()
|
||||
.downcast_ref::<datafusion::arrow::array::UInt64Array>()
|
||||
.expect("Failed to downcast").values();
|
||||
let num_sessions = results[0].column(num_sessions_idx).as_any()
|
||||
.downcast_ref::<datafusion::arrow::array::UInt64Array>()
|
||||
.expect("Failed to downcast").values();
|
||||
let timestamp_millis = results[0].column(timestamps_idx).as_any()
|
||||
.downcast_ref::<datafusion::arrow::array::TimestampMillisecondArray>()
|
||||
.expect("Failed to downcast").values();
|
||||
|
||||
let device_data_points = num_devices.iter()
|
||||
.enumerate().map(|(i, x)| (timestamp_secs_to_datetime(timestamp_millis[i] / 1000), *x));
|
||||
let session_data_points = num_sessions.iter()
|
||||
.enumerate().map(|(i, x)| (timestamp_secs_to_datetime(timestamp_millis[i] / 1000), *x));
|
||||
|
||||
let root = SVGBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
|
||||
root.fill(&WHITE)?;
|
||||
let mut chart = ChartBuilder::on(&root)
|
||||
.caption("Users and Sessions by Date", ("sans-serif", 50).into_font())
|
||||
.margin(5)
|
||||
.x_label_area_size(30)
|
||||
.y_label_area_size(30)
|
||||
.build_cartesian_2d(
|
||||
(timestamp_secs_to_datetime(timestamp_millis[0] / 1000))..(timestamp_secs_to_datetime(*timestamp_millis.last().unwrap() / 1000)),
|
||||
0..*num_sessions.iter().max().unwrap())?;
|
||||
|
||||
chart.configure_mesh().draw()?;
|
||||
|
||||
chart
|
||||
.draw_series(LineSeries::new(
|
||||
device_data_points,
|
||||
&RED,
|
||||
))?
|
||||
.label("Unique Devices")
|
||||
.legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));
|
||||
chart
|
||||
.draw_series(LineSeries::new(
|
||||
session_data_points,
|
||||
&BLUE,
|
||||
))?
|
||||
.label("Unique Sessions")
|
||||
.legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE));
|
||||
|
||||
chart
|
||||
.configure_series_labels()
|
||||
.background_style(&WHITE.mix(0.8))
|
||||
.border_style(&BLACK)
|
||||
.draw()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> datafusion::error::Result<()> {
|
||||
// let smash_open_table = NdJsonFile::try_new(
|
||||
// "smash_open.json",
|
||||
// NdJsonReadOptions{
|
||||
// schema: None,
|
||||
// schema_infer_max_records: 1,
|
||||
// file_extension: ".json",
|
||||
// }
|
||||
// ).unwrap();
|
||||
|
||||
let menu_open_table = NdJsonFile::try_new(
|
||||
"menu_open.json",
|
||||
NdJsonReadOptions{
|
||||
schema: Some(Arc::new(Schema::new(vec![
|
||||
Field::new("device_id", DataType::Utf8, false),
|
||||
Field::new("event_name", DataType::Utf8, false),
|
||||
Field::new("event_time", DataType::Int64, false),
|
||||
Field::new("menu_settings", DataType::Utf8, false),
|
||||
Field::new("session_id", DataType::Utf8, false),
|
||||
Field::new("smash_version", DataType::Utf8, false),
|
||||
Field::new("mod_version", DataType::Utf8, false),
|
||||
Field::new("user_id", DataType::Utf8, false),
|
||||
]))),
|
||||
schema_infer_max_records: 0,
|
||||
file_extension: ".json",
|
||||
}
|
||||
).unwrap();
|
||||
|
||||
// // declare a new context. In spark API, this corresponds to a new spark SQLsession
|
||||
let mut ctx = ExecutionContext::new();
|
||||
|
||||
// ctx.register_table("smash_open", Arc::new(smash_open_table))?;
|
||||
ctx.register_table("menu_open", Arc::new(menu_open_table))?;
|
||||
|
||||
// create a plan to run a SQL query
|
||||
let df = ctx.sql(
|
||||
"SELECT
|
||||
COUNT(DISTINCT device_id) num_devices,
|
||||
COUNT(DISTINCT session_id) num_sessions,
|
||||
COUNT(*) num_events,
|
||||
TO_TIMESTAMP_MILLIS(DATE_TRUNC('day', CAST(event_time * 1000000 AS timestamp))) AS date FROM menu_open
|
||||
WHERE
|
||||
-- after 09/01/2021
|
||||
event_time > 1630454400000
|
||||
-- before today
|
||||
AND CAST(event_time * 1000000 AS timestamp) < NOW()
|
||||
GROUP BY date ORDER BY date"
|
||||
)?;
|
||||
|
||||
let results: Vec<RecordBatch> = df.collect().await?;
|
||||
// use datafusion::arrow::util::pretty::pretty_format_batches;
|
||||
// println!("{}", pretty_format_batches(&results)?);
|
||||
|
||||
draw_chart(results).unwrap();
|
||||
|
||||
Ok(())
|
||||
use datafusion::prelude::*;
|
||||
use datafusion::arrow::record_batch::RecordBatch;
|
||||
use datafusion::datasource::json::NdJsonFile;
|
||||
use datafusion::physical_plan::json::NdJsonReadOptions;
|
||||
use datafusion::arrow::datatypes::{Schema, Field, DataType};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
// export.json is relative to /event/
|
||||
// cat export.json | jq -c '.SMASH_OPEN.device[][][]' > smash_open.json
|
||||
#[derive(Debug)]
|
||||
struct Event {
|
||||
device_id: String,
|
||||
event_name: String,
|
||||
event_time: i64,
|
||||
menu_settings: String,
|
||||
mod_version: String,
|
||||
session_id: String,
|
||||
smash_version: String,
|
||||
user_id: String
|
||||
}
|
||||
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
fn timestamp_secs_to_datetime(ts: i64) -> DateTime<Utc> {
|
||||
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(ts, 0), Utc)
|
||||
}
|
||||
|
||||
use plotters::prelude::*;
|
||||
const OUT_FILE_NAME: &'static str = "boxplot.svg";
|
||||
fn draw_chart(results: Vec<RecordBatch>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let num_devices_idx = results[0].schema().column_with_name("num_devices").unwrap().0;
|
||||
let num_sessions_idx = results[0].schema().column_with_name("num_sessions").unwrap().0;
|
||||
let timestamps_idx = results[0].schema().column_with_name("date").unwrap().0;
|
||||
|
||||
let num_devices = results[0].column(num_devices_idx).as_any()
|
||||
.downcast_ref::<datafusion::arrow::array::UInt64Array>()
|
||||
.expect("Failed to downcast").values();
|
||||
let num_sessions = results[0].column(num_sessions_idx).as_any()
|
||||
.downcast_ref::<datafusion::arrow::array::UInt64Array>()
|
||||
.expect("Failed to downcast").values();
|
||||
let timestamp_millis = results[0].column(timestamps_idx).as_any()
|
||||
.downcast_ref::<datafusion::arrow::array::TimestampMillisecondArray>()
|
||||
.expect("Failed to downcast").values();
|
||||
|
||||
let device_data_points = num_devices.iter()
|
||||
.enumerate().map(|(i, x)| (timestamp_secs_to_datetime(timestamp_millis[i] / 1000), *x));
|
||||
let session_data_points = num_sessions.iter()
|
||||
.enumerate().map(|(i, x)| (timestamp_secs_to_datetime(timestamp_millis[i] / 1000), *x));
|
||||
|
||||
let root = SVGBackend::new(OUT_FILE_NAME, (1024, 768)).into_drawing_area();
|
||||
root.fill(&WHITE)?;
|
||||
let mut chart = ChartBuilder::on(&root)
|
||||
.caption("Users and Sessions by Date", ("sans-serif", 50).into_font())
|
||||
.margin(5)
|
||||
.x_label_area_size(30)
|
||||
.y_label_area_size(30)
|
||||
.build_cartesian_2d(
|
||||
(timestamp_secs_to_datetime(timestamp_millis[0] / 1000))..(timestamp_secs_to_datetime(*timestamp_millis.last().unwrap() / 1000)),
|
||||
0..*num_sessions.iter().max().unwrap())?;
|
||||
|
||||
chart.configure_mesh().draw()?;
|
||||
|
||||
chart
|
||||
.draw_series(LineSeries::new(
|
||||
device_data_points,
|
||||
&RED,
|
||||
))?
|
||||
.label("Unique Devices")
|
||||
.legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));
|
||||
chart
|
||||
.draw_series(LineSeries::new(
|
||||
session_data_points,
|
||||
&BLUE,
|
||||
))?
|
||||
.label("Unique Sessions")
|
||||
.legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &BLUE));
|
||||
|
||||
chart
|
||||
.configure_series_labels()
|
||||
.background_style(&WHITE.mix(0.8))
|
||||
.border_style(&BLACK)
|
||||
.draw()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> datafusion::error::Result<()> {
|
||||
// let smash_open_table = NdJsonFile::try_new(
|
||||
// "smash_open.json",
|
||||
// NdJsonReadOptions{
|
||||
// schema: None,
|
||||
// schema_infer_max_records: 1,
|
||||
// file_extension: ".json",
|
||||
// }
|
||||
// ).unwrap();
|
||||
|
||||
let menu_open_table = NdJsonFile::try_new(
|
||||
"menu_open.json",
|
||||
NdJsonReadOptions{
|
||||
schema: Some(Arc::new(Schema::new(vec![
|
||||
Field::new("device_id", DataType::Utf8, false),
|
||||
Field::new("event_name", DataType::Utf8, false),
|
||||
Field::new("event_time", DataType::Int64, false),
|
||||
Field::new("menu_settings", DataType::Utf8, false),
|
||||
Field::new("session_id", DataType::Utf8, false),
|
||||
Field::new("smash_version", DataType::Utf8, false),
|
||||
Field::new("mod_version", DataType::Utf8, false),
|
||||
Field::new("user_id", DataType::Utf8, false),
|
||||
]))),
|
||||
schema_infer_max_records: 0,
|
||||
file_extension: ".json",
|
||||
}
|
||||
).unwrap();
|
||||
|
||||
// // declare a new context. In spark API, this corresponds to a new spark SQLsession
|
||||
let mut ctx = ExecutionContext::new();
|
||||
|
||||
// ctx.register_table("smash_open", Arc::new(smash_open_table))?;
|
||||
ctx.register_table("menu_open", Arc::new(menu_open_table))?;
|
||||
|
||||
// create a plan to run a SQL query
|
||||
let df = ctx.sql(
|
||||
"SELECT
|
||||
COUNT(DISTINCT device_id) num_devices,
|
||||
COUNT(DISTINCT session_id) num_sessions,
|
||||
COUNT(*) num_events,
|
||||
TO_TIMESTAMP_MILLIS(DATE_TRUNC('day', CAST(event_time * 1000000 AS timestamp))) AS date FROM menu_open
|
||||
WHERE
|
||||
-- after 09/01/2021
|
||||
event_time > 1630454400000
|
||||
-- before today
|
||||
AND CAST(event_time * 1000000 AS timestamp) < NOW()
|
||||
GROUP BY date ORDER BY date"
|
||||
)?;
|
||||
|
||||
let results: Vec<RecordBatch> = df.collect().await?;
|
||||
// use datafusion::arrow::util::pretty::pretty_format_batches;
|
||||
// println!("{}", pretty_format_batches(&results)?);
|
||||
|
||||
draw_chart(results).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="RUST_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="RUST_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
Loading…
Reference in a new issue