Compare commits
7
Commits
b0b1420f48
...
gltf_fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47662fe4ba | ||
|
|
445f249153 | ||
|
|
30477254e5 | ||
|
|
4861374aef | ||
|
|
d3a688e768 | ||
|
|
376a40d38c | ||
|
|
b29085f8a5 |
@@ -0,0 +1,45 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Check out source
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust toolchain
|
||||
run: |
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
|
||||
sh -s -- -y --profile minimal
|
||||
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
||||
"$HOME/.cargo/bin/rustup" toolchain install nightly --profile minimal
|
||||
|
||||
- name: Install Linux dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
clang \
|
||||
libasound2-dev \
|
||||
libudev-dev \
|
||||
libusb-1.0-0-dev \
|
||||
libwayland-dev \
|
||||
libx11-dev \
|
||||
libxkbcommon-dev \
|
||||
libxkbcommon-x11-0 \
|
||||
mesa-vulkan-drivers \
|
||||
mold \
|
||||
pkg-config
|
||||
|
||||
- name: Build
|
||||
run: cargo build --locked -j 4
|
||||
|
||||
- name: Run unit tests
|
||||
run: cargo test --locked --lib -j 4
|
||||
+10
-1
@@ -1,3 +1,12 @@
|
||||
/target
|
||||
/.jackdaw
|
||||
imported_assets
|
||||
imported_assets
|
||||
|
||||
# Local editor configuration
|
||||
**/.vscode/
|
||||
|
||||
# Generated and backup assets
|
||||
*.blend1
|
||||
*_old.glb
|
||||
/replay.json
|
||||
*.replay.tmp
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
frame(3);
|
||||
frame(4);
|
||||
hitbox(0,
|
||||
"Foot.L",
|
||||
"hand_l",
|
||||
damage("5.0"),
|
||||
vec3("0.0", "0.0", "0.0"),
|
||||
fg32("20.0"),
|
||||
fg32("5.0"),
|
||||
angle_sakurai(),
|
||||
knockback_normal(),
|
||||
knockback("10.0"),
|
||||
fg32("1.0")
|
||||
);
|
||||
frame(6);
|
||||
frame(8);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
frame(3);
|
||||
hitbox(0,
|
||||
"hand_l",
|
||||
damage("5.0"),
|
||||
vec3("0.0", "0.0", "0.0"),
|
||||
fg32("5.0"),
|
||||
angle(fg32("45.0")),
|
||||
knockback_normal(),
|
||||
knockback("18.0"),
|
||||
fg32("140.0")
|
||||
);
|
||||
frame(8);
|
||||
@@ -0,0 +1,13 @@
|
||||
frame(9);
|
||||
hitbox(0,
|
||||
"hand_l",
|
||||
damage("5.0"),
|
||||
vec3("1.0", "0.0", "0.0"),
|
||||
fg32("7.0"),
|
||||
angle_sakurai(),
|
||||
knockback_normal(),
|
||||
knockback("10.0"),
|
||||
fg32("1.0")
|
||||
);
|
||||
|
||||
frame(15);
|
||||
@@ -1,6 +1,6 @@
|
||||
(
|
||||
id: TestFighter,
|
||||
model_path: "fighters/test/test-fighter-2.glb",
|
||||
model_path: "fighters/test/test_fighter.gltf",
|
||||
model_scale: "10.0",
|
||||
baked_animation_path: "fighters/test/test.fighterbake",
|
||||
icon: (
|
||||
@@ -15,10 +15,10 @@
|
||||
dash_duration: 24,
|
||||
base_dash_accel: "0.1",
|
||||
stick_dash_accel: "0.05",
|
||||
max_dash_vel: "2.3",
|
||||
short_hop_vertical_velocity: "1.35",
|
||||
full_jump_vertical_velocity: "2.1",
|
||||
jump_horizontal_velocity: "0.7",
|
||||
max_dash_vel: "2.0",
|
||||
short_hop_vertical_velocity: "1.45",
|
||||
full_jump_vertical_velocity: "2.0",
|
||||
jump_horizontal_velocity: "0.6",
|
||||
air_jump_horizontal_velocity: "0.96",
|
||||
air_jump_multiplier: "1.0",
|
||||
dash_initial_velocity: "1.4",
|
||||
@@ -63,6 +63,10 @@
|
||||
DoubleJumpBack: "JumpB_Game",
|
||||
Fall: "Fall_Loop_Game",
|
||||
Turn: "Turn_Game",
|
||||
|
||||
FlinchGround: "Air_Hit_Game",
|
||||
FlinchAir: "Air_Hit_Game",
|
||||
|
||||
AttackJab1: "Punch_Jab_Game",
|
||||
AttackUpTilt: "Idle_Loop_Game",
|
||||
AttackForwardTilt: "Idle_Loop_Game",
|
||||
@@ -70,7 +74,7 @@
|
||||
},
|
||||
attack_scripts: {
|
||||
NeutralAir: "fighters/test/scripts/fair.attack.rhai",
|
||||
Jab: "fighters/test/scripts/fair.attack.rhai",
|
||||
Jab: "fighters/test/scripts/jab.attack.rhai",
|
||||
UpTilt: "fighters/test/scripts/uptilt.attack.rhai",
|
||||
ForwardTilt: "fighters/test/scripts/uptilt.attack.rhai",
|
||||
DownTilt: "fighters/test/scripts/uptilt.attack.rhai",
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -8,12 +8,16 @@
|
||||
smash_input_frame_threshold: 3,
|
||||
input_buffer_size: 3,
|
||||
turn_into_dashback_window: 2,
|
||||
|
||||
),
|
||||
fighter_common: (
|
||||
walk_speed_ease: "0.5",
|
||||
ground_max_horizontal_velocity: "3.0",
|
||||
ground_friction_over_walk_speed_multiplier: "2.0"
|
||||
ground_friction_over_walk_speed_multiplier: "2.0",
|
||||
knockback_stacking_window: 2,
|
||||
knockback_decay_per_frame: "0.051",
|
||||
knockback_launch_velocity_multiplier: "0.03",
|
||||
hitstun_frames_per_unit_knockback: "0.4",
|
||||
|
||||
),
|
||||
stage_manifest_paths: [
|
||||
"stages/battlefield/test.stage.ron"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,84 +0,0 @@
|
||||
(
|
||||
id: TestStage,
|
||||
model_path: "stages/battlefield.glb#Scene0",
|
||||
camera: (
|
||||
left: -75.0,
|
||||
right: 75.0,
|
||||
bottom: -30.0,
|
||||
top: 70.0,
|
||||
origin: (0.0, 15.0),
|
||||
vertical_fov_degrees: 30.0,
|
||||
min_depth: 150.0,
|
||||
max_depth: 400.0,
|
||||
subject_scale: 1.0,
|
||||
tracking_smoothness: 3.0,
|
||||
vertical_tilt_degrees: 0.0,
|
||||
horizontal_pan_coefficient: 0.0,
|
||||
vertical_pan_coefficient: 0.0,
|
||||
max_horizontal_pan_degrees: 17.5,
|
||||
max_upward_pan_degrees: 5.0,
|
||||
max_downward_pan_degrees: 7.0,
|
||||
max_downward_expansion: 40.0,
|
||||
),
|
||||
polygons: [
|
||||
(
|
||||
poly_type: Platform,
|
||||
lines: [
|
||||
(
|
||||
(x: "-59.5", y: "23.45"),
|
||||
Floor
|
||||
),
|
||||
(
|
||||
(x: "-28.0", y: "23.45"),
|
||||
Floor
|
||||
)
|
||||
]
|
||||
),
|
||||
(
|
||||
poly_type: Platform,
|
||||
lines: [
|
||||
(
|
||||
(x: "28.0", y: "23.45"),
|
||||
Floor
|
||||
),
|
||||
(
|
||||
(x: "59.5", y: "23.45"),
|
||||
Floor
|
||||
)
|
||||
]
|
||||
),
|
||||
(
|
||||
poly_type: Closed,
|
||||
lines: [
|
||||
(
|
||||
(x: "-56", y: "-200.0"),
|
||||
Wall
|
||||
),
|
||||
(
|
||||
(x: "-56.0", y: "-3.5"),
|
||||
Floor,
|
||||
),
|
||||
(
|
||||
(x: "-39.2", y: "0.0"),
|
||||
Floor,
|
||||
),
|
||||
(
|
||||
(x: "0.0", y: "0.0"),
|
||||
Floor
|
||||
),
|
||||
(
|
||||
(x: "39.2", y: "0.0"),
|
||||
Floor
|
||||
),
|
||||
(
|
||||
(x: "56.0", y: "-3.5"),
|
||||
Wall
|
||||
),
|
||||
(
|
||||
(x: "56", y: "-200.0"),
|
||||
Wall
|
||||
),
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 871 B |
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="128"
|
||||
height="128"
|
||||
viewBox="0 0 33.866666 33.866666"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4.4 (dcaf3e7d9e, 2026-05-05)"
|
||||
sodipodi:docname="cursor.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#000000"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="5.6568542"
|
||||
inkscape:cx="8.6620581"
|
||||
inkscape:cy="67.086756"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1006"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<linearGradient
|
||||
id="linearGradient1"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#949494;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop1" />
|
||||
<stop
|
||||
style="stop-color:#6c6c6c;stop-opacity:1;"
|
||||
offset="0.77473962"
|
||||
id="stop3" />
|
||||
<stop
|
||||
style="stop-color:#9f9f9f;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop2" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient1"
|
||||
id="radialGradient2"
|
||||
cx="16.933332"
|
||||
cy="16.933332"
|
||||
fx="16.933332"
|
||||
fy="16.933332"
|
||||
r="12.733072"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.2093771,0,0,1.2093771,-3.5454518,-3.5454518)" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Capa 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<circle
|
||||
style="fill:url(#radialGradient2);stroke-width:0.319981"
|
||||
id="path1"
|
||||
cx="16.933332"
|
||||
cy="16.933332"
|
||||
r="15.399086" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -3,6 +3,7 @@
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
io,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use bevy::{
|
||||
@@ -517,6 +518,7 @@ struct FighterBakeDeclaration {
|
||||
#[derive(Asset, TypePath)]
|
||||
struct FighterBakeSource {
|
||||
model_bytes: Vec<u8>,
|
||||
buffers: Vec<Vec<u8>>,
|
||||
animations: HashMap<AnimKind, String>,
|
||||
}
|
||||
|
||||
@@ -550,8 +552,31 @@ impl AssetLoader for FighterBakeSourceLoader {
|
||||
.read_asset_bytes(&manifest.model_path)
|
||||
.await
|
||||
.map_err(|error| io::Error::other(error.to_string()))?;
|
||||
|
||||
let gltf = gltf::Gltf::from_slice(&model_bytes)
|
||||
.map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;
|
||||
let mut buffers = Vec::with_capacity(gltf.buffers().len());
|
||||
for buffer in gltf.buffers() {
|
||||
let bytes = match buffer.source() {
|
||||
gltf::buffer::Source::Uri(uri) => load_context
|
||||
.read_asset_bytes(AssetPath::from_path_buf(
|
||||
Path::new(&manifest.model_path)
|
||||
.parent()
|
||||
.unwrap_or_else(|| Path::new(""))
|
||||
.join(uri),
|
||||
))
|
||||
.await
|
||||
.map_err(|error| io::Error::other(error.to_string()))?,
|
||||
gltf::buffer::Source::Bin => gltf.blob.clone().ok_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::InvalidData, "missing glTF binary blob")
|
||||
})?,
|
||||
};
|
||||
buffers.push(bytes);
|
||||
}
|
||||
|
||||
Ok(FighterBakeSource {
|
||||
model_bytes,
|
||||
buffers,
|
||||
animations: manifest.animations,
|
||||
})
|
||||
}
|
||||
@@ -600,7 +625,7 @@ impl AssetTransformer for FighterBakeTransformer {
|
||||
source: TransformedAsset<Self::AssetInput>,
|
||||
_: &'a Self::Settings,
|
||||
) -> Result<TransformedAsset<Self::AssetOutput>, Self::Error> {
|
||||
let baked = bake_gltf(&source.model_bytes, &source.animations)?;
|
||||
let baked = bake_gltf(&source.model_bytes, &source.buffers, &source.animations)?;
|
||||
Ok(source.replace_asset(baked))
|
||||
}
|
||||
}
|
||||
@@ -656,10 +681,43 @@ impl Plugin for BakedAnimationPlugin {
|
||||
|
||||
fn bake_gltf(
|
||||
bytes: &[u8],
|
||||
buffer_bytes: &[Vec<u8>],
|
||||
animations: &HashMap<AnimKind, String>,
|
||||
) -> io::Result<BakedFighterAnimations> {
|
||||
let (document, buffers, _) = gltf::import_slice(bytes)
|
||||
let gltf = gltf::Gltf::from_slice(bytes)
|
||||
.map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;
|
||||
let buffers = gltf
|
||||
.buffers()
|
||||
.zip(buffer_bytes)
|
||||
.map(|(buffer, bytes)| {
|
||||
if bytes.len() < buffer.length() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
format!(
|
||||
"glTF buffer {} is too short: expected {}, got {}",
|
||||
buffer.index(),
|
||||
buffer.length(),
|
||||
bytes.len()
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(gltf::buffer::Data(bytes.clone()))
|
||||
})
|
||||
.collect::<io::Result<Vec<_>>>()?;
|
||||
if buffers.len() != gltf.buffers().len() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"glTF buffer data is incomplete",
|
||||
));
|
||||
}
|
||||
bake_gltf_document(gltf.document, buffers, animations)
|
||||
}
|
||||
|
||||
fn bake_gltf_document(
|
||||
document: gltf::Document,
|
||||
buffers: Vec<gltf::buffer::Data>,
|
||||
animations: &HashMap<AnimKind, String>,
|
||||
) -> io::Result<BakedFighterAnimations> {
|
||||
let nodes: Vec<_> = document.nodes().collect();
|
||||
if nodes.is_empty() {
|
||||
return Err(io::Error::new(
|
||||
@@ -933,11 +991,12 @@ mod tests {
|
||||
fn configured_fighter_clips_bake_to_fixed_point_frames() {
|
||||
let manifest: FighterManifest =
|
||||
ron::from_str(include_str!("../../assets/fighters/test/test.fighter.ron")).unwrap();
|
||||
let baked = bake_gltf(
|
||||
include_bytes!("../../assets/fighters/test/test-fighter-2.glb"),
|
||||
&manifest.animations,
|
||||
)
|
||||
let (document, buffers, _) = gltf::import(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/assets/fighters/test/test_fighter.gltf"
|
||||
))
|
||||
.unwrap();
|
||||
let baked = bake_gltf_document(document, buffers, &manifest.animations).unwrap();
|
||||
|
||||
assert_eq!(baked.frame_rate, BAKED_ANIMATION_FPS);
|
||||
assert_eq!(baked.frame_count(AnimKind::Wait), Some(121));
|
||||
|
||||
+1
-5
@@ -1,7 +1,3 @@
|
||||
//! Standalone binary for game-test: `cargo run` plays the game
|
||||
//! without the editor. The editor's Play button runs the same
|
||||
//! [`game_test::GamePlugin`] through its own game runner instead.
|
||||
|
||||
use bevy::asset::AssetMode::Processed;
|
||||
use bevy::camera_controller::free_camera::FreeCameraPlugin;
|
||||
use bevy::image::{ImageAddressMode, ImagePlugin, ImageSamplerDescriptor};
|
||||
@@ -30,7 +26,7 @@ fn main() -> AppExit {
|
||||
App::new()
|
||||
.add_plugins(default_plugins)
|
||||
.add_plugins(avian3d::prelude::PhysicsPlugins::default())
|
||||
.add_plugins(game_test::GamePlugin)
|
||||
.add_plugins(shinespark::GamePlugin)
|
||||
.add_plugins(FreeCameraPlugin)
|
||||
.add_plugins(EguiPlugin::default())
|
||||
.add_plugins(WorldInspectorPlugin::default()) // adds default options and `InspectorEguiImpl`s
|
||||
|
||||
Reference in New Issue
Block a user