Establish native deterministic codegen framework (#45)
Some checks failed
Native code generation / deterministic (macos-latest) (push) Has been cancelled
Native code generation / deterministic (ubuntu-latest) (push) Has been cancelled
Native code generation / deterministic (windows-latest) (push) Has been cancelled
Imaging and meshing gate / native (macos-latest) (push) Has been cancelled
Imaging and meshing gate / native (ubuntu-latest) (push) Has been cancelled
Imaging and meshing gate / native (windows-latest) (push) Has been cancelled
JPEG 2000 feature / linux (push) Has been cancelled
JPEG 2000 feature / macos (push) Has been cancelled
JPEG 2000 feature / windows (push) Has been cancelled
Skia feature / linux (push) Has been cancelled
Skia feature / macos (push) Has been cancelled
Skia feature / windows (push) Has been cancelled
Some checks failed
Native code generation / deterministic (macos-latest) (push) Has been cancelled
Native code generation / deterministic (ubuntu-latest) (push) Has been cancelled
Native code generation / deterministic (windows-latest) (push) Has been cancelled
Imaging and meshing gate / native (macos-latest) (push) Has been cancelled
Imaging and meshing gate / native (ubuntu-latest) (push) Has been cancelled
Imaging and meshing gate / native (windows-latest) (push) Has been cancelled
JPEG 2000 feature / linux (push) Has been cancelled
JPEG 2000 feature / macos (push) Has been cancelled
JPEG 2000 feature / windows (push) Has been cancelled
Skia feature / linux (push) Has been cancelled
Skia feature / macos (push) Has been cancelled
Skia feature / windows (push) Has been cancelled
This commit is contained in:
31
.gitea/workflows/codegen.yml
Normal file
31
.gitea/workflows/codegen.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
name: Native code generation
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deterministic:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
components: clippy,rustfmt
|
||||||
|
- name: Test diagnostics and byte-identical generation
|
||||||
|
run: cargo test -p libremetaverse-codegen
|
||||||
|
- name: Verify vendored hashes and checked-in output
|
||||||
|
run: cargo run -p libremetaverse-codegen -- check
|
||||||
|
- name: Regenerate twice without reference checkout access
|
||||||
|
run: |
|
||||||
|
cargo run -p libremetaverse-codegen -- generate
|
||||||
|
cargo run -p libremetaverse-codegen -- generate
|
||||||
|
git diff --exit-code -- codegen/generated
|
||||||
|
- name: Lint native generator
|
||||||
|
run: cargo clippy -p libremetaverse-codegen --all-targets -- -D warnings
|
||||||
|
- name: Prove normal consumer build does not execute generation
|
||||||
|
run: cargo build -p libremetaverse --locked
|
||||||
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -370,6 +370,15 @@ dependencies = [
|
|||||||
"libremetaverse-types",
|
"libremetaverse-types",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libremetaverse-codegen"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libremetaverse-compat-tests"
|
name = "libremetaverse-compat-tests"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
@@ -691,6 +700,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ members = [
|
|||||||
"crates/libremetaverse-voice-webrtc",
|
"crates/libremetaverse-voice-webrtc",
|
||||||
"programs",
|
"programs",
|
||||||
"tests/compat",
|
"tests/compat",
|
||||||
|
"tools/codegen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
|
|||||||
@@ -178,3 +178,6 @@ baselines are documented in
|
|||||||
[`docs/imaging-meshing.md`](docs/imaging-meshing.md).
|
[`docs/imaging-meshing.md`](docs/imaging-meshing.md).
|
||||||
The controlled audit aggregates every expected failure by standardized C#
|
The controlled audit aggregates every expected failure by standardized C#
|
||||||
member ID and rejects unrelated fixture, assertion, compile, or symbol errors.
|
member ID and rejects unrelated fixture, assertion, compile, or symbol errors.
|
||||||
|
The deterministic, Rust-only source-data generator framework and its complete
|
||||||
|
pinned input inventory are documented in
|
||||||
|
[`codegen/README.md`](codegen/README.md).
|
||||||
|
|||||||
60
codegen/README.md
Normal file
60
codegen/README.md
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# Native data generation
|
||||||
|
|
||||||
|
`libremetaverse-codegen` is the Rust-only framework for the six source
|
||||||
|
generators present at LibreMetaverse commit
|
||||||
|
`2aa70bb68513b39795da5d13c88f31b86e85a3ba`. Normal builds compile only the
|
||||||
|
checked-in Rust outputs. They do not run this tool, invoke .NET or Roslyn, read
|
||||||
|
an environment-dependent path, access the network, or open the sibling
|
||||||
|
reference checkout.
|
||||||
|
|
||||||
|
## Provenance inventory
|
||||||
|
|
||||||
|
[`sources.json`](sources.json) is the machine-readable inventory. It records
|
||||||
|
the upstream repository and commit, source-generator hashes, every actual
|
||||||
|
`AdditionalFile`, its vendored path, SHA-256, format, and BSD-3-Clause license.
|
||||||
|
|
||||||
|
| Golden generator | Pinned data inputs |
|
||||||
|
| --- | --- |
|
||||||
|
| PacketSourceGenerator | `message_template.msg` |
|
||||||
|
| VisualParamGenerator | `avatar_lad.xml` |
|
||||||
|
| SkeletonGenerator | `avatar_skeleton.xml` |
|
||||||
|
| AttentionsGenerator | `attentions.xml`, `attentionsN.xml` |
|
||||||
|
| TreesGenerator | `trees.xml`, `grass.xml` |
|
||||||
|
| GenepoolGenerator | `genepool.xml` |
|
||||||
|
|
||||||
|
The C# project does not provide the optional `visualparamtemplate.cs` file.
|
||||||
|
The pinned VisualParam generator therefore uses the template embedded in its
|
||||||
|
own source; the inventory records that generator source and hash as provenance.
|
||||||
|
|
||||||
|
The files under `inputs/` are exact, unmodified snapshots. Their license and
|
||||||
|
copyright attribution are covered by the repository
|
||||||
|
[`LICENSE.md`](../LICENSE.md). The generated source manifest repeats each hash
|
||||||
|
and license in its header and data table.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
Regenerate every currently registered Rust output using only checked-in data:
|
||||||
|
|
||||||
|
```console
|
||||||
|
cargo run -p libremetaverse-codegen -- generate
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify hashes and reject stale output without writing:
|
||||||
|
|
||||||
|
```console
|
||||||
|
cargo run -p libremetaverse-codegen -- check
|
||||||
|
```
|
||||||
|
|
||||||
|
Maintainers can refresh the vendored snapshots from an explicitly supplied
|
||||||
|
checkout. The command verifies all six golden generator hashes and all input
|
||||||
|
hashes before writing, so a different upstream revision is rejected:
|
||||||
|
|
||||||
|
```console
|
||||||
|
cargo run -p libremetaverse-codegen -- vendor ../libremetaverse
|
||||||
|
```
|
||||||
|
|
||||||
|
Generation uses UTF-8 with an optional BOM, normalizes CRLF/CR to LF, rejects
|
||||||
|
NUL input, reports stable `path:line:column: severity[code]` diagnostics, sorts
|
||||||
|
manifest records by stable IDs, emits provenance-rich generated headers, and
|
||||||
|
always terminates output with one LF. Tests generate twice in memory and
|
||||||
|
require byte identity before comparing with the checked-in file.
|
||||||
32
codegen/generated/source_manifest.rs
Normal file
32
codegen/generated/source_manifest.rs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// @generated by libremetaverse-codegen; DO NOT EDIT.
|
||||||
|
// Regenerate: cargo run -p libremetaverse-codegen -- generate
|
||||||
|
// Generator: source-manifest
|
||||||
|
// Source: codegen/inputs/attentions.xml sha256=bdbc4ca02dd3bde78b86e796f7eb4ada0000e47be9a127e35d2b77f3010a20af license=BSD-3-Clause
|
||||||
|
// Source: codegen/inputs/attentionsN.xml sha256=80055e12a04d05ef5bb16e8c542cd6c218735f8c72f7e48317b8a34282d1ac5b license=BSD-3-Clause
|
||||||
|
// Source: codegen/inputs/avatar_lad.xml sha256=6f97a1408fa8f0ab5c09043da433c701701fe075e8a97867fcbcda207adf9eaf license=BSD-3-Clause
|
||||||
|
// Source: codegen/inputs/avatar_skeleton.xml sha256=addb3cc4cd582ed4343d778e06daf90c6b77b61b4ecb4a20d4bf202c2b93908a license=BSD-3-Clause
|
||||||
|
// Source: codegen/inputs/genepool.xml sha256=6fa1391cd98fddec0d7fe762343ea21e53a655a8ddd4f33af52f8a02aaa3f56d license=BSD-3-Clause
|
||||||
|
// Source: codegen/inputs/grass.xml sha256=90015f9768afe3cfee761d04239bf9e284b2739b095b7ab8331966fa1fbfcb4e license=BSD-3-Clause
|
||||||
|
// Source: codegen/inputs/message_template.msg sha256=15e524a46a9a449ead33c26d495a292ae2e100e641a408ac66ef63b8a7a2489d license=BSD-3-Clause
|
||||||
|
// Source: codegen/inputs/trees.xml sha256=f54e626b00bd2c4fec9f59a574a45860f209e4440bbb02b81d27050b9df8ffba license=BSD-3-Clause
|
||||||
|
|
||||||
|
pub const UPSTREAM_COMMIT: &str = "2aa70bb68513b39795da5d13c88f31b86e85a3ba";
|
||||||
|
pub const UPSTREAM_REPOSITORY: &str = "https://github.com/cinderblocks/libremetaverse";
|
||||||
|
pub const SOURCES: &[(&str, &str, &str, &str)] = &[
|
||||||
|
("attentions", "codegen/inputs/attentions.xml", "bdbc4ca02dd3bde78b86e796f7eb4ada0000e47be9a127e35d2b77f3010a20af", "BSD-3-Clause"),
|
||||||
|
("attentions_updated", "codegen/inputs/attentionsN.xml", "80055e12a04d05ef5bb16e8c542cd6c218735f8c72f7e48317b8a34282d1ac5b", "BSD-3-Clause"),
|
||||||
|
("avatar_lad", "codegen/inputs/avatar_lad.xml", "6f97a1408fa8f0ab5c09043da433c701701fe075e8a97867fcbcda207adf9eaf", "BSD-3-Clause"),
|
||||||
|
("avatar_skeleton", "codegen/inputs/avatar_skeleton.xml", "addb3cc4cd582ed4343d778e06daf90c6b77b61b4ecb4a20d4bf202c2b93908a", "BSD-3-Clause"),
|
||||||
|
("genepool", "codegen/inputs/genepool.xml", "6fa1391cd98fddec0d7fe762343ea21e53a655a8ddd4f33af52f8a02aaa3f56d", "BSD-3-Clause"),
|
||||||
|
("grass", "codegen/inputs/grass.xml", "90015f9768afe3cfee761d04239bf9e284b2739b095b7ab8331966fa1fbfcb4e", "BSD-3-Clause"),
|
||||||
|
("message_template", "codegen/inputs/message_template.msg", "15e524a46a9a449ead33c26d495a292ae2e100e641a408ac66ef63b8a7a2489d", "BSD-3-Clause"),
|
||||||
|
("trees", "codegen/inputs/trees.xml", "f54e626b00bd2c4fec9f59a574a45860f209e4440bbb02b81d27050b9df8ffba", "BSD-3-Clause"),
|
||||||
|
];
|
||||||
|
pub const GENERATORS: &[(&str, &str, &str, &str)] = &[
|
||||||
|
("attentions", "SourceGenerators/AttentionsGenerator/AttentionsGenerator.cs", "b2870ae020c42a8a6ec455363fbb70a1b3c94c814b205bad9b61609d5230da3e", "BSD-3-Clause"),
|
||||||
|
("genepool", "SourceGenerators/GenepoolGenerator/GenepoolGenerator.cs", "a48e914fc62efbb1bc4b2e17162121621eebd4cf03872cc226bc8a83a9230cd2", "BSD-3-Clause"),
|
||||||
|
("packets", "SourceGenerators/PacketSourceGenerator/PacketSourceGenerator.cs", "8e63c0356cd0269e10521d15fbcde780cf58f821935601b4f223933930db758f", "BSD-3-Clause"),
|
||||||
|
("skeleton", "SourceGenerators/SkeletonGenerator/SkeletonGenerator.cs", "6e1a5dd95b2604319cf65037c59b69a739af563e49cfb29e5db00c3d9c371d49", "BSD-3-Clause"),
|
||||||
|
("trees", "SourceGenerators/TreesGenerator/TreesGenerator.cs", "151a593ba215400361f9bf20848537a5c01bb0ab4a95b15c1e16fa4b1897f8bb", "BSD-3-Clause"),
|
||||||
|
("visual_params", "SourceGenerators/VisualParamGenerator/VisualParamGenerator.cs", "bff0ec0f823b415e811f0c84210b3ee8d7baa65cc21de19ed19b3c26560c6dac", "BSD-3-Clause"),
|
||||||
|
];
|
||||||
51
codegen/inputs/attentions.xml
Normal file
51
codegen/inputs/attentions.xml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?xml version="1.0" encoding="US-ASCII" standalone="yes"?>
|
||||||
|
<!--
|
||||||
|
Default values for "Look At" controls.
|
||||||
|
Various events compete for avatar attention. I.E. control where the
|
||||||
|
user's avatar looks.
|
||||||
|
The avatar's head will turn to look towards the source of those events
|
||||||
|
as much as is possible.
|
||||||
|
If the head cannot turn due to an animation override, the eyes will still
|
||||||
|
track those events.
|
||||||
|
Avatar attention will be taken by events of equal of greater priorities
|
||||||
|
and will last for timeout number of seconds before reverting to idle.
|
||||||
|
Negative timeout values indicate attentions that never time out.
|
||||||
|
Avatar sex determines which set of attention settings are used.
|
||||||
|
Within each set, the following named attentions relate to the indicated events:
|
||||||
|
|
||||||
|
IDLE: Tracks the mouse pointer movement.
|
||||||
|
AUTO LISTEN: Tracks nearby chat.
|
||||||
|
FREELOOK: Tracks "target objects" and a case of mouse moved in 3rd person mode.
|
||||||
|
RESPOND: Tracks the beginning of typing.
|
||||||
|
HOVER: Tracks objects the mouse lingers over when "show hover tooltips" is on.
|
||||||
|
CONVERSATION: Tracks avatars and other objects clicked on.
|
||||||
|
SEOECT: Tracks objects grabbed and being moved.
|
||||||
|
FOCUS: Freezes during avatar customization and when focused on object or point.
|
||||||
|
MOUSELOOK: Tracks center of view when in mouselook view mode.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<linden_attentions version="1.0">
|
||||||
|
<gender name="Masculine">
|
||||||
|
<param attention="idle" priority="1.0" timeout="3.0" />
|
||||||
|
<param attention="auto_listen" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="freelook" priority="2.0" timeout="2.0" />
|
||||||
|
<param attention="respond" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="hover" priority="4.0" timeout="1.0" />
|
||||||
|
<param attention="conversation" priority="0.0" timeout="-1" />
|
||||||
|
<param attention="select" priority="6.0" timeout="-1" />
|
||||||
|
<param attention="focus" priority="6.0" timeout="-1" />
|
||||||
|
<param attention="mouselook" priority="7.0" timeout="-1" />
|
||||||
|
</gender>
|
||||||
|
<gender name="Feminine">
|
||||||
|
<param attention="idle" priority="1.0" timeout="3.0" />
|
||||||
|
<param attention="auto_listen" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="freelook" priority="2.0" timeout="2.0" />
|
||||||
|
<param attention="respond" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="hover" priority="4.0" timeout="1.0" />
|
||||||
|
<param attention="conversation" priority="0.0" timeout="-1" />
|
||||||
|
<param attention="select" priority="6.0" timeout="-1" />
|
||||||
|
<param attention="focus" priority="6.0" timeout="-1" />
|
||||||
|
<param attention="mouselook" priority="7.0" timeout="-1" />
|
||||||
|
</gender>
|
||||||
|
</linden_attentions>
|
||||||
|
|
||||||
51
codegen/inputs/attentionsN.xml
Normal file
51
codegen/inputs/attentionsN.xml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?xml version="1.0" encoding="US-ASCII" standalone="yes"?>
|
||||||
|
<!--
|
||||||
|
Default values for "Look At" controls.
|
||||||
|
Various events compete for avatar attention. I.E. control where the
|
||||||
|
user's avatar looks.
|
||||||
|
The avatar's head will turn to look towards the source of those events
|
||||||
|
as much as is possible.
|
||||||
|
If the head cannot turn due to an animation override, the eyes will still
|
||||||
|
track those events.
|
||||||
|
Avatar attention will be taken by events of equal of greater priorities
|
||||||
|
and will last for timeout number of seconds before reverting to idle.
|
||||||
|
Negative timeout values indicate attentions that never time out.
|
||||||
|
Avatar sex determines which set of attention settings are used.
|
||||||
|
Within each set, the following named attentions relate to the indicated events:
|
||||||
|
|
||||||
|
IDLE: Tracks the mouse pointer movement.
|
||||||
|
AUTO LISTEN: Tracks nearby chat.
|
||||||
|
FREELOOK: Tracks "target objects" and a case of mouse moved in 3rd person mode.
|
||||||
|
RESPOND: Tracks the beginning of typing.
|
||||||
|
HOVER: Tracks objects the mouse lingers over when "show hover tooltips" is on.
|
||||||
|
CONVERSATION: Tracks avatars and other objects clicked on.
|
||||||
|
SEOECT: Tracks objects grabbed and being moved.
|
||||||
|
FOCUS: Freezes during avatar customization and when focused on object or point.
|
||||||
|
MOUSELOOK: Tracks center of view when in mouselook view mode.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<linden_attentions version="1.0">
|
||||||
|
<gender name="Masculine">
|
||||||
|
<param attention="idle" priority="1.0" timeout="3.0" />
|
||||||
|
<param attention="auto_listen" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="freelook" priority="2.0" timeout="2.0" />
|
||||||
|
<param attention="respond" priority="3.0" timeout="3.0" />
|
||||||
|
<param attention="hover" priority="4.0" timeout="1.0" />
|
||||||
|
<param attention="conversation" priority="5.0" timeout="3.0" />
|
||||||
|
<param attention="select" priority="3.5" timeout="-1" />
|
||||||
|
<param attention="focus" priority="3.5" timeout="20.0" />
|
||||||
|
<param attention="mouselook" priority="7.0" timeout="-1" />
|
||||||
|
</gender>
|
||||||
|
<gender name="Feminine">
|
||||||
|
<param attention="idle" priority="1.0" timeout="3.0" />
|
||||||
|
<param attention="auto_listen" priority="3.0" timeout="4.0" />
|
||||||
|
<param attention="freelook" priority="2.0" timeout="2.0" />
|
||||||
|
<param attention="respond" priority="3.0" timeout="6.0" />
|
||||||
|
<param attention="hover" priority="4.0" timeout="1.0" />
|
||||||
|
<param attention="conversation" priority="5.0" timeout="6.0" />
|
||||||
|
<param attention="select" priority="2.5" timeout="-1" />
|
||||||
|
<param attention="focus" priority="2.5" timeout="10.0" />
|
||||||
|
<param attention="mouselook" priority="7.0" timeout="-1" />
|
||||||
|
</gender>
|
||||||
|
</linden_attentions>
|
||||||
|
|
||||||
17504
codegen/inputs/avatar_lad.xml
Normal file
17504
codegen/inputs/avatar_lad.xml
Normal file
File diff suppressed because it is too large
Load Diff
232
codegen/inputs/avatar_skeleton.xml
Normal file
232
codegen/inputs/avatar_skeleton.xml
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
<linden_skeleton num_bones="133" num_collision_volumes="26" version="2.0">
|
||||||
|
<bone aliases="hip avatar_mPelvis" connected="false" end="0.000 0.000 0.084" group="Torso" name="mPelvis" pivot="0.000000 0.000000 1.067015" pos="0.000 0.000 1.067" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true">
|
||||||
|
<collision_volume end="0.030 0.000 0.095" group="Collision" name="PELVIS" pos="-0.01 0 -0.02" rot="0.000000 8.00000 0.000000" scale="0.12 0.16 0.17" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="-0.100 0.000 0.000" group="Collision" name="BUTT" pos="-0.06 0 -0.1" rot="0.000000 0.00000 0.000000" scale="0.1 0.1 0.1" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mSpine1" connected="true" end="0.000 0.000 -0.084" group="Spine" name="mSpine1" pivot="0.000000 0.000000 0.084073" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mSpine2" connected="true" end="0.000 0.000 0.084" group="Spine" name="mSpine2" pivot="0.000000 0.000000 -0.084073" pos="0.000 0.000 -0.084" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="abdomen avatar_mTorso" connected="true" end="-0.015 0.000 0.205" group="Torso" name="mTorso" pivot="0.000000 0.000000 0.084073" pos="0.000 0.000 0.084" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.028 0.000 0.094" group="Collision" name="BELLY" pos="0.028 0 0.04" rot="0.000000 8.00000 0.000000" scale="0.09 0.13 0.15" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="0.000 0.100 0.000" group="Collision" name="LEFT_HANDLE" pos="0.0 0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="0.000 -0.100 0.000" group="Collision" name="RIGHT_HANDLE" pos="0.0 -0.10 0.058" rot="0.000000 0.00000 0.000000" scale="0.05 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="-0.100 0.000 0.000" group="Collision" name="LOWER_BACK" pos="0.0 0.0 0.023" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mSpine3" connected="true" end="0.015 0.000 -0.205" group="Spine" name="mSpine3" pivot="-0.015368 0.000000 0.204877" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mSpine4" connected="true" end="-0.015 0.000 0.205" group="Spine" name="mSpine4" pivot="0.015368 0.000000 -0.204877" pos="0.015 0.000 -0.205" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="chest avatar_mChest" connected="true" end="-0.010 0.000 0.250" group="Torso" name="mChest" pivot="-0.015368 0.000000 0.204877" pos="-0.015 0.000 0.205" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="-0.096 0.000 0.152" group="Collision" name="CHEST" pos="0.028 0 0.07" rot="0.000000 -10.00000 0.000000" scale="0.11 0.15 0.2" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="0.080 0.000 -0.006" group="Collision" name="LEFT_PEC" pos="0.119 0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="0.080 0.000 -0.006" group="Collision" name="RIGHT_PEC" pos="0.119 -0.082 0.042" rot="0.000000 4.29000 0.000000" scale="0.05 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<collision_volume end="-0.100 0.000 0.000" group="Collision" name="UPPER_BACK" pos="0.0 0.0 0.017" rot="0.000000 0.00000 0.000000" scale="0.09 0.13 0.15" support="base" reposition="true"/>
|
||||||
|
<bone aliases="neck avatar_mNeck" connected="true" end="0.000 0.000 0.077" group="Torso" name="mNeck" pivot="-0.009507 0.000000 0.251108" pos="-0.010 0.000 0.251" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 0.000 0.080" group="Collision" name="NECK" pos="0.0 0 0.02" rot="0.000000 0.000000 0.000000" scale="0.05 0.06 0.08" support="base"/>
|
||||||
|
<bone aliases="head avatar_mHead" connected="true" end="0.000 0.000 0.079" group="Torso" name="mHead" pivot="0.000000 -0.000000 0.075630" pos="0.000 -0.000 0.076" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 0.000 0.100" group="Collision" name="HEAD" pos="0.02 0 0.07" rot="0.000000 0.000000 0.000000" scale="0.11 0.09 0.12" support="base" reposition="true"/>
|
||||||
|
<bone aliases="figureHair avatar_mSkull" connected="false" end="0.000 0.000 0.033" group="Extra" name="mSkull" pivot="0.000000 0.000000 0.079000" pos="0.000 0.000 0.079" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mEyeRight" connected="false" end="0.025 0.000 0.000" group="Extra" name="mEyeRight" pivot="0.098466 -0.036000 0.079000" pos="0.098 -0.036 0.079" rot="0.000000 0.000000 -0.000000" scale="1.000 1.000 1.000" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mEyeLeft" connected="false" end="0.025 0.000 0.000" group="Extra" name="mEyeLeft" pivot="0.098461 0.036000 0.079000" pos="0.098 0.036 0.079" rot="0.000000 -0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceRoot" connected="false" end="0.020 0.000 0.000" group="Face" name="mFaceRoot" pivot="0.025000 0.000000 0.045000" pos="0.025 0.000 0.045" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mFaceEyeAltRight" connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltRight" pivot="0.073466 -0.036000 0.0339300" pos="0.073 -0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyeAltLeft" connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceEyeAltLeft" pivot="0.073461 0.036000 0.0339300" pos="0.073 0.036 0.034" rot="0.000000 0.000000 0.000000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceForeheadLeft" connected="false" end="0.024 0.004 0.018" group="Face" name="mFaceForeheadLeft" pivot="0.061 0.035 0.083" pos="0.061 0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceForeheadRight" connected="false" end="0.024 -0.004 0.018" group="Face" name="mFaceForeheadRight" pivot="0.061 -0.035 0.083" pos="0.061 -0.035 0.083" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowOuterLeft" connected="false" end="0.023 0.013 0.000" group="Eyes" name="mFaceEyebrowOuterLeft" pivot="0.064 0.051 0.048" pos="0.064 0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowCenterLeft" connected="false" end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterLeft" pivot="0.070 0.043 0.056" pos="0.070 0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowInnerLeft" connected="false" end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerLeft" pivot="0.075 0.022 0.051" pos="0.075 0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowOuterRight" connected="false" end="0.023 -0.013 0.000" group="Eyes" name="mFaceEyebrowOuterRight" pivot="0.064 -0.051 0.048" pos="0.064 -0.051 0.048" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowCenterRight" connected="false" end="0.027 0.000 0.000" group="Eyes" name="mFaceEyebrowCenterRight" pivot="0.070 -0.043 0.056" pos="0.070 -0.043 0.056" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyebrowInnerRight" connected="false" end="0.026 0.000 0.000" group="Eyes" name="mFaceEyebrowInnerRight" pivot="0.075 -0.022 0.051" pos="0.075 -0.022 0.051" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyeLidUpperLeft" connected="false" end="0.027 0.000 0.005" group="Eyes" name="mFaceEyeLidUpperLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyeLidLowerLeft" connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerLeft" pivot="0.073 0.036 0.034" pos="0.073 0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyeLidUpperRight" connected="false" end="0.027 0.000 0.005" group="Eyes" name="mFaceEyeLidUpperRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyeLidLowerRight" connected="false" end="0.024 0.000 -0.007" group="Eyes" name="mFaceEyeLidLowerRight" pivot="0.073 -0.036 0.034" pos="0.073 -0.036 0.034" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEar1Left" connected="false" end="-0.019 0.018 0.025" group="Ears" name="mFaceEar1Left" pivot="0.000 0.080 0.002" pos="0.000 0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mFaceEar2Left" connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Left" pivot="-0.019 0.018 0.025" pos="-0.019 0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mFaceEar1Right" connected="false" end="-0.019 -0.018 0.025" group="Ears" name="mFaceEar1Right" pivot="0.000 -0.080 0.002" pos="0.000 -0.080 0.002" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mFaceEar2Right" connected="true" end="0.000 0.000 0.033" group="Ears" name="mFaceEar2Right" pivot="-0.019 -0.018 0.025" pos="-0.019 -0.018 0.025" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mFaceNoseLeft" connected="false" end="0.015 0.004 0.000" group="Face" name="mFaceNoseLeft" pivot="0.086 0.015 -0.004" pos="0.086 0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceNoseCenter" connected="false" end="0.025 0.000 0.000" group="Face" name="mFaceNoseCenter" pivot="0.102 0.000 0.000" pos="0.102 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceNoseRight" connected="false" end="0.015 -0.004 0.000" group="Face" name="mFaceNoseRight" pivot="0.086 -0.015 -0.004" pos="0.086 -0.015 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceCheekLowerLeft" connected="false" end="0.013 0.030 0.000" group="Face" name="mFaceCheekLowerLeft" pivot="0.050 0.034 -0.031" pos="0.050 0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceCheekUpperLeft" connected="false" end="0.022 0.015 0.000" group="Face" name="mFaceCheekUpperLeft" pivot="0.070 0.034 -0.005" pos="0.070 0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceCheekLowerRight" connected="false" end="0.013 -0.030 0.000" group="Face" name="mFaceCheekLowerRight" pivot="0.050 -0.034 -0.031" pos="0.050 -0.034 -0.031" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceCheekUpperRight" connected="false" end="0.022 -0.015 0.000" group="Face" name="mFaceCheekUpperRight" pivot="0.070 -0.034 -0.005" pos="0.070 -0.034 -0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceJaw" connected="false" end="0.059 0.000 -0.039" group="Mouth" name="mFaceJaw" pivot="-0.001 0.000 -0.015" pos="-0.001 0.000 -0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mFaceChin" connected="false" end="0.021 0.000 -0.018" group="Mouth" name="mFaceChin" pivot="0.074 0.000 -0.054" pos="0.074 0.000 -0.054" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceTeethLower" connected="false" end="0.035 0.000 0.000" group="Mouth" name="mFaceTeethLower" pivot="0.021 0.000 -0.039" pos="0.021 0.000 -0.039" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mFaceLipLowerLeft" connected="false" end="0.034 0.017 0.005" group="Lips" name="mFaceLipLowerLeft" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipLowerRight" connected="false" end="0.034 -0.017 0.005" group="Lips" name="mFaceLipLowerRight" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipLowerCenter" connected="false" end="0.040 0.000 0.002" group="Lips" name="mFaceLipLowerCenter" pivot="0.045 0.000 0.000" pos="0.045 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceTongueBase" connected="false" end="0.022 0.000 0.007" group="Mouth" name="mFaceTongueBase" pivot="0.039 0.000 0.005" pos="0.039 0.000 0.005" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mFaceTongueTip" connected="true" end="0.010 0.000 0.000" group="Mouth" name="mFaceTongueTip" pivot="0.022 0.000 0.007" pos="0.022 0.000 0.007" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mFaceJawShaper" connected="false" end="-0.017 0.000 0.000" group="Face" name="mFaceJawShaper" pivot="0.000 0.000 0.000" pos="0.000 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceForeheadCenter" connected="false" end="0.036 0.000 0.000" group="Face" name="mFaceForeheadCenter" pivot="0.069 0.000 0.065" pos="0.069 0.000 0.065" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceNoseBase" connected="false" end="0.014 0.000 0.000" group="Nose" name="mFaceNoseBase" pivot="0.094 0.000 -0.016" pos="0.094 0.000 -0.016" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceTeethUpper" connected="false" end="0.035 0.000 0.000" group="Mouth" name="mFaceTeethUpper" pivot="0.020 0.000 -0.030" pos="0.020 0.000 -0.030" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mFaceLipUpperLeft" connected="false" end="0.041 0.015 0.000" group="Lips" name="mFaceLipUpperLeft" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipUpperRight" connected="false" end="0.041 -0.015 0.000" group="Lips" name="mFaceLipUpperRight" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipCornerLeft" connected="false" end="0.045 0.051 0.000" group="Lips" name="mFaceLipCornerLeft" pivot="0.028 -0.019 -0.010" pos="0.028 -0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipCornerRight" connected="false" end="0.045 -0.051 0.000" group="Lips" name="mFaceLipCornerRight" pivot="0.028 0.019 -0.010" pos="0.028 0.019 -0.010" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceLipUpperCenter" connected="false" end="0.043 0.000 0.002" group="Lips" name="mFaceLipUpperCenter" pivot="0.045 0.000 -0.003" pos="0.045 0.000 -0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mFaceEyecornerInnerLeft" connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerLeft" pivot="0.075 0.017 0.032" pos="0.075 0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceEyecornerInnerRight" connected="false" end="0.016 0.000 0.000" group="Face" name="mFaceEyecornerInnerRight" pivot="0.075 -0.017 0.032" pos="0.075 -0.017 0.032" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFaceNoseBridge" connected="false" end="0.015 0.000 0.008" group="Nose" name="mFaceNoseBridge" pivot="0.091 0.000 0.020" pos="0.091 0.000 0.020" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="lCollar avatar_mCollarLeft" connected="false" end="0.000 0.079 0.000" group="Arms" name="mCollarLeft" pivot="-0.020927 0.084665 0.165396" pos="-0.021 0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 0.100 0.000" group="Collision" name="L_CLAVICLE" pos="0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="lShldr avatar_mShoulderLeft" connected="true" end="0.000 0.247 0.000" group="Arms" name="mShoulderLeft" pivot="0.000000 0.079000 -0.000000" pos="0.000 0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 0.130 -0.003" group="Collision" name="L_UPPER_ARM" pos="0.0 0.12 0.01" rot="-5.000000 0.00000 0.000000" scale="0.05 0.17 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="lForeArm avatar_mElbowLeft" connected="true" end="0.000 0.205 0.000" group="Arms" name="mElbowLeft" pivot="0.000000 0.248000 0.000000" pos="0.000 0.248 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 0.100 -0.001" group="Collision" name="L_LOWER_ARM" pos="0.0 0.1 0.0" rot="-3.000000 0.00000 0.000000" scale="0.04 0.14 0.04" support="base" reposition="true"/>
|
||||||
|
<bone aliases="lHand avatar_mWristLeft" connected="true" end="0.000 0.060 0.000" group="Arms" name="mWristLeft" pivot="-0.000000 0.204846 0.000000" pos="-0.000 0.205 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.005 0.049 -0.001" group="Collision" name="L_HAND" pos="0.01 0.05 0.0" rot="-3.000000 0.00000 -10.000000" scale="0.05 0.08 0.03" support="base"/>
|
||||||
|
<bone aliases="avatar_mHandMiddle1Left" connected="false" end="-0.001 0.040 -0.006" group="Hand" name="mHandMiddle1Left" pivot="0.013 0.101 0.015" pos="0.013 0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandMiddle2Left" connected="true" end="-0.001 0.049 -0.008" group="Hand" name="mHandMiddle2Left" pivot="-0.001 0.040 -0.006" pos="-0.001 0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandMiddle3Left" connected="true" end="-0.002 0.033 -0.006" group="Hand" name="mHandMiddle3Left" pivot="-0.001 0.049 -0.008" pos="-0.001 0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandIndex1Left" connected="false" end="0.017 0.036 -0.006" group="Hand" name="mHandIndex1Left" pivot="0.038 0.097 0.015" pos="0.038 0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandIndex2Left" connected="true" end="0.014 0.032 -0.006" group="Hand" name="mHandIndex2Left" pivot="0.017 0.036 -0.006" pos="0.017 0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandIndex3Left" connected="true" end="0.011 0.025 -0.004" group="Hand" name="mHandIndex3Left" pivot="0.014 0.032 -0.006" pos="0.014 0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandRing1Left" connected="false" end="-0.013 0.038 -0.008" group="Hand" name="mHandRing1Left" pivot="-0.010 0.099 0.009" pos="-0.010 0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandRing2Left" connected="true" end="-0.013 0.040 -0.009" group="Hand" name="mHandRing2Left" pivot="-0.013 0.038 -0.008" pos="-0.013 0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandRing3Left" connected="true" end="-0.010 0.028 -0.006" group="Hand" name="mHandRing3Left" pivot="-0.013 0.040 -0.009" pos="-0.013 0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandPinky1Left" connected="false" end="-0.024 0.025 -0.006" group="Hand" name="mHandPinky1Left" pivot="-0.031 0.095 0.003" pos="-0.031 0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandPinky2Left" connected="true" end="-0.015 0.018 -0.004" group="Hand" name="mHandPinky2Left" pivot="-0.024 0.025 -0.006" pos="-0.024 0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandPinky3Left" connected="true" end="-0.013 0.016 -0.004" group="Hand" name="mHandPinky3Left" pivot="-0.015 0.018 -0.004" pos="-0.015 0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandThumb1Left" connected="false" end="0.028 0.032 0.000" group="Hand" name="mHandThumb1Left" pivot="0.031 0.026 0.004" pos="0.031 0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandThumb2Left" connected="true" end="0.023 0.031 0.000" group="Hand" name="mHandThumb2Left" pivot="0.028 0.032 -0.001" pos="0.028 0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandThumb3Left" connected="true" end="0.015 0.025 0.000" group="Hand" name="mHandThumb3Left" pivot="0.023 0.031 -0.001" pos="0.023 0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="rCollar avatar_mCollarRight" connected="false" end="0.000 -0.079 0.000" group="Arms" name="mCollarRight" pivot="-0.020927 -0.085000 0.165396" pos="-0.021 -0.085 0.165" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 -0.100 0.000" group="Collision" name="R_CLAVICLE" pos="0.02 0 0.02" rot="0.000000 0.00000 0.000000" scale="0.07 0.14 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="rShldr avatar_mShoulderRight" connected="true" end="0.000 -0.247 0.000" group="Arms" name="mShoulderRight" pivot="0.000000 -0.079418 -0.000000" pos="0.000 -0.079 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 -0.130 -0.003" group="Collision" name="R_UPPER_ARM" pos="0.0 -0.12 0.01" rot="5.000000 0.00000 0.000000" scale="0.05 0.17 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="rForeArm avatar_mElbowRight" connected="true" end="0.000 -0.205 0.000" group="Arms" name="mElbowRight" pivot="0.000000 -0.248000 -0.000000" pos="0.000 -0.248 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.000 -0.100 -0.001" group="Collision" name="R_LOWER_ARM" pos="0.0 -0.1 0.0" rot="3.000000 0.00000 0.000000" scale="0.04 0.14 0.04" support="base" reposition="true"/>
|
||||||
|
<bone aliases="rHand avatar_mWristRight" connected="true" end="0.000 -0.060 0.000" group="Arms" name="mWristRight" pivot="-0.000000 -0.205000 -0.000000" pos="0.000 -0.205 -0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.005 -0.049 -0.001" group="Collision" name="R_HAND" pos="0.01 -0.05 0.0" rot="3.000000 0.00000 10.000000" scale="0.05 0.08 0.03" support="base"/>
|
||||||
|
<bone aliases="avatar_mHandMiddle1Right" connected="false" end="-0.001 -0.040 -0.006" group="Hand" name="mHandMiddle1Right" pivot="0.013 -0.101 0.015" pos="0.013 -0.101 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandMiddle2Right" connected="true" end="-0.001 -0.049 -0.008" group="Hand" name="mHandMiddle2Right" pivot="-0.001 -0.040 -0.006" pos="-0.001 -0.040 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandMiddle3Right" connected="true" end="-0.002 -0.033 -0.006" group="Hand" name="mHandMiddle3Right" pivot="-0.001 -0.049 -0.008" pos="-0.001 -0.049 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandIndex1Right" connected="false" end="0.017 -0.036 -0.006" group="Hand" name="mHandIndex1Right" pivot="0.038 -0.097 0.015" pos="0.038 -0.097 0.015" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandIndex2Right" connected="true" end="0.014 -0.032 -0.006" group="Hand" name="mHandIndex2Right" pivot="0.017 -0.036 -0.006" pos="0.017 -0.036 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandIndex3Right" connected="true" end="0.011 -0.025 -0.004" group="Hand" name="mHandIndex3Right" pivot="0.014 -0.032 -0.006" pos="0.014 -0.032 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandRing1Right" connected="false" end="-0.013 -0.038 -0.008" group="Hand" name="mHandRing1Right" pivot="-0.010 -0.099 0.009" pos="-0.010 -0.099 0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandRing2Right" connected="true" end="-0.013 -0.040 -0.009" group="Hand" name="mHandRing2Right" pivot="-0.013 -0.038 -0.008" pos="-0.013 -0.038 -0.008" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandRing3Right" connected="true" end="-0.010 -0.028 -0.006" group="Hand" name="mHandRing3Right" pivot="-0.013 -0.040 -0.009" pos="-0.013 -0.040 -0.009" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandPinky1Right" connected="false" end="-0.024 -0.025 -0.006" group="Hand" name="mHandPinky1Right" pivot="-0.031 -0.095 0.003" pos="-0.031 -0.095 0.003" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandPinky2Right" connected="true" end="-0.015 -0.018 -0.004" group="Hand" name="mHandPinky2Right" pivot="-0.024 -0.025 -0.006" pos="-0.024 -0.025 -0.006" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandPinky3Right" connected="true" end="-0.013 -0.016 -0.004" group="Hand" name="mHandPinky3Right" pivot="-0.015 -0.018 -0.004" pos="-0.015 -0.018 -0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHandThumb1Right" connected="false" end="0.028 -0.032 0.000" group="Hand" name="mHandThumb1Right" pivot="0.031 -0.026 0.004" pos="0.031 -0.026 0.004" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandThumb2Right" connected="true" end="0.023 -0.031 0.000" group="Hand" name="mHandThumb2Right" pivot="0.028 -0.032 -0.001" pos="0.028 -0.032 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHandThumb3Right" connected="true" end="0.015 -0.025 0.000" group="Hand" name="mHandThumb3Right" pivot="0.023 -0.031 -0.001" pos="0.023 -0.031 -0.001" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mWingsRoot" connected="false" end="-0.061 0.000 0.000" group="Wing" name="mWingsRoot" pivot="-0.014 0.000 0.000" pos="-0.014 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mWing1Left" connected="false" end="-0.168 0.169 0.067" group="Wing" name="mWing1Left" pivot="-0.099 0.105 0.181" pos="-0.099 0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing2Left" connected="true" end="-0.181 0.183 0.000" group="Wing" name="mWing2Left" pivot="-0.168 0.169 0.067" pos="-0.168 0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing3Left" connected="true" end="-0.171 0.173 0.000" group="Wing" name="mWing3Left" pivot="-0.181 0.183 0.000" pos="-0.181 0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing4Left" connected="true" end="-0.146 0.132 0.000" group="Wing" name="mWing4Left" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mWing4FanLeft" connected="true" end="-0.068 0.062 -0.159" group="Wing" name="mWing4FanLeft" pivot="-0.171 0.173 0.000" pos="-0.171 0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mWing1Right" connected="false" end="-0.168 -0.169 0.067" group="Wing" name="mWing1Right" pivot="-0.099 -0.105 0.181" pos="-0.099 -0.105 0.181" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing2Right" connected="true" end="-0.181 -0.183 0.000" group="Wing" name="mWing2Right" pivot="-0.168 -0.169 0.067" pos="-0.168 -0.169 0.067" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing3Right" connected="true" end="-0.171 -0.173 0.000" group="Wing" name="mWing3Right" pivot="-0.181 -0.183 0.000" pos="-0.181 -0.183 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mWing4Right" connected="true" end="-0.146 -0.132 0.000" group="Wing" name="mWing4Right" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mWing4FanRight" connected="true" end="-0.068 -0.062 -0.159" group="Wing" name="mWing4FanRight" pivot="-0.171 -0.173 0.000" pos="-0.171 -0.173 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="rThigh avatar_mHipRight" connected="false" end="-0.001 0.049 -0.491" group="Legs" name="mHipRight" pivot="0.033620 -0.128806 -0.041086" pos="0.034 -0.129 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true">
|
||||||
|
<collision_volume end="0.000 0.000 -0.200" group="Collision" name="R_UPPER_LEG" pos="-0.02 0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32" support="base" reposition="true"/>
|
||||||
|
<bone aliases="rShin avatar_mKneeRight" connected="true" end="-0.029 0.000 -0.469" group="Legs" name="mKneeRight" pivot="-0.000780 0.048635 -0.490922" pos="-0.001 0.049 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="-0.010 0.000 -0.150" group="Collision" name="R_LOWER_LEG" pos="-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25" support="base" reposition="true"/>
|
||||||
|
<bone aliases="rFoot avatar_mAnkleRight" connected="true" end="0.112 0.000 -0.061" group="Legs" name="mAnkleRight" pivot="-0.028869 0.000000 -0.468494" pos="-0.029 0.000 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.089 0.000 -0.026" group="Collision" name="R_FOOT" pos="0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFootRight" connected="true" end="0.105 -0.010 0.000" group="Extra" name="mFootRight" pivot="0.111956 -0.000000 -0.060637" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true">
|
||||||
|
<bone aliases="avatar_mToeRight" connected="false" end="0.020 0.000 0.000" group="Extra" name="mToeRight" pivot="0.105399 -0.010408 -0.000104" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="lThigh avatar_mHipLeft" connected="false" end="-0.001 -0.046 -0.491" group="Legs" name="mHipLeft" pivot="0.033757 0.126765 -0.040998" pos="0.034 0.127 -0.041" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true">
|
||||||
|
<collision_volume end="0.000 0.000 -0.200" group="Collision" name="L_UPPER_LEG" pos="-0.02 -0.05 -0.22" rot="0.000000 0.00000 0.000000" scale="0.09 0.09 0.32" support="base" reposition="true"/>
|
||||||
|
<bone aliases="lShin avatar_mKneeLeft" connected="true" end="-0.029 0.001 -0.469" group="Legs" name="mKneeLeft" pivot="-0.000887 -0.045568 -0.491053" pos="-0.001 -0.046 -0.491" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="-0.010 0.000 -0.150" group="Collision" name="L_LOWER_LEG" pos="-0.02 0.0 -0.2" rot="0.000000 0.00000 0.000000" scale="0.06 0.06 0.25" support="base" reposition="true"/>
|
||||||
|
<bone aliases="lFoot avatar_mAnkleLeft" connected="true" end="0.112 0.000 -0.061" group="Legs" name="mAnkleLeft" pivot="-0.028887 0.001378 -0.468449" pos="-0.029 0.001 -0.468" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base">
|
||||||
|
<collision_volume end="0.089 0.000 -0.026" group="Collision" name="L_FOOT" pos="0.077 0.0 -0.041" rot="0.000000 10.00000 0.000000" scale="0.13 0.05 0.05" support="base" reposition="true"/>
|
||||||
|
<bone aliases="avatar_mFootLeft" connected="true" end="0.105 0.008 0.001" group="Extra" name="mFootLeft" pivot="0.111956 -0.000000 -0.060620" pos="0.112 -0.000 -0.061" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base" reposition="true">
|
||||||
|
<bone aliases="avatar_mToeLeft" connected="false" end="0.020 0.000 0.000" group="Extra" name="mToeLeft" pivot="0.105387 0.008270 0.000871" pos="0.109 0.000 0.000" rot="0.000000 0.000000 0.000000" scale="1.000 1.000 1.000" support="base"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mTail1" connected="false" end="-0.197 0.000 0.000" group="Tail" name="mTail1" pivot="-0.116 0.000 0.047" pos="-0.116 0.000 0.047" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mTail2" connected="true" end="-0.168 0.000 0.000" group="Tail" name="mTail2" pivot="-0.197 0.000 0.000" pos="-0.197 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mTail3" connected="true" end="-0.142 0.000 0.000" group="Tail" name="mTail3" pivot="-0.168 0.000 0.000" pos="-0.168 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mTail4" connected="true" end="-0.112 0.000 0.000" group="Tail" name="mTail4" pivot="-0.142 0.000 0.000" pos="-0.142 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mTail5" connected="true" end="-0.094 0.000 0.000" group="Tail" name="mTail5" pivot="-0.112 0.000 0.000" pos="-0.112 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mTail6" connected="true" end="-0.089 0.000 0.000" group="Tail" name="mTail6" pivot="-0.094 0.000 0.000" pos="-0.094 0.000 0.000" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mGroin" connected="false" end="0.004 0.000 -0.066" group="Groin" name="mGroin" pivot="0.064 0.000 -0.097" pos="0.064 0.000 -0.097" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended"/>
|
||||||
|
<bone aliases="avatar_mHindLimbsRoot" connected="false" end="-0.204 0.000 0.000" group="Limb" name="mHindLimbsRoot" pivot="-0.200 0.000 0.084" pos="-0.200 0.000 0.084" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHindLimb1Left" connected="false" end="0.002 -0.046 -0.491" group="Limb" name="mHindLimb1Left" pivot="-0.204 0.129 -0.125" pos="-0.204 0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mHindLimb2Left" connected="true" end="-0.030 -0.003 -0.468" group="Limb" name="mHindLimb2Left" pivot="0.002 -0.046 -0.491" pos="0.002 -0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHindLimb3Left" connected="true" end="0.112 0.000 -0.061" group="Limb" name="mHindLimb3Left" pivot="-0.030 -0.003 -0.468" pos="-0.030 -0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHindLimb4Left" connected="true" end="0.105 0.008 0.000" group="Limb" name="mHindLimb4Left" pivot="0.112 0.000 -0.061" pos="0.112 0.000 -0.061" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
<bone aliases="avatar_mHindLimb1Right" connected="false" end="0.002 0.046 -0.491" group="Limb" name="mHindLimb1Right" pivot="-0.204 -0.129 -0.125" pos="-0.204 -0.129 -0.125" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true">
|
||||||
|
<bone aliases="avatar_mHindLimb2Right" connected="true" end="-0.030 0.003 -0.468" group="Limb" name="mHindLimb2Right" pivot="0.002 0.046 -0.491" pos="0.002 0.046 -0.491" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHindLimb3Right" connected="true" end="0.112 0.000 -0.061" group="Limb" name="mHindLimb3Right" pivot="-0.030 0.003 -0.468" pos="-0.030 0.003 -0.468" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended">
|
||||||
|
<bone aliases="avatar_mHindLimb4Right" connected="true" end="0.105 -0.008 0.000" group="Limb" name="mHindLimb4Right" pivot="0.112 0.000 -0.061" pos="0.112 0.000 -0.061" rot="0.000 0.000 0.000" scale="1.00 1.00 1.00" support="extended" reposition="true"/>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</bone>
|
||||||
|
</linden_skeleton>
|
||||||
7107
codegen/inputs/genepool.xml
Normal file
7107
codegen/inputs/genepool.xml
Normal file
File diff suppressed because it is too large
Load Diff
45
codegen/inputs/grass.xml
Normal file
45
codegen/inputs/grass.xml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||||
|
<grass_defs>
|
||||||
|
<grass
|
||||||
|
name="Grass 0"
|
||||||
|
species_id="0"
|
||||||
|
texture_id="6c4727b8-ac79-ba44-3b81-f9aa887b47eb"
|
||||||
|
blade_size_x="1.35"
|
||||||
|
blade_size_y="1.35"
|
||||||
|
/>
|
||||||
|
<grass
|
||||||
|
name="Grass 1"
|
||||||
|
species_id="1"
|
||||||
|
texture_id="79504bf5-c3ec-0763-6563-d843de66d0a1"
|
||||||
|
blade_size_x="1.0"
|
||||||
|
blade_size_y="0.66"
|
||||||
|
/>
|
||||||
|
<grass
|
||||||
|
name="Grass 2"
|
||||||
|
species_id="2"
|
||||||
|
texture_id="6c4727b8-ac79-ba44-3b81-f9aa887b47eb"
|
||||||
|
blade_size_x="1.8"
|
||||||
|
blade_size_y="1.8"
|
||||||
|
/>
|
||||||
|
<grass
|
||||||
|
name="Grass 3"
|
||||||
|
species_id="3"
|
||||||
|
texture_id="99bd60a2-3250-efc9-2e39-2fbcadefbecc"
|
||||||
|
blade_size_x="1.0"
|
||||||
|
blade_size_y="1.0"
|
||||||
|
/>
|
||||||
|
<grass
|
||||||
|
name="Grass 4"
|
||||||
|
species_id="4"
|
||||||
|
texture_id="7a2b3a4a-53c2-53ac-5716-aac7d743c020"
|
||||||
|
blade_size_x="2.25"
|
||||||
|
blade_size_y="2.25"
|
||||||
|
/>
|
||||||
|
<grass
|
||||||
|
name="undergrowth_1"
|
||||||
|
species_id="5"
|
||||||
|
texture_id="8f458549-173b-23ff-d4ff-bfaa5ea2371b"
|
||||||
|
blade_size_x="2.0"
|
||||||
|
blade_size_y="2.0"
|
||||||
|
/>
|
||||||
|
</grass_defs>
|
||||||
9291
codegen/inputs/message_template.msg
Normal file
9291
codegen/inputs/message_template.msg
Normal file
File diff suppressed because it is too large
Load Diff
24
codegen/inputs/trees.xml
Normal file
24
codegen/inputs/trees.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||||
|
<tree_defs>
|
||||||
|
<tree name="Pine 1" species_id="0" texture_id="0187babf-6c0d-5891-ebed-4ecab1426683" droop="60.0" twist="5.0" branches="5.0" depth="1" scale_step="0.7" trunk_depth="6" branch_length="8.0" trunk_length="11.5" leaf_scale="22.0" billboard_scale="39.5" billboard_ratio="1.1" trunk_aspect="0.1" branch_aspect="0.05" leaf_rotate="20.0" noise_mag="0.5" noise_scale="2.5" taper="0.8" repeat_z="3" />
|
||||||
|
<tree name="Oak" species_id="1" texture_id="8a515889-eac9-fb55-8eba-d2dc09eb32c8" droop="35.0" twist="3.0" branches="4.0" depth="3" scale_step="0.7" trunk_depth="0" branch_length="3.0" trunk_length="3.8" leaf_scale="7.0" billboard_scale="10.25" billboard_ratio="1.0" trunk_aspect="0.15" branch_aspect="0.07" leaf_rotate="0.0" noise_mag="1.2" noise_scale="4.0" taper="0.3" repeat_z="4" />
|
||||||
|
<tree name="Tropical Bush 1" species_id="2" texture_id="5bc11cd6-2f40-071e-a8da-0903394204f9" droop="10.0" twist="0.0" branches="6.0" depth="1" scale_step="0.5" trunk_depth="1" branch_length="0.5" trunk_length="0.15" leaf_scale="7.5" billboard_scale="5.0" billboard_ratio="1.25" trunk_aspect="1.0" branch_aspect="0.08" leaf_rotate="0.0" noise_mag="1.0" noise_scale="1.0" taper="0.2" repeat_z="1" />
|
||||||
|
<tree name="Palm 1" species_id="3" texture_id="ca4e8c27-473c-eb1c-2f5d-50ee3f07d85c" droop="0.0" twist="0.0" branches="3.0" depth="1" scale_step="0.5" trunk_depth="0" branch_length="0.7" trunk_length="9.0" leaf_scale="10.0" billboard_scale="13.25" billboard_ratio="1.0" trunk_aspect="0.035" branch_aspect="0.03" leaf_rotate="0.0" noise_mag="0.2" noise_scale="6.0" taper="0.7" repeat_z="10" />
|
||||||
|
<tree name="Dogwood" species_id="4" texture_id="64367bd1-697e-b3e6-0b65-3f862a577366" droop="30.0" twist="0.0" branches="3.0" depth="2" scale_step="0.7" trunk_depth="1" branch_length="2.75" trunk_length="4.0" leaf_scale="5.5" billboard_scale="10.0" billboard_ratio="1.0" trunk_aspect="0.06" branch_aspect="0.05" leaf_rotate="0.0" noise_mag="1.5" noise_scale="2.0" taper="0.8" repeat_z="3" />
|
||||||
|
<tree name="Tropical Bush 2" species_id="5" texture_id="cdd9a9fc-6d0b-f90d-8416-c72b6019bca8" droop="10.0" twist="0.0" branches="3.0" depth="1" scale_step="0.5" trunk_depth="1" branch_length="0.5" trunk_length="0.15" leaf_scale="6.0" billboard_scale="4.5" billboard_ratio="0.9" trunk_aspect="1.0" branch_aspect="0.08" leaf_rotate="0.0" noise_mag="1.0" noise_scale="1.0" taper="0.2" repeat_z="1" />
|
||||||
|
<tree name="Palm 2" species_id="6" texture_id="2d784476-d0db-9979-0cff-9408745a7cf3" droop="0.0" twist="0.0" branches="3.0" depth="1" scale_step="0.5" trunk_depth="0" branch_length="0.7" trunk_length="10.0" leaf_scale="7.5" billboard_scale="13.5" billboard_ratio="1.0" trunk_aspect="0.035" branch_aspect="0.03" leaf_rotate="0.0" noise_mag="0.2" noise_scale="6.0" taper="0.6" repeat_z="12" />
|
||||||
|
<tree name="Cypress 1" species_id="7" texture_id="fb2ae204-3fd1-df33-594f-c9f882830e66" droop="30.0" twist="0.0" branches="3.0" depth="4" scale_step="0.5" trunk_depth="0" branch_length="10.0" trunk_length="10.0" leaf_scale="70.0" billboard_scale="22.5" billboard_ratio="1.0" trunk_aspect="0.05" branch_aspect="0.03" leaf_rotate="0.0" noise_mag="1.2" noise_scale="1.0" taper="0.5" repeat_z="6" />
|
||||||
|
<tree name="Cypress 2" species_id="8" texture_id="30047cec-269d-408e-0c30-b2603b887268" droop="30.0" twist="0.0" branches="3.0" depth="4" scale_step="0.6" trunk_depth="3.0" branch_length="7.5" trunk_length="10.0" leaf_scale="35.0" billboard_scale="25.0" billboard_ratio="0.8" trunk_aspect="0.05" branch_aspect="0.04" leaf_rotate="0.0" noise_mag="1.2" noise_scale="1.0" taper="0.5" repeat_z="5" />
|
||||||
|
<tree name="Pine 2" species_id="9" texture_id="d691a01c-13b7-578d-57c0-5caef0b4e7e1" droop="50.0" twist="7.5" branches="4.0" depth="2" scale_step="0.7" trunk_depth="6.0" branch_length="6.0" trunk_length="10.0" leaf_scale="15.5" billboard_scale="33.0" billboard_ratio="1.35" trunk_aspect="0.1" branch_aspect="0.08" leaf_rotate="5.0" noise_mag="0.5" noise_scale="2.5" taper="0.7" repeat_z="3" />
|
||||||
|
<tree name="Plumeria" species_id="10" texture_id="6de37e4e-7029-61f5-54b8-f5e63f983f58" droop="8.0" twist="7.0" branches="3.0" depth="2" scale_step="0.6" trunk_depth="0" branch_length="3.0" trunk_length="0.1" leaf_scale="20" billboard_scale="10.0" billboard_ratio="1.35" trunk_aspect="0.10" branch_aspect="0.075" leaf_rotate="0.0" noise_mag="0" noise_scale="0" taper="0.85" repeat_z="2" />
|
||||||
|
<tree name="Winter Pine 1" species_id="11" texture_id="10d2a01a-0818-84b9-4b96-c2eb63256519" droop="90.0" twist="2.5" branches="6.0" depth="1" scale_step="0.66" trunk_depth="8" branch_length="0.0" trunk_length="4" leaf_scale="6.75" billboard_scale="12.5" billboard_ratio="0.6" trunk_aspect="0.1" branch_aspect="0.05" leaf_rotate="0.0" noise_mag="0.0" noise_scale="2.5" taper="0.85" repeat_z="2" />
|
||||||
|
<tree name="Winter Aspen" species_id="12" texture_id="7c0cf89b-44b1-1ce2-dd74-07102a98ac2a" droop="85.0" twist="3.0" branches="5" depth="1" scale_step="0.6" trunk_depth="8" branch_length="3.0" trunk_length="4.5" leaf_scale="8" billboard_scale="12" billboard_ratio=".675" trunk_aspect="0.06" branch_aspect="0.05" leaf_rotate="0.0" noise_mag="0.75" noise_scale="2.5" taper="0.8" repeat_z="2" />
|
||||||
|
<tree name="Winter Pine 2" species_id="13" texture_id="67931331-0c02-4876-1255-28770896c6a2" droop="140.0" twist="5.0" branches="6.0" depth="1" scale_step="0.6" trunk_depth="7" branch_length="0.0" trunk_length="3" leaf_scale="5.0" billboard_scale="7.5" billboard_ratio="0.5" trunk_aspect="0.1" branch_aspect="0.05" leaf_rotate="0.0" noise_mag="0.750" noise_scale="2.5" taper="0.5" repeat_z="2" />
|
||||||
|
<tree name="Eucalyptus" species_id="14" texture_id="a6162133-724b-54df-a12f-51cd070ad6f3" droop="20.0" twist="5.0" branches="3.6" depth="4" scale_step="0.6" trunk_depth="0" branch_length="12.0" trunk_length="8.0" leaf_scale="33.0" billboard_scale="24" billboard_ratio="1.3" trunk_aspect="0.15" branch_aspect="0.08" leaf_rotate="0.0" noise_mag="0" noise_scale="0" taper="0.675" repeat_z="3" />
|
||||||
|
<tree name="Fern" species_id="15" texture_id="8872f2b8-31db-42d8-580a-b3e4a91262de" droop="12.0" twist="0.0" branches="7.0" depth="1" scale_step="0.5" trunk_depth="0.1" branch_length="0.01" trunk_length="0.0" leaf_scale="4" billboard_scale="3.5" billboard_ratio="0.85" trunk_aspect="1.0" branch_aspect="0.08" leaf_rotate="0.0" noise_mag="1.0" noise_scale="1.0" taper="0.2" repeat_z="1" />
|
||||||
|
<tree name="Eelgrass" species_id="16" texture_id="96b4de31-f4fa-337d-ec78-451e3609769e" droop="0.0" twist="0.0" branches="5.0" depth="1" scale_step="0.5" trunk_depth="1" branch_length="0.5" trunk_length="0.15" leaf_scale="5.0" billboard_scale="3.0" billboard_ratio="1.0" trunk_aspect="1.0" branch_aspect="0.08" leaf_rotate="0.0" noise_mag="1.0" noise_scale="1.0" taper="0.2" repeat_z="1" />
|
||||||
|
<tree name="Sea Sword" species_id="17" texture_id="5894e2e7-ab8d-edfa-e61c-18cf16854ba3" droop="0.0" twist="0.0" branches="6.0" depth="1" scale_step="0.7" trunk_depth="1" branch_length="0.0" trunk_length="0.0" leaf_scale="2.0" billboard_scale="2.0" billboard_ratio="1.0" trunk_aspect="1.0" branch_aspect="1.0" leaf_rotate="0.0" noise_mag="0.5" noise_scale="0.0" taper="0.0" repeat_z="1" />
|
||||||
|
<tree name="Kelp 1" species_id="18" texture_id="2caf1179-7861-6ff3-4b7d-46e17780bdfa" droop="-15.0" twist="0.0" branches="1.0" depth="1" scale_step="1.0" trunk_depth="3" branch_length="2.5" trunk_length="0.75" leaf_scale="1.85" billboard_scale="4.9" billboard_ratio="1.0" trunk_aspect="0.04" branch_aspect="0.05" leaf_rotate="0.0" noise_mag="1.0" noise_scale="2.0" taper="0.8" repeat_z="2" />
|
||||||
|
<tree name="Beach Grass 1" species_id="19" texture_id="18fb888b-e8f1-dce7-7da7-321d651ea6b0" droop="0.0" twist="0.0" branches="4.0" depth="1" scale_step="0.7" trunk_depth="1" branch_length="0.0" trunk_length="0.0" leaf_scale="4.0" billboard_scale="2.5" billboard_ratio="1.2" trunk_aspect="1.0" branch_aspect="1.0" leaf_rotate="0.0" noise_mag="0.5" noise_scale="0.0" taper="0.0" repeat_z="1" />
|
||||||
|
<tree name="Kelp 2" species_id="20" texture_id="2a4880b6-b7a3-690a-2049-bfbe38eafb9f" droop="-15.0" twist="0.0" branches="1.0" depth="1" scale_step="1.0" trunk_depth="3" branch_length="2.5" trunk_length="1.35" leaf_scale="2.0" billboard_scale="4.9" billboard_ratio="1.0" trunk_aspect="0.025" branch_aspect="0.05" leaf_rotate="0.0" noise_mag="1.0" noise_scale="2.0" taper="0.8" repeat_z="2" />
|
||||||
|
</tree_defs>
|
||||||
23
codegen/sources.json
Normal file
23
codegen/sources.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"schema": 1,
|
||||||
|
"upstream_commit": "2aa70bb68513b39795da5d13c88f31b86e85a3ba",
|
||||||
|
"upstream_repository": "https://github.com/cinderblocks/libremetaverse",
|
||||||
|
"generators": [
|
||||||
|
{"id":"attentions","reference_source":"SourceGenerators/AttentionsGenerator/AttentionsGenerator.cs","sha256":"b2870ae020c42a8a6ec455363fbb70a1b3c94c814b205bad9b61609d5230da3e","license":"BSD-3-Clause","inputs":["attentions","attentions_updated"]},
|
||||||
|
{"id":"genepool","reference_source":"SourceGenerators/GenepoolGenerator/GenepoolGenerator.cs","sha256":"a48e914fc62efbb1bc4b2e17162121621eebd4cf03872cc226bc8a83a9230cd2","license":"BSD-3-Clause","inputs":["genepool"]},
|
||||||
|
{"id":"packets","reference_source":"SourceGenerators/PacketSourceGenerator/PacketSourceGenerator.cs","sha256":"8e63c0356cd0269e10521d15fbcde780cf58f821935601b4f223933930db758f","license":"BSD-3-Clause","inputs":["message_template"]},
|
||||||
|
{"id":"skeleton","reference_source":"SourceGenerators/SkeletonGenerator/SkeletonGenerator.cs","sha256":"6e1a5dd95b2604319cf65037c59b69a739af563e49cfb29e5db00c3d9c371d49","license":"BSD-3-Clause","inputs":["avatar_skeleton"]},
|
||||||
|
{"id":"trees","reference_source":"SourceGenerators/TreesGenerator/TreesGenerator.cs","sha256":"151a593ba215400361f9bf20848537a5c01bb0ab4a95b15c1e16fa4b1897f8bb","license":"BSD-3-Clause","inputs":["trees","grass"]},
|
||||||
|
{"id":"visual_params","reference_source":"SourceGenerators/VisualParamGenerator/VisualParamGenerator.cs","sha256":"bff0ec0f823b415e811f0c84210b3ee8d7baa65cc21de19ed19b3c26560c6dac","license":"BSD-3-Clause","inputs":["avatar_lad"],"note":"The project supplies no visualparamtemplate.cs AdditionalFile; the pinned C# generator uses its embedded template."}
|
||||||
|
],
|
||||||
|
"inputs": [
|
||||||
|
{"id":"message_template","reference_path":"data/message_template.msg","vendored_path":"codegen/inputs/message_template.msg","sha256":"15e524a46a9a449ead33c26d495a292ae2e100e641a408ac66ef63b8a7a2489d","license":"BSD-3-Clause","format":"message-template"},
|
||||||
|
{"id":"avatar_lad","reference_path":"LibreMetaverse/linden/character/avatar_lad.xml","vendored_path":"codegen/inputs/avatar_lad.xml","sha256":"6f97a1408fa8f0ab5c09043da433c701701fe075e8a97867fcbcda207adf9eaf","license":"BSD-3-Clause","format":"xml"},
|
||||||
|
{"id":"avatar_skeleton","reference_path":"LibreMetaverse/linden/character/avatar_skeleton.xml","vendored_path":"codegen/inputs/avatar_skeleton.xml","sha256":"addb3cc4cd582ed4343d778e06daf90c6b77b61b4ecb4a20d4bf202c2b93908a","license":"BSD-3-Clause","format":"xml"},
|
||||||
|
{"id":"attentions","reference_path":"LibreMetaverse/linden/character/attentions.xml","vendored_path":"codegen/inputs/attentions.xml","sha256":"bdbc4ca02dd3bde78b86e796f7eb4ada0000e47be9a127e35d2b77f3010a20af","license":"BSD-3-Clause","format":"xml"},
|
||||||
|
{"id":"attentions_updated","reference_path":"LibreMetaverse/linden/character/attentionsN.xml","vendored_path":"codegen/inputs/attentionsN.xml","sha256":"80055e12a04d05ef5bb16e8c542cd6c218735f8c72f7e48317b8a34282d1ac5b","license":"BSD-3-Clause","format":"xml"},
|
||||||
|
{"id":"genepool","reference_path":"LibreMetaverse/linden/character/genepool.xml","vendored_path":"codegen/inputs/genepool.xml","sha256":"6fa1391cd98fddec0d7fe762343ea21e53a655a8ddd4f33af52f8a02aaa3f56d","license":"BSD-3-Clause","format":"xml"},
|
||||||
|
{"id":"trees","reference_path":"LibreMetaverse/linden/trees.xml","vendored_path":"codegen/inputs/trees.xml","sha256":"f54e626b00bd2c4fec9f59a574a45860f209e4440bbb02b81d27050b9df8ffba","license":"BSD-3-Clause","format":"xml"},
|
||||||
|
{"id":"grass","reference_path":"LibreMetaverse/linden/grass.xml","vendored_path":"codegen/inputs/grass.xml","sha256":"90015f9768afe3cfee761d04239bf9e284b2739b095b7ab8331966fa1fbfcb4e","license":"BSD-3-Clause","format":"xml"}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -146,5 +146,5 @@
|
|||||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeUUID::test",
|
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeUUID::test",
|
||||||
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeUndef::test"
|
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeUndef::test"
|
||||||
],
|
],
|
||||||
"support_passes": 134
|
"support_passes": 137
|
||||||
}
|
}
|
||||||
|
|||||||
17
tools/codegen/Cargo.toml
Normal file
17
tools/codegen/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "libremetaverse-codegen"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
description = "Deterministic native generators for pinned LibreMetaverse data"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
|
sha2 = "0.11"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
365
tools/codegen/src/lib.rs
Normal file
365
tools/codegen/src/lib.rs
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
//! Deterministic framework shared by the `LibreMetaverse` data generators.
|
||||||
|
|
||||||
|
#![allow(clippy::missing_errors_doc)] // The CLI renders the complete error at its boundary.
|
||||||
|
#![allow(clippy::must_use_candidate)] // Generator helpers are also exercised for validation.
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
use std::fmt;
|
||||||
|
use std::fmt::Write as _;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::{Component, Path, PathBuf};
|
||||||
|
|
||||||
|
pub const INVENTORY_PATH: &str = "codegen/sources.json";
|
||||||
|
pub const MANIFEST_OUTPUT: &str = "codegen/generated/source_manifest.rs";
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
||||||
|
pub struct Inventory {
|
||||||
|
pub schema: u32,
|
||||||
|
pub upstream_commit: String,
|
||||||
|
pub upstream_repository: String,
|
||||||
|
pub generators: Vec<GeneratorSpec>,
|
||||||
|
pub inputs: Vec<InputSpec>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
||||||
|
pub struct GeneratorSpec {
|
||||||
|
pub id: String,
|
||||||
|
pub reference_source: String,
|
||||||
|
pub sha256: String,
|
||||||
|
pub license: String,
|
||||||
|
pub inputs: Vec<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub note: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
||||||
|
pub struct InputSpec {
|
||||||
|
pub id: String,
|
||||||
|
pub reference_path: String,
|
||||||
|
pub vendored_path: String,
|
||||||
|
pub sha256: String,
|
||||||
|
pub license: String,
|
||||||
|
pub format: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
|
pub enum Severity {
|
||||||
|
Error,
|
||||||
|
Warning,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
|
pub struct Diagnostic {
|
||||||
|
pub code: &'static str,
|
||||||
|
pub severity: Severity,
|
||||||
|
pub path: String,
|
||||||
|
pub line: usize,
|
||||||
|
pub column: usize,
|
||||||
|
pub message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Diagnostic {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let severity = match self.severity {
|
||||||
|
Severity::Error => "error",
|
||||||
|
Severity::Warning => "warning",
|
||||||
|
};
|
||||||
|
write!(
|
||||||
|
formatter,
|
||||||
|
"{}:{}:{}: {severity}[{}]: {}",
|
||||||
|
self.path, self.line, self.column, self.code, self.message
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn workspace_root() -> PathBuf {
|
||||||
|
Path::new(env!("CARGO_MANIFEST_DIR")).join("../..")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalize_text(path: &str, bytes: &[u8]) -> Result<String, Diagnostic> {
|
||||||
|
let bytes = bytes.strip_prefix(&[0xef, 0xbb, 0xbf]).unwrap_or(bytes);
|
||||||
|
let text = std::str::from_utf8(bytes).map_err(|error| {
|
||||||
|
let valid = &bytes[..error.valid_up_to()];
|
||||||
|
let (line, column) = line_column(valid);
|
||||||
|
Diagnostic {
|
||||||
|
code: "CG001",
|
||||||
|
severity: Severity::Error,
|
||||||
|
path: path.replace('\\', "/"),
|
||||||
|
line,
|
||||||
|
column,
|
||||||
|
message: "input is not valid UTF-8".to_owned(),
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
if let Some(position) = text.as_bytes().iter().position(|byte| *byte == 0) {
|
||||||
|
let prefix = &text.as_bytes()[..position];
|
||||||
|
let (line, column) = line_column(prefix);
|
||||||
|
return Err(Diagnostic {
|
||||||
|
code: "CG002",
|
||||||
|
severity: Severity::Error,
|
||||||
|
path: path.replace('\\', "/"),
|
||||||
|
line,
|
||||||
|
column,
|
||||||
|
message: "input contains a NUL byte".to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(text.replace("\r\n", "\n").replace('\r', "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line_column(bytes: &[u8]) -> (usize, usize) {
|
||||||
|
let mut line = 1;
|
||||||
|
let mut column = 1;
|
||||||
|
for byte in bytes {
|
||||||
|
if *byte == b'\n' {
|
||||||
|
line += 1;
|
||||||
|
column = 1;
|
||||||
|
} else {
|
||||||
|
column += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(line, column)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generated_rust(generator: &str, sources: &[&InputSpec], body: &str) -> Vec<u8> {
|
||||||
|
let mut output = String::new();
|
||||||
|
output.push_str("// @generated by libremetaverse-codegen; DO NOT EDIT.\n");
|
||||||
|
output.push_str("// Regenerate: cargo run -p libremetaverse-codegen -- generate\n");
|
||||||
|
let _ = writeln!(output, "// Generator: {generator}");
|
||||||
|
for source in sources {
|
||||||
|
let _ = writeln!(
|
||||||
|
output,
|
||||||
|
"// Source: {} sha256={} license={}",
|
||||||
|
source.vendored_path, source.sha256, source.license
|
||||||
|
);
|
||||||
|
}
|
||||||
|
output.push('\n');
|
||||||
|
output.push_str(body.trim_end());
|
||||||
|
output.push('\n');
|
||||||
|
output.into_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_inventory(root: &Path) -> Result<Inventory, String> {
|
||||||
|
let path = root.join(INVENTORY_PATH);
|
||||||
|
let bytes = fs::read(&path).map_err(|error| format!("{}: {error}", path.display()))?;
|
||||||
|
let inventory: Inventory =
|
||||||
|
serde_json::from_slice(&bytes).map_err(|error| format!("{}: {error}", path.display()))?;
|
||||||
|
validate_inventory(&inventory)?;
|
||||||
|
Ok(inventory)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_inventory(inventory: &Inventory) -> Result<(), String> {
|
||||||
|
if inventory.schema != 1 || inventory.upstream_commit.len() != 40 {
|
||||||
|
return Err("unsupported or malformed source inventory header".to_owned());
|
||||||
|
}
|
||||||
|
let mut input_ids = BTreeSet::new();
|
||||||
|
for input in &inventory.inputs {
|
||||||
|
validate_relative(&input.reference_path)?;
|
||||||
|
validate_relative(&input.vendored_path)?;
|
||||||
|
validate_hash(&input.sha256)?;
|
||||||
|
if input.license != "BSD-3-Clause" || !input_ids.insert(&input.id) {
|
||||||
|
return Err(format!("invalid or duplicate input {}", input.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut generator_ids = BTreeSet::new();
|
||||||
|
for generator in &inventory.generators {
|
||||||
|
validate_relative(&generator.reference_source)?;
|
||||||
|
validate_hash(&generator.sha256)?;
|
||||||
|
if generator.license != "BSD-3-Clause" || !generator_ids.insert(&generator.id) {
|
||||||
|
return Err(format!("invalid or duplicate generator {}", generator.id));
|
||||||
|
}
|
||||||
|
for input in &generator.inputs {
|
||||||
|
if !input_ids.contains(input) {
|
||||||
|
return Err(format!(
|
||||||
|
"generator {} references unknown input {input}",
|
||||||
|
generator.id
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_relative(value: &str) -> Result<(), String> {
|
||||||
|
let path = Path::new(value);
|
||||||
|
if path.is_absolute()
|
||||||
|
|| path
|
||||||
|
.components()
|
||||||
|
.any(|part| !matches!(part, Component::Normal(_)))
|
||||||
|
{
|
||||||
|
return Err(format!("unsafe inventory path {value}"));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_hash(value: &str) -> Result<(), String> {
|
||||||
|
if value.len() == 64 && value.bytes().all(|byte| byte.is_ascii_hexdigit()) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("invalid SHA-256 {value}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sha256(bytes: &[u8]) -> String {
|
||||||
|
const HEX: &[u8; 16] = b"0123456789abcdef";
|
||||||
|
let mut output = String::with_capacity(64);
|
||||||
|
for byte in Sha256::digest(bytes) {
|
||||||
|
output.push(char::from(HEX[usize::from(byte >> 4)]));
|
||||||
|
output.push(char::from(HEX[usize::from(byte & 0x0f)]));
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_inputs(root: &Path, inventory: &Inventory) -> Result<(), String> {
|
||||||
|
for input in &inventory.inputs {
|
||||||
|
let path = root.join(&input.vendored_path);
|
||||||
|
let bytes = fs::read(&path).map_err(|error| format!("{}: {error}", path.display()))?;
|
||||||
|
let actual = sha256(&bytes);
|
||||||
|
if actual != input.sha256 {
|
||||||
|
return Err(format!(
|
||||||
|
"{}: SHA-256 mismatch: expected {}, found {actual}",
|
||||||
|
path.display(),
|
||||||
|
input.sha256
|
||||||
|
));
|
||||||
|
}
|
||||||
|
normalize_text(&input.vendored_path, &bytes).map_err(|error| error.to_string())?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vendor_inputs(root: &Path, reference: &Path) -> Result<(), String> {
|
||||||
|
let inventory = load_inventory(root)?;
|
||||||
|
for generator in &inventory.generators {
|
||||||
|
let source = reference.join(&generator.reference_source);
|
||||||
|
let bytes = fs::read(&source).map_err(|error| format!("{}: {error}", source.display()))?;
|
||||||
|
let actual = sha256(&bytes);
|
||||||
|
if actual != generator.sha256 {
|
||||||
|
return Err(format!(
|
||||||
|
"{}: pinned generator SHA-256 mismatch: expected {}, found {actual}",
|
||||||
|
source.display(),
|
||||||
|
generator.sha256
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut snapshots = Vec::with_capacity(inventory.inputs.len());
|
||||||
|
for input in &inventory.inputs {
|
||||||
|
let source = reference.join(&input.reference_path);
|
||||||
|
let bytes = fs::read(&source).map_err(|error| format!("{}: {error}", source.display()))?;
|
||||||
|
let actual = sha256(&bytes);
|
||||||
|
if actual != input.sha256 {
|
||||||
|
return Err(format!(
|
||||||
|
"{}: pinned SHA-256 mismatch: expected {}, found {actual}",
|
||||||
|
source.display(),
|
||||||
|
input.sha256
|
||||||
|
));
|
||||||
|
}
|
||||||
|
snapshots.push((root.join(&input.vendored_path), bytes));
|
||||||
|
}
|
||||||
|
for (target, bytes) in snapshots {
|
||||||
|
fs::create_dir_all(target.parent().ok_or("vendored input has no parent")?)
|
||||||
|
.map_err(|error| error.to_string())?;
|
||||||
|
fs::write(&target, bytes).map_err(|error| format!("{}: {error}", target.display()))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source_manifest_bytes(root: &Path) -> Result<Vec<u8>, String> {
|
||||||
|
let inventory = load_inventory(root)?;
|
||||||
|
verify_inputs(root, &inventory)?;
|
||||||
|
let mut inputs: Vec<&InputSpec> = inventory.inputs.iter().collect();
|
||||||
|
inputs.sort_by_key(|input| &input.id);
|
||||||
|
let mut generators: Vec<&GeneratorSpec> = inventory.generators.iter().collect();
|
||||||
|
generators.sort_by_key(|generator| &generator.id);
|
||||||
|
let mut body = String::new();
|
||||||
|
let _ = writeln!(
|
||||||
|
body,
|
||||||
|
"pub const UPSTREAM_COMMIT: &str = {:?};",
|
||||||
|
inventory.upstream_commit
|
||||||
|
);
|
||||||
|
let _ = writeln!(
|
||||||
|
body,
|
||||||
|
"pub const UPSTREAM_REPOSITORY: &str = {:?};",
|
||||||
|
inventory.upstream_repository
|
||||||
|
);
|
||||||
|
body.push_str("pub const SOURCES: &[(&str, &str, &str, &str)] = &[\n");
|
||||||
|
for input in &inputs {
|
||||||
|
let _ = writeln!(
|
||||||
|
body,
|
||||||
|
" ({:?}, {:?}, {:?}, {:?}),",
|
||||||
|
input.id, input.vendored_path, input.sha256, input.license
|
||||||
|
);
|
||||||
|
}
|
||||||
|
body.push_str("];\n");
|
||||||
|
body.push_str("pub const GENERATORS: &[(&str, &str, &str, &str)] = &[\n");
|
||||||
|
for generator in generators {
|
||||||
|
let _ = writeln!(
|
||||||
|
body,
|
||||||
|
" ({:?}, {:?}, {:?}, {:?}),",
|
||||||
|
generator.id, generator.reference_source, generator.sha256, generator.license
|
||||||
|
);
|
||||||
|
}
|
||||||
|
body.push_str("];\n");
|
||||||
|
Ok(generated_rust("source-manifest", &inputs, &body))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn regenerate(root: &Path, check: bool) -> Result<(), String> {
|
||||||
|
let expected = source_manifest_bytes(root)?;
|
||||||
|
let path = root.join(MANIFEST_OUTPUT);
|
||||||
|
if check {
|
||||||
|
let actual = fs::read(&path).map_err(|error| format!("{}: {error}", path.display()))?;
|
||||||
|
if actual != expected {
|
||||||
|
return Err(format!(
|
||||||
|
"{} is stale; run the regeneration command",
|
||||||
|
path.display()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fs::create_dir_all(path.parent().ok_or("generated output has no parent")?)
|
||||||
|
.map_err(|error| error.to_string())?;
|
||||||
|
fs::write(&path, expected).map_err(|error| format!("{}: {error}", path.display()))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn checked_in_inputs_and_manifest_are_current() {
|
||||||
|
let root = workspace_root();
|
||||||
|
let first = source_manifest_bytes(&root).expect("first deterministic generation");
|
||||||
|
let second = source_manifest_bytes(&root).expect("second deterministic generation");
|
||||||
|
assert_eq!(first, second);
|
||||||
|
regenerate(&root, true).expect("checked-in manifest");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn text_normalization_and_diagnostics_are_stable() {
|
||||||
|
assert_eq!(
|
||||||
|
normalize_text("a\\b.xml", b"\xef\xbb\xbfa\r\nb\r").unwrap(),
|
||||||
|
"a\nb\n"
|
||||||
|
);
|
||||||
|
let error = normalize_text("a\\b.xml", b"one\n\0two").unwrap_err();
|
||||||
|
assert_eq!(
|
||||||
|
error.to_string(),
|
||||||
|
"a/b.xml:2:1: error[CG002]: input contains a NUL byte"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inventory_rejects_unsafe_paths_hashes_and_unknown_inputs() {
|
||||||
|
let root = workspace_root();
|
||||||
|
let mut inventory = load_inventory(&root).expect("pinned inventory");
|
||||||
|
inventory.inputs[0].vendored_path = "../escape".to_owned();
|
||||||
|
assert!(validate_inventory(&inventory).is_err());
|
||||||
|
|
||||||
|
let mut inventory = load_inventory(&root).expect("pinned inventory");
|
||||||
|
inventory.generators[0].sha256 = "not-a-hash".to_owned();
|
||||||
|
assert!(validate_inventory(&inventory).is_err());
|
||||||
|
|
||||||
|
let mut inventory = load_inventory(&root).expect("pinned inventory");
|
||||||
|
inventory.generators[0].inputs.push("missing".to_owned());
|
||||||
|
assert!(validate_inventory(&inventory).is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
19
tools/codegen/src/main.rs
Normal file
19
tools/codegen/src/main.rs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
use libremetaverse_codegen::{regenerate, vendor_inputs, workspace_root};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let arguments: Vec<String> = std::env::args().skip(1).collect();
|
||||||
|
let root = workspace_root();
|
||||||
|
let result = match arguments.as_slice() {
|
||||||
|
[command] if command == "generate" => regenerate(&root, false),
|
||||||
|
[command] if command == "check" => regenerate(&root, true),
|
||||||
|
[command, reference] if command == "vendor" => vendor_inputs(&root, Path::new(reference)),
|
||||||
|
_ => Err(
|
||||||
|
"usage: libremetaverse-codegen <generate|check|vendor REFERENCE_CHECKOUT>".to_owned(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
if let Err(error) = result {
|
||||||
|
eprintln!("{error}");
|
||||||
|
std::process::exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user