同步
This commit is contained in:
206
Packages/dev.yarnspinner.unity/.editorconfig
Normal file
206
Packages/dev.yarnspinner.unity/.editorconfig
Normal file
@@ -0,0 +1,206 @@
|
||||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
||||
root = true
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
|
||||
#### Core EditorConfig Options ####
|
||||
|
||||
# Indentation and spacing
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
tab_width = 4
|
||||
|
||||
# New line preferences
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
#### .NET Coding Conventions ####
|
||||
|
||||
# Organize usings
|
||||
dotnet_separate_import_directive_groups = false
|
||||
dotnet_sort_system_directives_first = false
|
||||
|
||||
# this. and Me. preferences
|
||||
dotnet_style_qualification_for_event = false:silent
|
||||
dotnet_style_qualification_for_field = false:silent
|
||||
dotnet_style_qualification_for_method = false:silent
|
||||
dotnet_style_qualification_for_property = false:silent
|
||||
|
||||
# Language keywords vs BCL types preferences
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
|
||||
dotnet_style_predefined_type_for_member_access = true:silent
|
||||
|
||||
# Parentheses preferences
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
|
||||
|
||||
# Modifier preferences
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||
|
||||
# Expression-level preferences
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
|
||||
# Field preferences
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
|
||||
# Parameter preferences
|
||||
dotnet_code_quality_unused_parameters = all:suggestion
|
||||
|
||||
#### C# Coding Conventions ####
|
||||
|
||||
# var preferences
|
||||
csharp_style_var_elsewhere = false:silent
|
||||
csharp_style_var_for_built_in_types = false:silent
|
||||
csharp_style_var_when_type_is_apparent = false:silent
|
||||
|
||||
# Expression-bodied members
|
||||
csharp_style_expression_bodied_accessors = true:silent
|
||||
csharp_style_expression_bodied_constructors = false:silent
|
||||
csharp_style_expression_bodied_indexers = true:silent
|
||||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_operators = false:silent
|
||||
csharp_style_expression_bodied_properties = true:silent
|
||||
|
||||
# Pattern matching preferences
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_prefer_switch_expression = true:suggestion
|
||||
|
||||
# Null-checking preferences
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
|
||||
# Modifier preferences
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
||||
|
||||
# Code-block preferences
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_prefer_simple_using_statement = true:suggestion
|
||||
|
||||
# Expression-level preferences
|
||||
csharp_prefer_simple_default_expression = true:suggestion
|
||||
csharp_style_deconstructed_variable_declaration = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_pattern_local_over_anonymous_function = true:suggestion
|
||||
csharp_style_prefer_index_operator = true:suggestion
|
||||
csharp_style_prefer_range_operator = true:suggestion
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||
|
||||
# 'using' directive preferences
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
|
||||
#### C# Formatting Rules ####
|
||||
|
||||
# New line preferences
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
|
||||
# Indentation preferences
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = true
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_indent_switch_labels = true
|
||||
|
||||
# Space preferences
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
|
||||
# Wrapping preferences
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = false
|
||||
csharp_style_prefer_not_pattern = false
|
||||
dotnet_style_readonly_field = false
|
||||
dotnet_style_object_initializer = false
|
||||
|
||||
# RS2008: Enable analyzer release tracking
|
||||
dotnet_diagnostic.RS2008.severity = none
|
||||
5
Packages/dev.yarnspinner.unity/.github/FUNDING.yml
vendored
Normal file
5
Packages/dev.yarnspinner.unity/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
patreon: secretlab
|
||||
github: YarnSpinnerTool
|
||||
custom: ['https://yarnspinner.itch.io', 'https://assetstore.unity.com/packages/tools/behavior-ai/yarn-spinner-for-unity-the-friendly-dialogue-and-narrative-tool-267061']
|
||||
25
Packages/dev.yarnspinner.unity/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
25
Packages/dev.yarnspinner.unity/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve!
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees:
|
||||
|
||||
---
|
||||
|
||||
**What is the current behavior?**
|
||||
<!-- Please describe what you're seeing. -->
|
||||
|
||||
**Please provide the steps to reproduce, and if possible a minimal demo of the problem**:
|
||||
<!-- Please give us as much detail as you can, so that we can reproduce the issue. If possible, please consider uploading a demo project that demonstrates the problem. -->
|
||||
|
||||
**What is the expected behavior?**
|
||||
<!-- What do you expect to see instead of what's happening now? -->
|
||||
|
||||
**Please tell us about your environment:**
|
||||
|
||||
- Yarn Spinner Version:
|
||||
- Unity Version:
|
||||
|
||||
**Other information**
|
||||
<!-- For example, a detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context... -->
|
||||
20
Packages/dev.yarnspinner.unity/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
Packages/dev.yarnspinner.unity/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for Yarn Spinner!
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||
|
||||
**Describe the solution you'd like**
|
||||
<!-- A clear and concise description of what you want to happen. -->
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
||||
58
Packages/dev.yarnspinner.unity/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
58
Packages/dev.yarnspinner.unity/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
* **Please check if the pull request fulfills these requirements**
|
||||
- [ ] Tests for the changes have been added (for bug fixes / features)
|
||||
- [ ] Does it pass all existing unit tests without modification?
|
||||
- If not, what did you change?
|
||||
- If you altered it significantly, what coverage issue did you fix?
|
||||
- [ ] Docs have been added / updated (for bug fixes / features)
|
||||
- [ ] CHANGELOG.md has been updated to describe this change
|
||||
|
||||
<!-- Please also consider adding yourself to CONTRIBUTORS.md as part of your pull request. We'd like to recognise you for your efforts! -->
|
||||
|
||||
<!-- To update the documentation on yarnspinner.dev, please submit a pull request to the documentation repository at https://github.com/YarnSpinnerTool/Docs. -->
|
||||
|
||||
* **What kind of change does this pull request introduce?**
|
||||
|
||||
- [ ] Bug Fix
|
||||
- [ ] Feature
|
||||
- [ ] Something else
|
||||
|
||||
* **What is the current behavior?**
|
||||
|
||||
<!-- If you are fixing a known bug, you can also link to an open issue here. -->
|
||||
|
||||
* **What is the new behavior (if this is a feature change)?**
|
||||
|
||||
<!-- Please describe, in as much detail as you can, what your pull request changes in Yarn Spinner. -->
|
||||
|
||||
* **Does this pull request introduce a breaking change?**
|
||||
|
||||
<!-- What changes might users need to make in their application due to this PR? -->
|
||||
|
||||
* **Other information**:
|
||||
|
||||
<!--
|
||||
|
||||
Ideas:
|
||||
|
||||
- Performance?
|
||||
- Does this drastically change performance characteristics, or simply allow for optimizations?
|
||||
- Does this performance involve:
|
||||
- Disk access
|
||||
- CPU time
|
||||
- Memory layout optimization (Lx caching etc)
|
||||
- Might there be a use case where you are encouraged to be unperformant by default?
|
||||
- What optimizations did you consider but left out due to time and/or complexity?
|
||||
- Usability?
|
||||
- If your change is to a sample, is it accessible? We don't follow standards like WCAG but any easy wins should be taken.
|
||||
- Does it make it easier to use our API? If not, what annoyance mitigations have you taken/considered?
|
||||
- Who will be affected?
|
||||
- Is this an internal change, or something meant to be consumed by the end user?
|
||||
- If you add API changes, is it easily upgradable from the previous version?
|
||||
- What indirect consequence might be annoying to the end user?
|
||||
- For what reasons would you say this is justified? E.g. super annoying to use in the first place, tightening up undefined behavior etc.
|
||||
- What do you think will be controversial, if any?
|
||||
- How would you describe the cause of the problem and changes to non-technical users if at all possible?
|
||||
|
||||
Feel free to take any all or none of these points as relevant, though we recommend you read through each point. They're just to get you started!
|
||||
|
||||
-->
|
||||
38
Packages/dev.yarnspinner.unity/.github/RELEASE_TEMPLATE.md
vendored
Normal file
38
Packages/dev.yarnspinner.unity/.github/RELEASE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<!-- RELEASE_TEMPLATE.md is not a formally supported file used by GitHub. This file is used by .github/workflows/release.yml to add a release notes preface. -->
|
||||
|
||||
Yarn Spinner is made possible by your generous patronage. Please consider supporting Yarn Spinner's development by [becoming a patron](https://patreon.com/secretlab), or by buying a copy of Yarn Spinner on [itch.io](https://yarnspinner.itch.io/yarn-spinner) or the [Unity Asset Store](https://assetstore.unity.com/packages/tools/behavior-ai/yarn-spinner-for-unity-267061)!
|
||||
|
||||
<a href="https://patreon.com/secretlab"><img width="200" src="https://user-images.githubusercontent.com/901768/71883373-6f40ff80-318a-11ea-9d3a-01f1f58cb39e.png"></a>
|
||||
|
||||
## 👩🚒 Getting Help
|
||||
|
||||
There are several places you can go to get help with Yarn Spinner.
|
||||
|
||||
* Join the [Yarn Spinner Discord](https://discord.gg/yarnspinner).
|
||||
* Talk to us via [BlueSky](http://bsky.app/profile/yarnspinner.dev) or [Mastodon](https://team.yarnspinner.dev/@yarnspinner)
|
||||
* To report a bug, [file an issue on GitHub](https://github.com/YarnSpinnerTool/YarnSpinner-Unity/issues/new?labels=bug+beta&template=bug_report.md&title=).
|
||||
|
||||
## 📦 How To Install Yarn Spinner
|
||||
|
||||
To install the most recent release of Yarn Spinner for Unity, please see the [Installation Instructions](https://docs.yarnspinner.dev/using-yarnspinner-with-unity/installation-and-setup) in the Yarn Spinner documentation.
|
||||
|
||||
If you want to install _this_ particular version of Yarn Spinner for Unity, follow these steps:
|
||||
|
||||
<details>
|
||||
<summary>Installing Yarn Spinner for Unity {RELEASE_TAG} from Git</summary>
|
||||
<p>
|
||||
|
||||
* Open the Window menu, and choose Package Manager.
|
||||
* If you already have any previous version of the Yarn Spinner package installed, remove it.
|
||||
* Click the `+` button, and click *Add package from git URL...*
|
||||
* Enter the following URL:
|
||||
* `https://github.com/YarnSpinnerTool/YarnSpinner-Unity.git#{RELEASE_TAG}`
|
||||
|
||||
Each release will have a different URL. To upgrade to future versions of Yarn Spinner, you will need to uninstall the package, and reinstall using the new URL.
|
||||
</p>
|
||||
</details>
|
||||
|
||||
|
||||
## 📜 Changes
|
||||
|
||||
|
||||
51
Packages/dev.yarnspinner.unity/.github/get-version.sh
vendored
Normal file
51
Packages/dev.yarnspinner.unity/.github/get-version.sh
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Get info about the current commit
|
||||
most_recent_tag=$(git describe --tags --match="v*" --abbrev=0)
|
||||
commits_since_tag=$(git rev-list $most_recent_tag..HEAD | wc -l | awk '{$1=$1};1')
|
||||
sha=$(git log -1 --format=%H)
|
||||
short_sha=$(git log -1 --format=%h)
|
||||
branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
# A regex for extracting data from a version number: major, minor, patch,
|
||||
# [prerelease]
|
||||
REGEX='v(\d+)\.(\d+)\.(\d+)(-.*)?'
|
||||
|
||||
raw_version=${1:-"$most_recent_tag"}
|
||||
|
||||
# Extract the data from the version number
|
||||
major=$(echo $raw_version | perl -pe "s|$REGEX|\1|" )
|
||||
minor=$(echo $raw_version | perl -pe "s|$REGEX|\2|" )
|
||||
patch=$(echo $raw_version | perl -pe "s|$REGEX|\3|" )
|
||||
prerelease=$(echo $raw_version | perl -pe "s|$REGEX|\4|" )
|
||||
|
||||
# Calculate the semver from the version (should be the same as the version, but
|
||||
# just in case)
|
||||
SemVer="$major.$minor.$patch$prerelease"
|
||||
|
||||
# If there are any commits since the current tag and we aren't overriding our
|
||||
# version, add that note
|
||||
if [ "$commits_since_tag" -gt 0 -a -z "$1" ]; then
|
||||
SemVer="$SemVer+$commits_since_tag"
|
||||
fi
|
||||
|
||||
# Create the version strings we'll write into the AssemblyInfo files
|
||||
OutputAssemblyVersion=$(echo "$major.$minor.$patch.$commits_since_tag" | perl -pe "s|\/|\\\/|" )
|
||||
OutputAssemblyInformationalVersion=$(echo "$SemVer.Branch.$branch.Sha.$sha" | perl -pe "s|\/|\\\/|" )
|
||||
OutputAssemblyFileVersion=$(echo "$major.$minor.$patch.$commits_since_tag" | perl -pe "s|\/|\\\/|" )
|
||||
|
||||
# Update the AssemblyInfo.cs files
|
||||
for infoFile in $(find . -name "AssemblyInfo.cs"); do
|
||||
perl -pi -e "s/AssemblyVersion\(\".*\"\)/AssemblyVersion(\"$OutputAssemblyVersion\")/" $infoFile
|
||||
perl -pi -e "s/AssemblyInformationalVersion\(\".*\"\)/AssemblyInformationalVersion(\"$OutputAssemblyInformationalVersion\")/" $infoFile
|
||||
perl -pi -e "s/AssemblyFileVersion\(\".*\"\)/AssemblyFileVersion(\"$OutputAssemblyFileVersion\")/" $infoFile
|
||||
done
|
||||
|
||||
# If we're running in GitHub Workflows, output our calculated SemVer
|
||||
if [[ -n $GITHUB_OUTPUT ]]; then
|
||||
echo "SemVer=$SemVer" >> "$GITHUB_OUTPUT"
|
||||
echo "ShortSha=$short_sha" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
# Log our SemVer
|
||||
echo $SemVer
|
||||
13
Packages/dev.yarnspinner.unity/.github/update-package-version.sh
vendored
Normal file
13
Packages/dev.yarnspinner.unity/.github/update-package-version.sh
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#/bin/bash
|
||||
|
||||
if [ ! -d ".git" ]; then
|
||||
echo "This script must be run in the root of the repository."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION=$(.github/get-version.sh $@)
|
||||
|
||||
jq ".version=\"$VERSION\"" package.json > package.json.tmp
|
||||
mv package.json.tmp package.json
|
||||
|
||||
echo "Updated package version to $VERSION"
|
||||
102
Packages/dev.yarnspinner.unity/.github/workflows/broad_version_test.yml
vendored
Normal file
102
Packages/dev.yarnspinner.unity/.github/workflows/broad_version_test.yml
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
name: Run Tests on Broad Version Range 🌶
|
||||
|
||||
env:
|
||||
ACTIONS_RUNNER_DEBUG: true
|
||||
ACTIONS_STEP_DEBUG: true
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
buildAndTestForSomePlatforms:
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: true # Cancel other jobs if another one arrives
|
||||
name: Test on ${{ matrix.unityVersion }} for ${{ matrix.targetPlatform }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1 # Only run one at a time, to prevent license contention
|
||||
matrix:
|
||||
projectPath:
|
||||
- YarnSpinner
|
||||
unityVersion:
|
||||
- 2021.3.0f1
|
||||
- 2021.3.32f1
|
||||
- 2022.1.0f1
|
||||
- 2022.1.24f1
|
||||
- 2022.2.0f1
|
||||
- 2022.2.21f1
|
||||
- 2022.3.0f1
|
||||
- 2022.3.13f1
|
||||
- 2023.1.0f1
|
||||
- 2023.1.20f1
|
||||
targetPlatform:
|
||||
# - StandaloneOSX # Build a macOS standalone (Intel 64-bit).
|
||||
- StandaloneWindows64 # Build a Windows 64-bit standalone.
|
||||
# - StandaloneLinux64 # Build a Linux 64-bit standalone.
|
||||
# - iOS # Build an iOS player.
|
||||
# - Android # Build an Android player.
|
||||
# - WebGL # WebGL.
|
||||
steps:
|
||||
- name: Create empty Unity project
|
||||
run: |
|
||||
mkdir -p ${{ matrix.projectPath }}/Assets
|
||||
mkdir -p ${{ matrix.projectPath }}/ProjectSettings
|
||||
mkdir -p ${{ matrix.projectPath }}/Packages
|
||||
|
||||
# Add the Unity Input System package, and configure the new project to use
|
||||
# both the Input System and the legacy Input Manager.
|
||||
- name: Add Input System package
|
||||
run: |
|
||||
cat <<EOF > ${{ matrix.projectPath }}/ProjectSettings/ProjectSettings.asset
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!129 &1
|
||||
PlayerSettings:
|
||||
activeInputHandler: 2
|
||||
EOF
|
||||
|
||||
cat <<EOF > ${{ matrix.projectPath }}/Packages/manifest.json
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.inputsystem": "1.0.2"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: Check out to Packages/YarnSpinner
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
path: ${{ matrix.projectPath }}/Packages/YarnSpinner
|
||||
|
||||
- name: Fetch from Cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ matrix.projectPath }}/Library
|
||||
key: Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}-${{ matrix.unityVersion }}-${{ hashFiles(matrix.projectPath) }}
|
||||
restore-keys: |
|
||||
Library-${{ matrix.projectPath }}-${{ matrix.targetPlatform }}-${{ matrix.unityVersion }}-
|
||||
|
||||
- name: Run tests
|
||||
uses: game-ci/unity-test-runner@v4
|
||||
id: testRunner
|
||||
env:
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
unityVersion: ${{ matrix.unityVersion }}
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
checkName: 'Test Results ${{ matrix.unityVersion }}-${{ matrix.targetPlatform }}'
|
||||
# customParameters: -quit
|
||||
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: Test results (edit + play, ${{ matrix.unityVersion }}-${{ matrix.targetPlatform }}
|
||||
# path: ${{ steps.testRunner.outputs.artifactsPath }}
|
||||
path: artifacts
|
||||
37
Packages/dev.yarnspinner.unity/.github/workflows/release.yml
vendored
Normal file
37
Packages/dev.yarnspinner.unity/.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Create Release 📦
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*.*.*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Extract release notes
|
||||
id: extract-release-notes
|
||||
uses: ffurrer2/extract-release-notes@v1
|
||||
- name: Read release notes preface
|
||||
id: release_preface
|
||||
uses: bluwy/substitute-string-action@v1
|
||||
with:
|
||||
_input-file: .github/RELEASE_TEMPLATE.md
|
||||
_format-key: '{key}'
|
||||
RELEASE_TAG: ${{ github.ref_name }}
|
||||
- name: Create release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: ${{ github.ref }}
|
||||
draft: true
|
||||
prerelease: true
|
||||
body: |
|
||||
${{ steps.release_preface.outputs.result }}
|
||||
${{ steps.extract-release-notes.outputs.release_notes }}
|
||||
|
||||
157
Packages/dev.yarnspinner.unity/.github/workflows/test.yml
vendored
Normal file
157
Packages/dev.yarnspinner.unity/.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
name: Run Tests 🧪
|
||||
|
||||
env:
|
||||
ACTIONS_RUNNER_DEBUG: true
|
||||
ACTIONS_STEP_DEBUG: true
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "feature/**"
|
||||
- "release/**"
|
||||
paths:
|
||||
- "Editor/**"
|
||||
- "Runtime/**"
|
||||
- "Samples~/**"
|
||||
- "Tests/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
buildAndTestForSomePlatforms:
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ matrix.unityVersion }}-${{ matrix.unityLocalisation }}-${{ matrix.uniTask }}
|
||||
cancel-in-progress: true # Cancel other jobs if another one arrives
|
||||
name: ${{ matrix.unityVersion }} (${{ matrix.targetPlatform }}, ${{ matrix.unityLocalisation && 'with unity loc' || 'no unity loc' }}, ${{ matrix.uniTask && 'with unitask' || 'no unitask' }})
|
||||
runs-on: [self-hosted, linux]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
# max-parallel: 1 # Only run one at a time, to prevent license contention
|
||||
matrix:
|
||||
projectPath:
|
||||
- YarnSpinner
|
||||
unityVersion:
|
||||
- 2022.3.45f1
|
||||
- 2023.2.12f1
|
||||
- 6000.0.54f1
|
||||
- 6000.1.10f1
|
||||
unityLocalisation:
|
||||
- true
|
||||
- false
|
||||
uniTask:
|
||||
- true
|
||||
- false
|
||||
targetPlatform:
|
||||
# - StandaloneOSX # Build a macOS standalone (Intel 64-bit).
|
||||
# - StandaloneWindows64 # Build a Windows 64-bit standalone.
|
||||
- StandaloneLinux64 # Build a Linux 64-bit standalone.
|
||||
# - iOS # Build an iOS player.
|
||||
# - Android # Build an Android player.
|
||||
# - WebGL # WebGL.
|
||||
steps:
|
||||
- name: Create empty Unity project
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p ${{ matrix.projectPath }}/Assets
|
||||
mkdir -p ${{ matrix.projectPath }}/ProjectSettings
|
||||
mkdir -p ${{ matrix.projectPath }}/Packages
|
||||
mkdir -p output
|
||||
|
||||
# Add the Unity Input System package, and configure the new project to use
|
||||
# both the Input System and the legacy Input Manager.
|
||||
- name: Add Input System package
|
||||
shell: bash
|
||||
run: |
|
||||
cat <<EOF > ${{ matrix.projectPath }}/ProjectSettings/ProjectSettings.asset
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!129 &1
|
||||
PlayerSettings:
|
||||
activeInputHandler: 2
|
||||
EOF
|
||||
|
||||
cat <<EOF > ${{ matrix.projectPath }}/Packages/manifest.json
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.inputsystem": "1.11.2"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Select correct TMP Essentials package
|
||||
if [[ ${{matrix.unityVersion}} == "2022"* ]]; then
|
||||
TMP_VERSION="ugui-1.0.0"
|
||||
else
|
||||
TMP_VERSION="ugui-2.0.0"
|
||||
fi
|
||||
echo "Installing TMP Essentials for $TMP_VERSION"
|
||||
|
||||
# Add the correct version of the TMP Essentials package to package manifest
|
||||
MANIFEST_PATH=${{ matrix.projectPath }}/Packages/manifest.json
|
||||
jq ".dependencies += {\"dev.yarnspinner.tmp-essentials\": \"https://github.com/desplesda/dev.yarnspinner.tmp-essentials.git#$TMP_VERSION\"}" "$MANIFEST_PATH" > manifest.json
|
||||
mv manifest.json "$MANIFEST_PATH"
|
||||
|
||||
- name: Add Unity Localisation
|
||||
if: ${{ matrix.unityLocalisation }}
|
||||
run: |
|
||||
# Add Unity Localisation package to package manifest
|
||||
MANIFEST_PATH=${{ matrix.projectPath }}/Packages/manifest.json
|
||||
jq '.dependencies += {"com.unity.localization": "1.3.2"}' "$MANIFEST_PATH" > manifest.json
|
||||
mv manifest.json "$MANIFEST_PATH"
|
||||
|
||||
- name: Add UniTask Package
|
||||
if: ${{ matrix.uniTask }}
|
||||
run: |
|
||||
# Add UniTask package to package manifest
|
||||
MANIFEST_PATH=${{ matrix.projectPath }}/Packages/manifest.json
|
||||
jq '.dependencies += {"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask"}' "$MANIFEST_PATH" > manifest.json
|
||||
mv manifest.json "$MANIFEST_PATH"
|
||||
|
||||
- name: Check out to Packages/YarnSpinner
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
path: ${{ matrix.projectPath }}/Packages/dev.yarnspinner.unity
|
||||
|
||||
- name: Run edit mode tests
|
||||
run: |
|
||||
docker run \
|
||||
--rm \
|
||||
-v ./${{ matrix.projectPath }}:/project \
|
||||
-v ./output:/output \
|
||||
-e TEST_MODE=EditMode \
|
||||
--hostname YS-Linux-Build \
|
||||
yarnspinner/unity-${{ matrix.unityVersion }}
|
||||
|
||||
- name: Run play mode tests
|
||||
if: always()
|
||||
run: |
|
||||
docker run \
|
||||
--rm \
|
||||
-v ./${{ matrix.projectPath }}:/project \
|
||||
-v ./output:/output \
|
||||
-e TEST_MODE=PlayMode \
|
||||
--hostname YS-Linux-Build \
|
||||
yarnspinner/unity-${{ matrix.unityVersion }}
|
||||
|
||||
- name: Generate HTML test report (Play Mode)
|
||||
uses: rjtngit/nunit-html-action@v1
|
||||
if: always()
|
||||
with:
|
||||
inputXmlPath: output/TestResults-PlayMode.xml
|
||||
outputHtmlPath: output/TestResults-PlayMode.html
|
||||
|
||||
- name: Generate HTML test report (Edit Mode)
|
||||
uses: rjtngit/nunit-html-action@v1
|
||||
if: always()
|
||||
with:
|
||||
inputXmlPath: output/TestResults-EditMode.xml
|
||||
outputHtmlPath: output/TestResults-EditMode.html
|
||||
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: Test results (edit + play, ${{ matrix.unityVersion }} ${{ matrix.targetPlatform }} ${{ matrix.unityLocalisation && 'with-unity-loc' || 'no-unity-loc' }} ${{ matrix.uniTask && 'with-unitask' || 'no-unitask' }})
|
||||
# path: ${{ steps.testRunner.outputs.artifactsPath }}
|
||||
path: ./output
|
||||
98
Packages/dev.yarnspinner.unity/.github/workflows/update_dlls.yml
vendored
Normal file
98
Packages/dev.yarnspinner.unity/.github/workflows/update_dlls.yml
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
name: Update DLLs 📚
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
update_dlls:
|
||||
name: Update Yarn Spinner DLLs
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# We need to be able to:
|
||||
# 1. create a branch in a repo ('contents'), and
|
||||
# 2. create a pull request using that branch ('pull-requests')
|
||||
pull-requests: write
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout Yarn Spinner for Unity
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: YarnSpinner-Unity
|
||||
- name: Checkout Yarn Spinner
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: YarnSpinnerTool/YarnSpinner
|
||||
path: YarnSpinner
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
9.0.x
|
||||
|
||||
- name: Fetch all commits
|
||||
run: git fetch --unshallow
|
||||
working-directory: ./YarnSpinner
|
||||
|
||||
- name: Install dotnet-assembly-alias
|
||||
run: dotnet tool install -g Alias
|
||||
|
||||
# Update the assembly info for this build of YS, so that the About window is
|
||||
# appropriate
|
||||
- name: Execute GitVersion
|
||||
id: version # step id used as reference for output values
|
||||
run: ./get-version.sh
|
||||
working-directory: ./YarnSpinner
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
working-directory: ./YarnSpinner
|
||||
|
||||
- name: Build
|
||||
run: dotnet build --no-restore --configuration Release
|
||||
working-directory: ./YarnSpinner
|
||||
|
||||
# Don't proceed unless we're including a build of Yarn Spinner that passes
|
||||
# its tests.
|
||||
- name: Test
|
||||
run: dotnet test --no-build --configuration Release --verbosity normal
|
||||
working-directory: ./YarnSpinner
|
||||
|
||||
# We need to copy dependency DLLs into the project, but if a Unity project
|
||||
# contains multiple DLLs with the same name (even from a package), that's an
|
||||
# error. This causes problems for users who want to use, for example,
|
||||
# Google.Protobuf (especially if they want to use a different version).
|
||||
#
|
||||
# Our solution partly involves renaming the dependency DLLs to have the
|
||||
# prefix 'Yarn.', and updating all references to these renamed DLLs, using
|
||||
# dotnet-assembly-alias
|
||||
# (https://github.com/getsentry/dotnet-assembly-alias/). For more
|
||||
# information on this fix, see
|
||||
# https://github.com/YarnSpinnerTool/YarnSpinner-Unity/issues/15#issuecomment-1036162152.
|
||||
- name: Rename vendored DLLs
|
||||
run: |
|
||||
assemblyalias --target-directory "YarnSpinner/YarnSpinner.Compiler/bin/Release/netstandard2.0/" --prefix "Yarn." --assemblies-to-alias "Antlr*;Csv*;Google*;"
|
||||
assemblyalias --target-directory "YarnSpinner/YarnSpinner.Compiler/bin/Release/netstandard2.0/" --internalize --prefix "Yarn." --assemblies-to-alias "System*;Microsoft.Bcl*;Microsoft.Extensions*"
|
||||
|
||||
# Copy all of the dependency DLLs into the YarnSpinner-Unity repo, except
|
||||
# for Microsoft.CSharp.dll (which is provided by Unity, so including it
|
||||
# would cause an error.)
|
||||
- name: Copy DLLs
|
||||
run: |
|
||||
cp -v YarnSpinner/YarnSpinner.Compiler/bin/Release/netstandard2.0/*.dll YarnSpinner-Unity/Runtime/DLLs
|
||||
cp -v YarnSpinner/YarnSpinner.Compiler/bin/Release/netstandard2.0/*.pdb YarnSpinner-Unity/Runtime/DLLs
|
||||
cp -v YarnSpinner/YarnSpinner.Compiler/bin/Release/netstandard2.0/*.xml YarnSpinner-Unity/Runtime/DLLs
|
||||
rm -fv YarnSpinner-Unity/Runtime/DLLs/Microsoft.CSharp.dll
|
||||
|
||||
# Make the PR against YarnSpinner-Unity that merges this change
|
||||
- name: Create pull request
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
path: ./YarnSpinner-Unity
|
||||
commit-message: Update Yarn Spinner DLLs to YarnSpinnerTool/YarnSpinner@${{ steps.version.outputs.ShortSha }}
|
||||
branch: update-dlls-${{ steps.version.outputs.ShortSha }}
|
||||
title: Update Yarn Spinner DLLs to latest (${{ steps.version.outputs.ShortSha }})
|
||||
body: |
|
||||
This is an automated PR made by @${{ github.actor }} that updates the precompiled Yarn Spinner DLLs (and their dependencies) to YarnSpinnerTool/YarnSpinner@${{ steps.version.outputs.ShortSha }} (v${{ steps.version.outputs.SemVer }}).
|
||||
21
Packages/dev.yarnspinner.unity/.pkgignore
Normal file
21
Packages/dev.yarnspinner.unity/.pkgignore
Normal file
@@ -0,0 +1,21 @@
|
||||
# Ignore the Samples symlink, which links to Samples~. This symlink exists
|
||||
# so that the distributed package ships its samples in a folder called
|
||||
# Samples~ (which Unity will ignore, and users can import into their projects
|
||||
# when they want to), while the sameples are visible in the package when
|
||||
# developing.
|
||||
Samples
|
||||
Samples.meta
|
||||
|
||||
# Ignore markdown files when packaging for asset stores - they'll be converted
|
||||
# into PDFs or other more readable formats.
|
||||
*.md
|
||||
*.md.meta
|
||||
|
||||
# Ignore test files, which don't need to be shipped (they're not needed by
|
||||
# end-users)
|
||||
Tests
|
||||
Tests.meta
|
||||
|
||||
# Ignore the file that defines which way we install the samples - the
|
||||
# appropriate setting will be manually copied in.
|
||||
YarnPackageImporter.SamplesInstallApproach.cs
|
||||
1258
Packages/dev.yarnspinner.unity/CHANGELOG.md
Normal file
1258
Packages/dev.yarnspinner.unity/CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
7
Packages/dev.yarnspinner.unity/CHANGELOG.md.meta
Normal file
7
Packages/dev.yarnspinner.unity/CHANGELOG.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db3ac383f37b340b593e3cd5d16b4cf5
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
76
Packages/dev.yarnspinner.unity/CODE_OF_CONDUCT.md
Normal file
76
Packages/dev.yarnspinner.unity/CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at yarnspinner@secretlab.com.au. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
7
Packages/dev.yarnspinner.unity/CODE_OF_CONDUCT.md.meta
Normal file
7
Packages/dev.yarnspinner.unity/CODE_OF_CONDUCT.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5cfcecef19b8f44c8a2e435d277c5a04
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
43
Packages/dev.yarnspinner.unity/CONTRIBUTING.md
Normal file
43
Packages/dev.yarnspinner.unity/CONTRIBUTING.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Contributing to Yarn Spinner
|
||||
|
||||
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
|
||||
|
||||
## How to send in your contributions
|
||||
|
||||
There are many ways you can send your contributions to Yarn Spinner. You can either **report a bug**, or you can make the changes yourself and **submit a pull request**!
|
||||
|
||||
### Reporting bugs and opening issues
|
||||
|
||||
Please [report bugs](https://github.com/YarnSpinnerTool/YarnSpinner-Unity/issues) and open issues generously. Don't be afraid that your idea is silly, or you're reporting a duplicate. We're happy to hear from you. Seriously.
|
||||
|
||||
> ***Please Note:*** Yarn Spinner is written by volunteers. If you encounter a problem while using it, we'll do our best to help you, but neither the authors, or Secret Lab Pty. Ltd. can offer any support.
|
||||
|
||||
### Submitting a pull request
|
||||
|
||||
* [Fork](https://github.com/YarnSpinnerTool/YarnSpinner-Unity/fork) and clone the repository
|
||||
* Create a new branch: git checkout -b my-branch-name
|
||||
* Make your changes
|
||||
* Push to your fork and [submit a pull request](https://github.com/YarnSpinnerTool/YarnSpinner-Unity/compare)
|
||||
* Pat your self on the back and wait for your pull request to be reviewed.
|
||||
|
||||
If you're unfamiliar with how pull requests work, [GitHub's documentation on them](https://help.github.com/articles/using-pull-requests/) is very good.
|
||||
|
||||
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
|
||||
|
||||
* Update the documentation as necessary, as well as making code changes.
|
||||
* Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
|
||||
* [Write a good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
||||
|
||||
### Unity & LTS support
|
||||
|
||||
As we are a group of volunteers, we can only officially support the versions of Unity that are actively supported by Unity themselves. Please check the official [LTS FAQ](https://support.unity.com/hc/en-us/articles/4403332003348-What-is-a-Unity-LTS-Long-Term-Support-version-and-what-can-I-expect-from-it-) for more up-to-date information. Currently, the minimum supported version is **2019.4**.
|
||||
|
||||
However, if you would like to submit contributions to fix support for unsupported versions, please go ahead and do so, but do note that we cannot guarantee that it continues to work for that version.
|
||||
|
||||
### Branches
|
||||
|
||||
All of Yarn Spinner's in-progress work happens on the `main` branch. When we make releases, we create a new tag from `main`. Larger features are developed on their own branch, and then merged to `main` when ready.
|
||||
|
||||
### Code and other contributions
|
||||
|
||||
Contributions to Yarn Spinner (via pull request or otherwise) must be licensed under the MIT license.
|
||||
7
Packages/dev.yarnspinner.unity/CONTRIBUTING.md.meta
Normal file
7
Packages/dev.yarnspinner.unity/CONTRIBUTING.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e079b710417049b2915eacde0b91e1b
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
21
Packages/dev.yarnspinner.unity/CONTRIBUTORS.md
Normal file
21
Packages/dev.yarnspinner.unity/CONTRIBUTORS.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Contributors
|
||||
|
||||
The following people have contributed to the development of Yarn Spinner. If you submit a pull request, please add your name to the list below.
|
||||
|
||||
* 2015-ongoing: Secret Lab Team - Dr Jon Manning and Dr Paris Buttfield-Addison <lab@secretlab.com.au>
|
||||
* 2017: Rev Peter Lawler <relwalretep@gmail.com>
|
||||
* 2017: Dr Tim 'McJones' Nugent <tim@lonely.coffee>
|
||||
* 2018: Damon 'demanrisu' Reece <de@coy.ninja>
|
||||
* 2019: Tamme Schichler <tamme@schichler.dev>
|
||||
* 2020: @Schroedingers-Cat, Robert Yang (https://debacle.us)
|
||||
* 2021: Jonathan MacAlpine <apocriva@gmail.com>
|
||||
* 2021: Shane Marks (https://necrosoftgames.com)
|
||||
* 2021: @andiCR, Andrés Cartín (andres@treeinteractivecr.com)
|
||||
* 2021: Shane Duan <github@xsduan.com>
|
||||
* 2022: Bernardo Vecchia Stein <jkhulw@sidhion.com>
|
||||
* 2023: ChocolaMint (https://chocola-mint.github.io/)
|
||||
* 2023: Mitch Zais <https://github.com/Invertex>
|
||||
* 2023: Thomas Ingram (https://vertx.xyz)
|
||||
* 2023: Isaac Berman (https://github.com/bermanisaac)
|
||||
* 20??: Mars Buttfield-Addison (https://github.com/TheMartianLife)
|
||||
* 2025: Jay Xavier Peet (https://github.com/JayPeet)
|
||||
7
Packages/dev.yarnspinner.unity/CONTRIBUTORS.md.meta
Normal file
7
Packages/dev.yarnspinner.unity/CONTRIBUTORS.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9db75e8c06dd1484bb6f0c05ecc00b7f
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/dev.yarnspinner.unity/Editor.meta
Normal file
8
Packages/dev.yarnspinner.unity/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3b025f9df1834d5e91c6873ece463b1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/dev.yarnspinner.unity/Editor/Analysis.meta
Normal file
8
Packages/dev.yarnspinner.unity/Editor/Analysis.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 991bb6a4238c84092a59ac23d54fda95
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1025
Packages/dev.yarnspinner.unity/Editor/Analysis/Action.cs
Normal file
1025
Packages/dev.yarnspinner.unity/Editor/Analysis/Action.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad1e0218baeab43be922ae40dbfb3ade
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
public static class ActionSourceCodeGenerator
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Get a path in the current project that can be used for storing
|
||||
/// manually-generated Yarn Action registration code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property checks to see if a file exists in the Assets folder
|
||||
/// that is both named "YarnActionRegistration.cs", and contains a
|
||||
/// marker indicating that it was generated by Yarn Spinner's code
|
||||
/// generation systems. If this is found, the path to the file is
|
||||
/// returned. Otherwise, the path
|
||||
/// <c>Assets/YarnActionRegistration.cs</c> is returned.
|
||||
/// </remarks>
|
||||
public static string GeneratedSourcePath
|
||||
{
|
||||
get
|
||||
{
|
||||
const string YarnRegistrationFileName = "YarnActionRegistration.cs";
|
||||
const string DefaultOutputFilePath = "Assets/" + YarnRegistrationFileName;
|
||||
|
||||
// Note the lack of a closing parenthesis in this string - we
|
||||
// only want to check to see if it was generated by
|
||||
// "YarnActionAnalyzer", not any specific version of that
|
||||
// analyzer
|
||||
const string YarnGeneratedCodeSignature = "GeneratedCode(\"YarnActionAnalyzer\"";
|
||||
|
||||
var existingFile = System.IO.Directory.EnumerateFiles(System.Environment.CurrentDirectory, YarnRegistrationFileName, System.IO.SearchOption.AllDirectories).FirstOrDefault();
|
||||
|
||||
if (existingFile == null)
|
||||
{
|
||||
return DefaultOutputFilePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = System.IO.File.ReadAllText(existingFile);
|
||||
return text.Contains(YarnGeneratedCodeSignature)
|
||||
? existingFile
|
||||
: DefaultOutputFilePath;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
// Something happened while checking the file. Return
|
||||
// our default, and log that we encountered a problem.
|
||||
Debug.LogWarning($"Can't check to see if {existingFile} is a valid action registration script, using {DefaultOutputFilePath} instead: {e}");
|
||||
return DefaultOutputFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates and imports a C# source code file in the project
|
||||
/// containing Yarn Action registration code at the path indicated by
|
||||
/// <see cref="GeneratedSourcePath"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method should not be called in projects where Unity has support
|
||||
/// for source generators (i.e. Unity 2021.2 and later).
|
||||
/// </remarks>
|
||||
public static void GenerateYarnActionSourceCode()
|
||||
{
|
||||
var analysis = new Yarn.Unity.ActionAnalyser.Analyser("Assets");
|
||||
try
|
||||
{
|
||||
var actions = analysis.GetActions();
|
||||
var source = Yarn.Unity.ActionAnalyser.Analyser.GenerateRegistrationFileSource(actions);
|
||||
|
||||
var path = GeneratedSourcePath;
|
||||
|
||||
System.IO.File.WriteAllText(path, source);
|
||||
UnityEditor.AssetDatabase.ImportAsset(path);
|
||||
|
||||
Debug.Log($"Generated Yarn command and function registration code at {path}");
|
||||
}
|
||||
catch (Yarn.Unity.ActionAnalyser.AnalyserException e)
|
||||
{
|
||||
Debug.LogError($"Error generating source code: " + e.InnerException.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dabf0558de47a486199baa9e568783ce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,625 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Yarn.Unity.ActionAnalyser;
|
||||
using YarnAction = Yarn.Unity.ActionAnalyser.Action;
|
||||
|
||||
#nullable enable
|
||||
|
||||
[Generator]
|
||||
public class ActionRegistrationSourceGenerator : ISourceGenerator
|
||||
{
|
||||
const string YarnSpinnerUnityAssemblyName = "YarnSpinner.Unity";
|
||||
const string DebugLoggingPreprocessorSymbol = "YARN_SOURCE_GENERATION_DEBUG_LOGGING";
|
||||
const string IncludeTestCommands = "YARN_INCLUDE_TEST_COMMANDS";
|
||||
const string MinimumUnityVersionPreprocessorSymbol = "UNITY_2021_2_OR_NEWER";
|
||||
|
||||
public static string? GetProjectRoot(GeneratorExecutionContext context)
|
||||
{
|
||||
// We need to know if the settings are configured to not perform codegen
|
||||
// to link attributed methods. This is kinda annoying because the path
|
||||
// root of the project settings and the root path of this process are
|
||||
// *very* different. So, what we do is we use the included Compilation
|
||||
// Assembly additional file that Unity gives us. This file, if opened,
|
||||
// has the path of the Unity project, which we can then use to get the
|
||||
// settings. If any stage of this fails, then we bail out and assume
|
||||
// that codegen is desired.
|
||||
|
||||
// Try and find any additional files passed to the context
|
||||
if (!context.AdditionalFiles.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// One of those files is (AssemblyName).[Unity]AdditionalFile.txt, and it
|
||||
// contains the path to the project
|
||||
var relevantFiles = context.AdditionalFiles.Where(
|
||||
i => i.Path.Contains($"{context.Compilation.AssemblyName}.AdditionalFile.txt")
|
||||
|| i.Path.Contains($"{context.Compilation.AssemblyName}.UnityAdditionalFile.txt")
|
||||
);
|
||||
|
||||
if (!relevantFiles.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var assemblyRelevantFile = relevantFiles.First();
|
||||
|
||||
// The file needs to exist on disk
|
||||
if (!File.Exists(assemblyRelevantFile.Path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Attempt to read it - it should contain the path to the project directory
|
||||
var projectPath = File.ReadAllText(assemblyRelevantFile.Path);
|
||||
if (Directory.Exists(projectPath))
|
||||
{
|
||||
// If this directory exists, we're done
|
||||
return projectPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// We encountered a problem while testing
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
using var output = GetOutput(context);
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
|
||||
output.WriteLine(DateTime.Now);
|
||||
|
||||
Yarn.Unity.Editor.YarnSpinnerProjectSettings? settings = null;
|
||||
var projectPath = GetProjectRoot(context);
|
||||
|
||||
if (projectPath != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var fullPath = Path.Combine(projectPath, Yarn.Unity.Editor.YarnSpinnerProjectSettings.YarnSpinnerProjectSettingsPath);
|
||||
output.WriteLine($"Attempting to read settings file at {fullPath}");
|
||||
|
||||
settings = Yarn.Unity.Editor.YarnSpinnerProjectSettings.GetOrCreateSettings(projectPath, output);
|
||||
if (!settings.automaticallyLinkAttributedYarnCommandsAndFunctions)
|
||||
{
|
||||
output.WriteLine("Skipping codegen due to settings.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
output.WriteLine($"Unable to determine Yarn settings, settings values will be ignored and codegen will occur: {e.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
output.WriteLine($"Unable to determine project location on disk. Settings values will be ignored and codegen will occur");
|
||||
}
|
||||
|
||||
bool hasCriticalActionErrors = false;
|
||||
try
|
||||
{
|
||||
output.WriteLine("Source code generation for assembly " + context.Compilation.AssemblyName);
|
||||
|
||||
if (context.AdditionalFiles.Any())
|
||||
{
|
||||
output.WriteLine($"Additional files:");
|
||||
foreach (var item in context.AdditionalFiles)
|
||||
{
|
||||
output.WriteLine(" " + item.Path);
|
||||
}
|
||||
}
|
||||
|
||||
output.WriteLine("Referenced assemblies for this compilation:");
|
||||
foreach (var referencedAssembly in context.Compilation.ReferencedAssemblyNames)
|
||||
{
|
||||
output.WriteLine(" - " + referencedAssembly.Name);
|
||||
}
|
||||
|
||||
bool compilationReferencesYarnSpinner = context.Compilation.ReferencedAssemblyNames
|
||||
.Any(name => name.Name == YarnSpinnerUnityAssemblyName);
|
||||
|
||||
if (compilationReferencesYarnSpinner == false)
|
||||
{
|
||||
// This compilation doesn't reference YarnSpinner.Unity. Any
|
||||
// code that we generate that references symbols in that
|
||||
// assembly won't work.
|
||||
output.WriteLine($"Assembly {context.Compilation.AssemblyName} doesn't reference {YarnSpinnerUnityAssemblyName}. Not generating any code for it.");
|
||||
return;
|
||||
}
|
||||
|
||||
output.WriteLine("Preprocessor Symbols: ");
|
||||
foreach (var symbol in context.ParseOptions.PreprocessorSymbolNames)
|
||||
{
|
||||
output.WriteLine("- " + symbol);
|
||||
}
|
||||
|
||||
// Don't generate source code if we're not targeting at least Unity
|
||||
// 2021.2. (Unity will not invoke this DLL as a source code
|
||||
// generator until at least this version, but other tools like
|
||||
// OmniSharp might.)
|
||||
if (!context.ParseOptions.PreprocessorSymbolNames.Contains(MinimumUnityVersionPreprocessorSymbol))
|
||||
{
|
||||
output.WriteLine($"Not generating code for assembly {context.Compilation.AssemblyName} because this assembly is not being built for Unity 2021.2 or newer");
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't generate source code for certain Yarn Spinner provided
|
||||
// assemblies - these always manually register any actions in them.
|
||||
var prefixesToIgnore = new List<string>()
|
||||
{
|
||||
"YarnSpinner.Unity",
|
||||
"YarnSpinner.Editor",
|
||||
};
|
||||
|
||||
// But DO generate source code for the Samples assembly and the Test assembly
|
||||
var prefixesToKeep = new List<string>()
|
||||
{
|
||||
"YarnSpinner.Unity.Samples",
|
||||
};
|
||||
|
||||
// Additionally, if we're building for unit tests, include the Yarn
|
||||
// Spinner unit tests assembly.
|
||||
if (context.ParseOptions.PreprocessorSymbolNames.Contains(IncludeTestCommands))
|
||||
{
|
||||
prefixesToKeep.Add("YarnSpinner.Unity.Tests");
|
||||
}
|
||||
|
||||
if (context.Compilation.AssemblyName == null)
|
||||
{
|
||||
output.WriteLine("Not generating registration code, because the provided AssemblyName is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (prefixesToIgnore.Any(prefix => context.Compilation.AssemblyName.StartsWith(prefix)) && !prefixesToKeep.Any(prefix => context.Compilation.AssemblyName.StartsWith(prefix)))
|
||||
{
|
||||
output.WriteLine($"Not generating registration code for {context.Compilation.AssemblyName}: we've been told to exclude it, because its name begins with one of these prefixes: {string.Join(", ", prefixesToIgnore)}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(context.Compilation is CSharpCompilation compilation))
|
||||
{
|
||||
// This is not a C# compilation, so we can't do analysis.
|
||||
output.WriteLine($"Stopping code generation because compilation is not a {nameof(CSharpCompilation)}.");
|
||||
return;
|
||||
}
|
||||
|
||||
var actions = new List<YarnAction>();
|
||||
foreach (var tree in compilation.SyntaxTrees)
|
||||
{
|
||||
actions.AddRange(Analyser.GetActions(compilation, tree, output));
|
||||
}
|
||||
|
||||
if (actions.Count() == 0)
|
||||
{
|
||||
output.WriteLine($"Didn't find any Yarn Actions in {context.Compilation.AssemblyName}. Not generating any source code for it.");
|
||||
return;
|
||||
}
|
||||
|
||||
// validating and logging all the actions
|
||||
foreach (var action in actions)
|
||||
{
|
||||
if (action == null)
|
||||
{
|
||||
output.WriteLine($"Action is null??");
|
||||
continue;
|
||||
}
|
||||
|
||||
var diagnostics = action.Validate(compilation, output);
|
||||
foreach (var diagnostic in diagnostics)
|
||||
{
|
||||
context.ReportDiagnostic(diagnostic);
|
||||
if (diagnostic.Severity == DiagnosticSeverity.Warning || diagnostic.Severity == DiagnosticSeverity.Error)
|
||||
{
|
||||
output.WriteLine($"Flagging '{action.Name}' ({action.MethodName}): {diagnostic}");
|
||||
action.ContainsErrors = true;
|
||||
|
||||
if (diagnostic.Severity == DiagnosticSeverity.Error)
|
||||
{
|
||||
hasCriticalActionErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Commands are parsed as whitespace, so spaces in the command name
|
||||
// would render the command un-callable.
|
||||
if (action.Name.Any(x => Char.IsWhiteSpace(x)))
|
||||
{
|
||||
var descriptor = new DiagnosticDescriptor(
|
||||
"YS1002",
|
||||
$"Yarn {action.Type} methods must have a valid name",
|
||||
"YarnCommand and YarnFunction methods follow existing ID rules for Yarn. \"{0}\" is invalid.",
|
||||
"Yarn Spinner",
|
||||
DiagnosticSeverity.Warning,
|
||||
true,
|
||||
"[YarnCommand] and [YarnFunction] attributed methods must follow Yarn ID rules so that Yarn scripts can reference them.",
|
||||
"https://docs.yarnspinner.dev/using-yarnspinner-with-unity/creating-commands-functions");
|
||||
context.ReportDiagnostic(Microsoft.CodeAnalysis.Diagnostic.Create(
|
||||
descriptor,
|
||||
action.Declaration?.GetLocation(),
|
||||
action.Name
|
||||
));
|
||||
action.ContainsErrors = true;
|
||||
output.WriteLine($"Action {action.MethodIdentifierName} will be flagged due to it's name {action.Name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
output.WriteLine($"Action {action.Name}: {action.SourceFileName}:{action.Declaration?.GetLocation()?.GetLineSpan().StartLinePosition.Line} ({action.Type})");
|
||||
}
|
||||
|
||||
if (hasCriticalActionErrors)
|
||||
{
|
||||
stopwatch.Stop();
|
||||
output.WriteLine($"Critical issues were encountered in the actions, aborting code generation, stopping analysis after {stopwatch.Elapsed.TotalMilliseconds}ms");
|
||||
return;
|
||||
}
|
||||
|
||||
output.Write($"Generating source code...");
|
||||
|
||||
var source = Analyser.GenerateRegistrationFileSource(actions);
|
||||
|
||||
output.WriteLine($"Done.");
|
||||
|
||||
SourceText sourceText = SourceText.From(source, Encoding.UTF8);
|
||||
|
||||
output.Write($"Writing generated source...");
|
||||
|
||||
DumpGeneratedFile(context, source);
|
||||
|
||||
output.WriteLine($"Done.");
|
||||
|
||||
context.AddSource($"YarnActionRegistration-{compilation.AssemblyName}.Generated.cs", sourceText);
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
if (settings.generateYSLSFile)
|
||||
{
|
||||
output.Write($"Generating ysls...");
|
||||
// generating the ysls
|
||||
|
||||
IEnumerable<string> commandJSON = actions.Where(a => a.Type == ActionType.Command).Select(a => a.ToJSON());
|
||||
IEnumerable<string> functionJSON = actions.Where(a => a.Type == ActionType.Function).Select(a => a.ToJSON());
|
||||
|
||||
var ysls = "{" +
|
||||
@"""version"":2," +
|
||||
$@"""commands"":[{string.Join(",", commandJSON)}]," +
|
||||
$@"""functions"":[{string.Join(",", functionJSON)}]" +
|
||||
"}";
|
||||
|
||||
output.WriteLine($"Done.");
|
||||
|
||||
if (!string.IsNullOrEmpty(projectPath))
|
||||
{
|
||||
output.Write($"Writing generated ysls...");
|
||||
|
||||
var fullPath = Path.Combine(projectPath, Yarn.Unity.Editor.YarnSpinnerProjectSettings.YarnSpinnerAssemblyGeneratedYSLSPath(compilation.AssemblyName));
|
||||
try
|
||||
{
|
||||
System.IO.File.WriteAllText(fullPath, ysls);
|
||||
output.WriteLine($"Done.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
output.WriteLine($"Unable to write ysls to disk: {e.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
output.WriteLine("unable to identify project path, ysls will not be written to disk");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
output.WriteLine($"skipping ysls generation due to settings");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
output.WriteLine($"skipping ysls generation due to settings not being found");
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
output.WriteLine($"Source code generation completed in {stopwatch.Elapsed.TotalMilliseconds}ms");
|
||||
return;
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
output.WriteLine($"{e}");
|
||||
}
|
||||
}
|
||||
|
||||
private MethodDeclarationSyntax GenerateLoggingMethod(string methodName, string sourceExpression, string prefix)
|
||||
{
|
||||
return SyntaxFactory.MethodDeclaration(
|
||||
SyntaxFactory.PredefinedType(
|
||||
SyntaxFactory.Token(SyntaxKind.VoidKeyword)),
|
||||
SyntaxFactory.Identifier(methodName))
|
||||
.WithModifiers(
|
||||
SyntaxFactory.TokenList(
|
||||
new[]{
|
||||
SyntaxFactory.Token(SyntaxKind.PublicKeyword),
|
||||
SyntaxFactory.Token(SyntaxKind.StaticKeyword)}))
|
||||
.WithBody(
|
||||
SyntaxFactory.Block(
|
||||
SyntaxFactory.LocalDeclarationStatement(
|
||||
SyntaxFactory.VariableDeclaration(
|
||||
SyntaxFactory.GenericName(
|
||||
SyntaxFactory.Identifier("IEnumerable"))
|
||||
.WithTypeArgumentList(
|
||||
SyntaxFactory.TypeArgumentList(
|
||||
SyntaxFactory.SingletonSeparatedList<TypeSyntax>(
|
||||
SyntaxFactory.PredefinedType(
|
||||
SyntaxFactory.Token(SyntaxKind.StringKeyword))))))
|
||||
.WithVariables(
|
||||
SyntaxFactory.SingletonSeparatedList<VariableDeclaratorSyntax>(
|
||||
SyntaxFactory.VariableDeclarator(
|
||||
SyntaxFactory.Identifier("source"))
|
||||
.WithInitializer(
|
||||
SyntaxFactory.EqualsValueClause(
|
||||
SyntaxFactory.ParseExpression(sourceExpression)))))),
|
||||
SyntaxFactory.LocalDeclarationStatement(
|
||||
SyntaxFactory.VariableDeclaration(
|
||||
SyntaxFactory.IdentifierName(
|
||||
SyntaxFactory.Identifier(
|
||||
SyntaxFactory.TriviaList(),
|
||||
SyntaxKind.VarKeyword,
|
||||
"var",
|
||||
"var",
|
||||
SyntaxFactory.TriviaList())))
|
||||
.WithVariables(
|
||||
SyntaxFactory.SingletonSeparatedList<VariableDeclaratorSyntax>(
|
||||
SyntaxFactory.VariableDeclarator(
|
||||
SyntaxFactory.Identifier("prefix"))
|
||||
.WithInitializer(
|
||||
SyntaxFactory.EqualsValueClause(
|
||||
SyntaxFactory.LiteralExpression(
|
||||
SyntaxKind.StringLiteralExpression,
|
||||
SyntaxFactory.Literal(prefix))))))),
|
||||
SyntaxFactory.ExpressionStatement(
|
||||
SyntaxFactory.InvocationExpression(
|
||||
SyntaxFactory.MemberAccessExpression(
|
||||
SyntaxKind.SimpleMemberAccessExpression,
|
||||
SyntaxFactory.IdentifierName("Debug"),
|
||||
SyntaxFactory.IdentifierName("Log")
|
||||
)
|
||||
)
|
||||
.WithArgumentList(
|
||||
SyntaxFactory.ArgumentList(
|
||||
SyntaxFactory.SingletonSeparatedList<ArgumentSyntax>(
|
||||
SyntaxFactory.Argument(
|
||||
SyntaxFactory.InterpolatedStringExpression(
|
||||
SyntaxFactory.Token(SyntaxKind.InterpolatedVerbatimStringStartToken)
|
||||
)
|
||||
.WithContents(
|
||||
SyntaxFactory.List<InterpolatedStringContentSyntax>(
|
||||
new InterpolatedStringContentSyntax[]{
|
||||
SyntaxFactory.Interpolation(
|
||||
SyntaxFactory.IdentifierName("prefix")
|
||||
),
|
||||
SyntaxFactory.InterpolatedStringText()
|
||||
.WithTextToken(
|
||||
SyntaxFactory.Token(
|
||||
SyntaxFactory.TriviaList(),
|
||||
SyntaxKind.InterpolatedStringTextToken,
|
||||
" ",
|
||||
" ",
|
||||
SyntaxFactory.TriviaList()
|
||||
)
|
||||
),
|
||||
SyntaxFactory.Interpolation(
|
||||
SyntaxFactory.InvocationExpression(
|
||||
SyntaxFactory.MemberAccessExpression(
|
||||
SyntaxKind.SimpleMemberAccessExpression,
|
||||
SyntaxFactory.PredefinedType(
|
||||
SyntaxFactory.Token(SyntaxKind.StringKeyword)
|
||||
),
|
||||
SyntaxFactory.IdentifierName("Join")
|
||||
)
|
||||
)
|
||||
.WithArgumentList(
|
||||
SyntaxFactory.ArgumentList(
|
||||
SyntaxFactory.SeparatedList<ArgumentSyntax>(
|
||||
new SyntaxNodeOrToken[]{
|
||||
SyntaxFactory.Argument(
|
||||
SyntaxFactory.LiteralExpression(
|
||||
SyntaxKind.CharacterLiteralExpression,
|
||||
SyntaxFactory.Literal(';')
|
||||
)
|
||||
),
|
||||
SyntaxFactory.Token(SyntaxKind.CommaToken),
|
||||
SyntaxFactory.Argument(
|
||||
SyntaxFactory.IdentifierName("source")
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.NormalizeWhitespace();
|
||||
}
|
||||
|
||||
public static MethodDeclarationSyntax GenerateSingleLogMethod(string methodName, string text, string prefix)
|
||||
{
|
||||
return SyntaxFactory.MethodDeclaration(
|
||||
SyntaxFactory.PredefinedType(
|
||||
SyntaxFactory.Token(SyntaxKind.VoidKeyword)
|
||||
),
|
||||
SyntaxFactory.Identifier(methodName)
|
||||
)
|
||||
.WithModifiers(
|
||||
SyntaxFactory.TokenList(
|
||||
new[]{
|
||||
SyntaxFactory.Token(SyntaxKind.PublicKeyword),
|
||||
SyntaxFactory.Token(SyntaxKind.StaticKeyword)
|
||||
}
|
||||
)
|
||||
)
|
||||
.WithBody(
|
||||
SyntaxFactory.Block(
|
||||
SyntaxFactory.SingletonList<StatementSyntax>(
|
||||
SyntaxFactory.ExpressionStatement(
|
||||
SyntaxFactory.InvocationExpression(
|
||||
SyntaxFactory.MemberAccessExpression(
|
||||
SyntaxKind.SimpleMemberAccessExpression,
|
||||
SyntaxFactory.IdentifierName("Debug"),
|
||||
SyntaxFactory.IdentifierName("Log")
|
||||
)
|
||||
)
|
||||
.WithArgumentList(
|
||||
SyntaxFactory.ArgumentList(
|
||||
SyntaxFactory.SingletonSeparatedList<ArgumentSyntax>(
|
||||
SyntaxFactory.Argument(
|
||||
SyntaxFactory.InterpolatedStringExpression(
|
||||
SyntaxFactory.Token(SyntaxKind.InterpolatedStringStartToken)
|
||||
)
|
||||
.WithContents(
|
||||
SyntaxFactory.List<InterpolatedStringContentSyntax>(
|
||||
new InterpolatedStringContentSyntax[]{
|
||||
SyntaxFactory.Interpolation(
|
||||
SyntaxFactory.LiteralExpression(
|
||||
SyntaxKind.StringLiteralExpression,
|
||||
SyntaxFactory.Literal(prefix)
|
||||
)
|
||||
),
|
||||
SyntaxFactory.InterpolatedStringText()
|
||||
.WithTextToken(
|
||||
SyntaxFactory.Token(
|
||||
SyntaxFactory.TriviaList(),
|
||||
SyntaxKind.InterpolatedStringTextToken,
|
||||
" ",
|
||||
" ",
|
||||
SyntaxFactory.TriviaList()
|
||||
)
|
||||
),
|
||||
SyntaxFactory.Interpolation(
|
||||
SyntaxFactory.LiteralExpression(
|
||||
SyntaxKind.StringLiteralExpression,
|
||||
SyntaxFactory.Literal(text)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.NormalizeWhitespace();
|
||||
}
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterForSyntaxNotifications(() => new ClassDeclarationSyntaxReceiver());
|
||||
}
|
||||
|
||||
static string GetTemporaryPath(GeneratorExecutionContext context)
|
||||
{
|
||||
string tempPath;
|
||||
var rootPath = GetProjectRoot(context);
|
||||
if (rootPath != null)
|
||||
{
|
||||
tempPath = Path.Combine(rootPath, "Logs", "Packages", "dev.yarnspinner.unity");
|
||||
}
|
||||
else
|
||||
{
|
||||
tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "dev.yarnspinner.logs");
|
||||
}
|
||||
|
||||
// we need to make the logs folder, but this can potentially fail
|
||||
// if it does fail then we will just chuck the logs inside the tmp folder
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(tempPath))
|
||||
{
|
||||
Directory.CreateDirectory(tempPath);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
tempPath = System.IO.Path.GetTempPath();
|
||||
}
|
||||
return tempPath;
|
||||
}
|
||||
|
||||
public Yarn.Unity.ILogger GetOutput(GeneratorExecutionContext context)
|
||||
{
|
||||
if (GetShouldLogToFile(context))
|
||||
{
|
||||
var tempPath = ActionRegistrationSourceGenerator.GetTemporaryPath(context);
|
||||
|
||||
var path = System.IO.Path.Combine(tempPath, $"{nameof(ActionRegistrationSourceGenerator)}-{context.Compilation.AssemblyName}.txt");
|
||||
var outFile = System.IO.File.Open(path, System.IO.FileMode.Create);
|
||||
|
||||
return new Yarn.Unity.FileLogger(new System.IO.StreamWriter(outFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Yarn.Unity.NullLogger();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool GetShouldLogToFile(GeneratorExecutionContext context)
|
||||
{
|
||||
return context.ParseOptions.PreprocessorSymbolNames.Contains(DebugLoggingPreprocessorSymbol);
|
||||
}
|
||||
|
||||
public void DumpGeneratedFile(GeneratorExecutionContext context, string text)
|
||||
{
|
||||
if (GetShouldLogToFile(context))
|
||||
{
|
||||
var tempPath = ActionRegistrationSourceGenerator.GetTemporaryPath(context);
|
||||
var path = System.IO.Path.Combine(tempPath, $"{nameof(ActionRegistrationSourceGenerator)}-{context.Compilation.AssemblyName}.cs");
|
||||
System.IO.File.WriteAllText(path, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ClassDeclarationSyntaxReceiver : ISyntaxReceiver
|
||||
{
|
||||
public List<ClassDeclarationSyntax> Classes { get; private set; } = new List<ClassDeclarationSyntax>();
|
||||
|
||||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
{
|
||||
// Business logic to decide what we're interested in goes here
|
||||
if (syntaxNode is ClassDeclarationSyntax cds)
|
||||
{
|
||||
Classes.Add(cds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Actions Registration Generator for Yarn Spinner
|
||||
|
||||
This folder contains the source code for the [source generator](https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview) that produces registration code for Yarn Spinner actions (for example, `YarnCommand` and `YarnAction`).
|
||||
|
||||
This folder ends with a tilde `~` to make Unity not aware of it. To build the source code generator, install the .NET SDK and use `dotnet-build`. The built DLL will be placed at the following path:
|
||||
|
||||
```
|
||||
(path to Yarn Spinner)/SourceGenerator/YarnSpinner.Unity.SourceCodeGenerator.dll
|
||||
```
|
||||
1165
Packages/dev.yarnspinner.unity/Editor/Analysis/Analyser.cs
Normal file
1165
Packages/dev.yarnspinner.unity/Editor/Analysis/Analyser.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee966ea0c2700450080c5d533c3c5afc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Yarn.Unity.ActionAnalyser
|
||||
{
|
||||
[System.Serializable]
|
||||
public class AnalyserException : System.Exception
|
||||
{
|
||||
public AnalyserException() { }
|
||||
public AnalyserException(string message) : base(message) { }
|
||||
public AnalyserException(string message, System.Exception inner) : base(message, inner) { }
|
||||
public AnalyserException(string message, System.Exception inner, IEnumerable<Microsoft.CodeAnalysis.Diagnostic> diagnostics) : base(message, inner)
|
||||
{
|
||||
this.Diagnostics = diagnostics;
|
||||
}
|
||||
protected AnalyserException(
|
||||
System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
|
||||
public IEnumerable<Microsoft.CodeAnalysis.Diagnostic> Diagnostics { get; } = new List<Microsoft.CodeAnalysis.Diagnostic>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4318b63e7e2584e3895f7b9c8782154b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/dev.yarnspinner.unity/Editor/Analysis/DLLs.meta
Normal file
8
Packages/dev.yarnspinner.unity/Editor/Analysis/DLLs.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38292618b0e0e46e2a23aa0b7ab05be9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e596e8d36f4949e49a276da7dcf74d0
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0d5eb061e5a94e61918a4bcc8343d0f
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05b4f6ee4402b4befa8b93e0b0f30072
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d36ed78c475f14eada798a8881d84f4a
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f124754956f07408dafc0d384a437712
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33c2c99bdbd9f48f1bfe7333e3c7f401
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8807786a5b21e4484ae712f0f92620db
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b1c9dc69df6f47a38bd1ad37d4319bd
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
111
Packages/dev.yarnspinner.unity/Editor/Analysis/Diagnostics.cs
Normal file
111
Packages/dev.yarnspinner.unity/Editor/Analysis/Diagnostics.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
|
||||
public static class Diagnostics
|
||||
{
|
||||
public static readonly DiagnosticDescriptor YS1000UnknownError = new DiagnosticDescriptor(
|
||||
"YS0000",
|
||||
title: $"Internal unknown error",
|
||||
messageFormat: "An internal error was encountered while processing this action: {0}",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true);
|
||||
public static readonly DiagnosticDescriptor YS1001ActionMethodsMustBePublic = new DiagnosticDescriptor(
|
||||
"YS1001",
|
||||
title: $"Yarn action methods must be public",
|
||||
messageFormat: "YarnCommand and YarnFunction methods must be public. \"{0}\" is {1}.",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true,
|
||||
description: "[YarnCommand] and [YarnFunction] attributed methods must be public so that the codegen can reference them.",
|
||||
helpLinkUri: "https://docs.yarnspinner.dev/using-yarnspinner-with-unity/creating-commands-functions");
|
||||
|
||||
public static readonly DiagnosticDescriptor YS1002ActionMethodsMustHaveAValidName = new DiagnosticDescriptor(
|
||||
"YS1002",
|
||||
title: $"Yarn action methods must have a valid name",
|
||||
messageFormat: "YarnCommand and YarnFunction methods must follow existing ID rules for Yarn. \"{0}\" is invalid.",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true,
|
||||
description: "[YarnCommand] and [YarnFunction] attributed methods must follow Yarn ID rules so that Yarn scripts can reference them.",
|
||||
helpLinkUri: "https://docs.yarnspinner.dev/using-yarnspinner-with-unity/creating-commands-functions");
|
||||
public static readonly DiagnosticDescriptor YS1003CommandMethodsMustHaveAValidReturnType = new DiagnosticDescriptor(
|
||||
"YS1003",
|
||||
title: $"YarnCommand methods must return a valid type",
|
||||
messageFormat: $"YarnCommand methods must return a valid type (either void, a coroutine, or a task). \"{{0}}\"'s return type is {{1}}.",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true,
|
||||
helpLinkUri: "https://docs.yarnspinner.dev/using-yarnspinner-with-unity/creating-commands-functions");
|
||||
public static readonly DiagnosticDescriptor YS1004FunctionMethodsMustHaveAValidReturnType = new DiagnosticDescriptor(
|
||||
"YS1004",
|
||||
title: $"YarnFunction methods must return a valid type",
|
||||
messageFormat: $"YarnFunction methods must return a valid type (either bool, string, or a numeric type). \"{{0}}\"'s return type is {{1}}.",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true,
|
||||
helpLinkUri: "https://docs.yarnspinner.dev/using-yarnspinner-with-unity/creating-commands-functions");
|
||||
public static readonly DiagnosticDescriptor YS1005ActionMethodsMustHaveOneActionAttribute = new DiagnosticDescriptor(
|
||||
"YS1005",
|
||||
title: $"Yarn action methods must have a single YarnCommand or YarnAction attribute",
|
||||
messageFormat: $"YarnCommand and YarnFunction methods must have a single attribute. \"{{0}}\" has {{1}}.",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true,
|
||||
helpLinkUri: "https://docs.yarnspinner.dev/using-yarnspinner-with-unity/creating-commands-functions");
|
||||
|
||||
public static readonly DiagnosticDescriptor YS1006YarnFunctionsMustBeStatic = new DiagnosticDescriptor(
|
||||
"YS1006",
|
||||
title: $"YarnFunction methods be static",
|
||||
messageFormat: $"YarnFunction methods are required to be static.",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true,
|
||||
helpLinkUri: "https://docs.yarnspinner.dev/using-yarnspinner-with-unity/creating-commands-functions");
|
||||
|
||||
public static readonly DiagnosticDescriptor YS1008ActionsParamsArraysMustBeOfYarnTypes = new DiagnosticDescriptor(
|
||||
"YS1008",
|
||||
title: "Params arrays must be of a Yarn compatible type",
|
||||
messageFormat: "Params arrays must be of a Yarn compatible type, but {0} is of type \"{1}\"",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true,
|
||||
helpLinkUri: "https://docs.yarnspinner.dev/yarn-spinner-for-unity/creating-commands-functions");
|
||||
|
||||
public static readonly DiagnosticDescriptor YS1009ActionsEnumAttributedParameterIsOfIncompatibleType = new DiagnosticDescriptor(
|
||||
"YS1009",
|
||||
title: "Yarn Enum attributed parameters must be of a Yarn compatible type",
|
||||
messageFormat: "Yarn Enum attributed parameters must be of a Yarn compatible type, but {0} is of type \"{1}\"",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true,
|
||||
helpLinkUri: "https://docs.yarnspinner.dev/yarn-spinner-for-unity/creating-commands-functions");
|
||||
|
||||
public static readonly DiagnosticDescriptor YS1010ActionsNodeAttributedParameterIsOfIncompatibleType = new DiagnosticDescriptor(
|
||||
"YS1010",
|
||||
title: "Yarn Node attributed parameters must be a string",
|
||||
messageFormat: "Yarn Node attributed parameters must be a string, but {0} is of type \"{1}\"",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true,
|
||||
helpLinkUri: "https://docs.yarnspinner.dev/yarn-spinner-for-unity/creating-commands-functions");
|
||||
|
||||
public static readonly DiagnosticDescriptor YS1011ActionsParameterIsAnIncompatibleType = new DiagnosticDescriptor(
|
||||
"YS1011",
|
||||
title: "Yarn action parameters must be of a Yarn compatible type",
|
||||
messageFormat: "Yarn action parameters must be of a Yarn compatible type, but {0} is of type \"{1}\"",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Warning,
|
||||
isEnabledByDefault: true,
|
||||
helpLinkUri: "https://docs.yarnspinner.dev/yarn-spinner-for-unity/creating-commands-functions");
|
||||
|
||||
public static readonly DiagnosticDescriptor YS1012ActionIsALambda = new DiagnosticDescriptor(
|
||||
"YS1012",
|
||||
title: "Yarn actions can be lambdas but this generally isn't recommended",
|
||||
messageFormat: "Yarn actions can be lambdas but this generally isn't recommended. Lambda based actions cannot be unregistered and are more difficult to debug",
|
||||
category: "Yarn Spinner",
|
||||
defaultSeverity: DiagnosticSeverity.Info,
|
||||
isEnabledByDefault: true,
|
||||
helpLinkUri: "https://docs.yarnspinner.dev/yarn-spinner-for-unity/creating-commands-functions");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ef837099f8664a9ab951ed2c6ba6e72
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#nullable enable
|
||||
|
||||
static class EnumerableExtensions
|
||||
{
|
||||
public static IEnumerable<T> NonNull<T>(this IEnumerable<T?> collection, bool throwIfAnyNull = false) where T : class
|
||||
{
|
||||
foreach (var item in collection)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (throwIfAnyNull)
|
||||
{
|
||||
throw new NullReferenceException("Collection contains a null item");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a3d39b6f28ae4a31989cb67e5aa3d98
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
132
Packages/dev.yarnspinner.unity/Editor/Analysis/ILogger.cs
Normal file
132
Packages/dev.yarnspinner.unity/Editor/Analysis/ILogger.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
#endif
|
||||
|
||||
namespace Yarn.Unity
|
||||
{
|
||||
#nullable enable
|
||||
public interface ILogger : IDisposable
|
||||
{
|
||||
void Write(object obj);
|
||||
void WriteLine(object obj);
|
||||
void WriteException(System.Exception ex, string? message = null);
|
||||
|
||||
void Inc();
|
||||
void Dec();
|
||||
void SetDepth(int depth);
|
||||
}
|
||||
|
||||
public class FileLogger : ILogger
|
||||
{
|
||||
System.IO.TextWriter writer;
|
||||
private int depth = 0;
|
||||
|
||||
public FileLogger(System.IO.TextWriter writer)
|
||||
{
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
writer.Flush();
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
public void Write(object text)
|
||||
{
|
||||
var tabs = new String('\t', depth);
|
||||
writer.Write(tabs + text);
|
||||
}
|
||||
|
||||
public void WriteLine(object text)
|
||||
{
|
||||
var tabs = new String('\t', depth);
|
||||
writer.WriteLine(tabs + text);
|
||||
}
|
||||
public void WriteException(System.Exception ex, string? message)
|
||||
{
|
||||
var tabs = new String('\t', depth);
|
||||
if (message == null)
|
||||
{
|
||||
writer.WriteLine($"{tabs}Exception: {ex.Message}");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine($"{tabs}{message}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Inc()
|
||||
{
|
||||
depth +=1 ;
|
||||
}
|
||||
public void Dec()
|
||||
{
|
||||
depth = Math.Max(depth - 1, 0);
|
||||
}
|
||||
public void SetDepth(int depth)
|
||||
{
|
||||
this.depth = Math.Max(depth, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class UnityLogger : ILogger
|
||||
{
|
||||
public void Dispose() { }
|
||||
|
||||
public void Write(object text)
|
||||
{
|
||||
WriteLine(text);
|
||||
}
|
||||
|
||||
public void WriteLine(object text)
|
||||
{
|
||||
var tabs = new String('\t', depth);
|
||||
#if UNITY_EDITOR
|
||||
Debug.LogWarning(tabs + text.ToString());
|
||||
#endif
|
||||
}
|
||||
|
||||
public void WriteException(System.Exception ex, string? message = null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Debug.LogException(ex);
|
||||
#endif
|
||||
}
|
||||
|
||||
private int depth = 0;
|
||||
public void Inc()
|
||||
{
|
||||
depth +=1 ;
|
||||
}
|
||||
public void Dec()
|
||||
{
|
||||
depth = Math.Max(depth - 1, 0);
|
||||
}
|
||||
public void SetDepth(int depth)
|
||||
{
|
||||
this.depth = Math.Max(depth, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class NullLogger : ILogger
|
||||
{
|
||||
public void Dispose() { }
|
||||
|
||||
public void Write(object text) { }
|
||||
|
||||
public void WriteLine(object text) { }
|
||||
|
||||
public void WriteException(System.Exception ex, string? message = null) { }
|
||||
|
||||
public void Inc(){}
|
||||
public void Dec(){}
|
||||
public void SetDepth(int depth) {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45e3ce698d3364e5790443887a66daff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
#nullable enable
|
||||
|
||||
static class SymbolExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// If the <paramref name="symbol"/> is a method symbol, returns <see langword="true"/> if the method's return type is "awaitable", but not if it's <see langword="dynamic"/>.
|
||||
/// If the <paramref name="symbol"/> is a type symbol, returns <see langword="true"/> if that type is "awaitable".
|
||||
/// An "awaitable" is any type that exposes a GetAwaiter method which returns a valid "awaiter". This GetAwaiter method may be an instance method or an extension method.
|
||||
/// </summary>
|
||||
public static bool IsAwaitableNonDynamic(this ISymbol symbol, SemanticModel semanticModel, int position)
|
||||
{
|
||||
IMethodSymbol? methodSymbol = symbol as IMethodSymbol;
|
||||
ITypeSymbol? typeSymbol = null;
|
||||
|
||||
if (methodSymbol == null)
|
||||
{
|
||||
typeSymbol = symbol as ITypeSymbol;
|
||||
if (typeSymbol == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (methodSymbol.ReturnType == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise: needs valid GetAwaiter
|
||||
var potentialGetAwaiters = semanticModel.LookupSymbols(position,
|
||||
container: typeSymbol ?? methodSymbol?.ReturnType.OriginalDefinition,
|
||||
name: WellKnownMemberNames.GetAwaiter,
|
||||
includeReducedExtensionMethods: true);
|
||||
var getAwaiters = potentialGetAwaiters.OfType<IMethodSymbol>().Where(x => !x.Parameters.Any());
|
||||
return getAwaiters.Any(VerifyGetAwaiter);
|
||||
}
|
||||
|
||||
private static bool VerifyGetAwaiter(IMethodSymbol getAwaiter)
|
||||
{
|
||||
var returnType = getAwaiter.ReturnType;
|
||||
if (returnType == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// bool IsCompleted { get }
|
||||
if (!returnType.GetMembers().OfType<IPropertySymbol>().Any(p => p.Name == WellKnownMemberNames.IsCompleted && p.Type.SpecialType == SpecialType.System_Boolean && p.GetMethod != null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var methods = returnType.GetMembers().OfType<IMethodSymbol>();
|
||||
|
||||
// NOTE: (vladres) The current version of C# Spec, §7.7.7.3 'Runtime evaluation of await expressions', requires that
|
||||
// NOTE: the interface method INotifyCompletion.OnCompleted or ICriticalNotifyCompletion.UnsafeOnCompleted is invoked
|
||||
// NOTE: (rather than any OnCompleted method conforming to a certain pattern).
|
||||
// NOTE: Should this code be updated to match the spec?
|
||||
|
||||
// void OnCompleted(Action)
|
||||
// Actions are delegates, so we'll just check for delegates.
|
||||
if (!methods.Any(x => x.Name == WellKnownMemberNames.OnCompleted && x.ReturnsVoid && x.Parameters.Length == 1 && x.Parameters.First().Type.TypeKind == TypeKind.Delegate))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// void GetResult() || T GetResult()
|
||||
return methods.Any(m => m.Name == WellKnownMemberNames.GetResult && !m.Parameters.Any());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 245397f2263474149856dba1cfc50f19
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
13
Packages/dev.yarnspinner.unity/Editor/AssemblyInfo.cs
Normal file
13
Packages/dev.yarnspinner.unity/Editor/AssemblyInfo.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyVersion("3.1.4.0")]
|
||||
[assembly: AssemblyFileVersion("3.1.4.0")]
|
||||
[assembly: AssemblyInformationalVersion("3.1.4.Branch.hotfix/textanim-build-errors.Sha.c2b119c5eda7fdd3cd0b13a689f95d54d456fb69")]
|
||||
|
||||
[assembly: InternalsVisibleTo("YarnSpinner.Unity.Editor")]
|
||||
[assembly: InternalsVisibleTo("YarnSpinner.Unity.Tests.Editor")]
|
||||
11
Packages/dev.yarnspinner.unity/Editor/AssemblyInfo.cs.meta
Normal file
11
Packages/dev.yarnspinner.unity/Editor/AssemblyInfo.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be2fc8d5bc6c7624e95557f8af15a1b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/dev.yarnspinner.unity/Editor/Editors.meta
Normal file
8
Packages/dev.yarnspinner.unity/Editor/Editors.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53fbdca23523543cfbcda84a57c09996
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AssetImporters;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using Yarn.Compiler;
|
||||
|
||||
#if USE_UNITY_LOCALIZATION
|
||||
using UnityEditor.Localization;
|
||||
using UnityEngine.Localization.Tables;
|
||||
using UnityEngine.Localization;
|
||||
|
||||
public class AddAssetsToAssetTableCollectionWizard : EditorWindow
|
||||
{
|
||||
|
||||
private YarnProject? yarnProject;
|
||||
|
||||
private AssetTableCollection? assetTableCollection;
|
||||
|
||||
private Type? _assetType;
|
||||
private Type AssetType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_assetType == null)
|
||||
{
|
||||
var typeName = EditorPrefs.GetString("YarnSpinner_AddAssets_AssetType", string.Empty);
|
||||
if (typeName != string.Empty)
|
||||
{
|
||||
_assetType = System.Type.GetType(typeName, throwOnError: false, ignoreCase: false);
|
||||
}
|
||||
}
|
||||
_assetType ??= typeof(AudioClip);
|
||||
return _assetType;
|
||||
}
|
||||
set
|
||||
{
|
||||
_assetType = value;
|
||||
EditorPrefs.SetString("YarnSpinner_AddAssets_AssetType", _assetType?.AssemblyQualifiedName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, DefaultAsset?> localesToFolders = new Dictionary<string, DefaultAsset?>();
|
||||
private Type[] allTypes = Array.Empty<Type>();
|
||||
private GUIContent[] allTypeContents = Array.Empty<GUIContent>();
|
||||
System.Collections.ObjectModel.ReadOnlyCollection<UnityEngine.Localization.Locale>? locales = null;
|
||||
|
||||
private Dictionary<LocaleIdentifier, LocalizationTable> _cachedTables = new();
|
||||
|
||||
const string description = "This tool searches Asset Folders for assets of the selected type, and then adds them to an Asset Table Collection. Line Providers, like Unity Localised Line Provider, can then fetch these assets at run-time.";
|
||||
|
||||
[MenuItem("Window/Yarn Spinner/Add Assets to Table Collection")]
|
||||
static void Init()
|
||||
{
|
||||
// Get existing open window or if none, make a new one:
|
||||
var window = CreateWindow<AddAssetsToAssetTableCollectionWizard>();
|
||||
window.ShowPopup();
|
||||
window.titleContent = new GUIContent("Add Assets to Table Collection");
|
||||
|
||||
if (Selection.activeObject is AssetTableCollection collection)
|
||||
{
|
||||
window.assetTableCollection = collection;
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
allTypes = TypeCache.GetTypesDerivedFrom<UnityEngine.Object>().OrderBy(t => t.FullName).ToArray();
|
||||
allTypeContents = allTypes.Select(t => new GUIContent(
|
||||
t.FullName.Replace(".", "/"),
|
||||
EditorGUIUtility.ObjectContent(null, t).image
|
||||
)).ToArray();
|
||||
locales = LocalizationEditorSettings.GetLocales();
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
|
||||
using (new GUILayout.VerticalScope())
|
||||
{
|
||||
|
||||
EditorGUILayout.BeginVertical(EditorStyles.inspectorFullWidthMargins);
|
||||
|
||||
EditorGUILayout.HelpBox(description, MessageType.Info);
|
||||
|
||||
assetTableCollection = EditorGUILayout.ObjectField(new GUIContent("Asset Table Collection", "The asset table collection to add assets to"), assetTableCollection, typeof(AssetTableCollection), allowSceneObjects: false) as AssetTableCollection;
|
||||
|
||||
|
||||
yarnProject = EditorGUILayout.ObjectField(new GUIContent("Yarn Project", "The Yarn Project to add assets for."), yarnProject, typeof(YarnProject), allowSceneObjects: false) as YarnProject;
|
||||
|
||||
var selectedIndex = Array.IndexOf(allTypes, AssetType);
|
||||
|
||||
using (var change = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
var newSelection = EditorGUILayout.Popup(new GUIContent("Asset Type", "The type of assets to find in the Asset Folders"), selectedIndex, allTypeContents);
|
||||
|
||||
if (change.changed)
|
||||
{
|
||||
AssetType = allTypes[newSelection];
|
||||
}
|
||||
}
|
||||
|
||||
var headerStyle = EditorStyles.boldLabel;
|
||||
|
||||
if (assetTableCollection != null)
|
||||
{
|
||||
EditorGUILayout.LabelField("Asset Folders", headerStyle);
|
||||
|
||||
EditorGUI.indentLevel += 1;
|
||||
|
||||
if (locales == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("No locales were found in your project. Is Unity Localization installed and correctly configured?", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var locale in locales)
|
||||
{
|
||||
if (_cachedTables.TryGetValue(locale.Identifier, out var localizationTable) == false || localizationTable == null)
|
||||
{
|
||||
if (assetTableCollection != null)
|
||||
{
|
||||
localizationTable = assetTableCollection.GetTable(locale.Identifier);
|
||||
|
||||
_cachedTables[locale.Identifier] = localizationTable;
|
||||
}
|
||||
}
|
||||
|
||||
if (localizationTable == null)
|
||||
{
|
||||
EditorGUILayout.LabelField(new GUIContent(locale.LocaleName), new GUIContent("No table in collection"));
|
||||
continue;
|
||||
}
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(localizationTable == null))
|
||||
{
|
||||
localesToFolders.TryGetValue(locale.Identifier.Code, out var currentFolder);
|
||||
|
||||
localesToFolders[locale.Identifier.Code] = EditorGUILayout.ObjectField(
|
||||
new GUIContent(locale.LocaleName, $"The folder to search for {AssetType.Name} assets for the '{locale.LocaleName}' locale"),
|
||||
currentFolder,
|
||||
typeof(DefaultAsset),
|
||||
allowSceneObjects: false) as DefaultAsset;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel -= 1;
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
var readyToAddAssets = assetTableCollection != null && yarnProject != null && localesToFolders.Where(kv => kv.Value != null).Count() > 0;
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(!readyToAddAssets))
|
||||
{
|
||||
if (GUILayout.Button("Add Assets"))
|
||||
{
|
||||
AddAssets(assetTableCollection!, yarnProject!, localesToFolders!, AssetType);
|
||||
// this.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddAssets(AssetTableCollection assetTableCollection, YarnProject yarnProject, IReadOnlyDictionary<string, DefaultAsset> localesToFolders, System.Type assetType)
|
||||
{
|
||||
var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(yarnProject)) as YarnProjectImporter;
|
||||
|
||||
if (importer == null)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to get an importer for Yarn Project");
|
||||
}
|
||||
|
||||
var stringTable = importer.GenerateStringsTable();
|
||||
|
||||
var lineIDs = stringTable.Select(e => e.ID);
|
||||
|
||||
int totalCount = 0;
|
||||
foreach (var locale in LocalizationEditorSettings.GetLocales())
|
||||
{
|
||||
int perLocaleCount = 0;
|
||||
if (localesToFolders.TryGetValue(locale.Identifier.Code, out var folder) == false
|
||||
|| folder == null)
|
||||
{
|
||||
// No folder given for this locale. Skip it!
|
||||
Debug.Log($"Skipping {locale.LocaleName} because no folder was provided");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assetTableCollection.ContainsTable(locale.Identifier) == false)
|
||||
{
|
||||
// No table in this collection for this locale! Skip it!
|
||||
Debug.Log($"Skipping {locale.LocaleName} because no table exists");
|
||||
continue;
|
||||
}
|
||||
|
||||
var path = AssetDatabase.GetAssetPath(folder);
|
||||
|
||||
var idsToAssetPaths = YarnProjectUtility.FindAssetPathsForLineIDs(lineIDs, AssetDatabase.GetAssetPath(folder), assetType);
|
||||
|
||||
foreach (var (lineID, assetPath) in idsToAssetPaths)
|
||||
{
|
||||
var asset = AssetDatabase.LoadAssetAtPath(assetPath, assetType);
|
||||
|
||||
if (asset == null)
|
||||
{
|
||||
// Not the type of asset we're looking for
|
||||
continue;
|
||||
}
|
||||
|
||||
assetTableCollection.AddAssetToTable(locale.Identifier, lineID, asset);
|
||||
|
||||
perLocaleCount += 1;
|
||||
totalCount += 1;
|
||||
}
|
||||
EditorUtility.SetDirty(assetTableCollection);
|
||||
Debug.Log($"Added {perLocaleCount} assets to {locale.LocaleName}");
|
||||
}
|
||||
Debug.Log($"Added {totalCount} assets to asset table collection");
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2c8a684ed88e47a083d7334e5f24ebc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6042640492df0421da69d5084456a10c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
||||
<ui:Label text="Label" display-tooltip-when-elided="true" name="Title" />
|
||||
<ui:Label text="Label" display-tooltip-when-elided="true" name="Subtitle" />
|
||||
</ui:UXML>
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90cfaddaa17c84dc79cd95f4448553b2
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using Yarn.Unity;
|
||||
|
||||
internal class CommandsCollection : IActionRegistration
|
||||
{
|
||||
public List<Actions.CommandRegistration> commandRegistrations = new List<Actions.CommandRegistration>();
|
||||
|
||||
public List<(string Name, Delegate Function)> functionRegistrations = new List<(string Name, Delegate Function)>();
|
||||
|
||||
public IEnumerable<CommandsWindow.IListItem> GetListItems()
|
||||
{
|
||||
foreach (var registrationMethod in Actions.ActionRegistrationMethods)
|
||||
{
|
||||
registrationMethod.Invoke(this, RegistrationType.Compilation);
|
||||
}
|
||||
|
||||
yield return new CommandsWindow.HeaderListItem("Commands");
|
||||
|
||||
foreach (var command in commandRegistrations)
|
||||
{
|
||||
yield return new CommandsWindow.CommandListItem(command);
|
||||
}
|
||||
|
||||
// Add a fake 'stop' command to the list, so that it appears in the
|
||||
// window
|
||||
System.Action fakeStop = () => { };
|
||||
yield return new CommandsWindow.CommandListItem(new Actions.CommandRegistration("stop", fakeStop));
|
||||
}
|
||||
|
||||
public void AddCommandHandler(string commandName, Delegate handler)
|
||||
{
|
||||
commandRegistrations.Add(new Actions.CommandRegistration(commandName, handler));
|
||||
|
||||
}
|
||||
|
||||
public void AddCommandHandler(string commandName, MethodInfo methodInfo)
|
||||
{
|
||||
commandRegistrations.Add(new Actions.CommandRegistration(commandName, methodInfo));
|
||||
}
|
||||
|
||||
public void AddFunction(string name, Delegate implementation) => functionRegistrations.Add((name, implementation));
|
||||
|
||||
public void RemoveCommandHandler(string commandName)
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
public void RemoveFunction(string name)
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
public void RegisterFunctionDeclaration(string name, Type returnType, Type[] parameterTypes)
|
||||
{
|
||||
/* TODO: Implement */
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandsWindow : EditorWindow
|
||||
{
|
||||
public interface IListItem { string DisplayName { get; } }
|
||||
|
||||
public class HeaderListItem : IListItem
|
||||
{
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
public HeaderListItem(string displayName)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandListItem : IListItem
|
||||
{
|
||||
internal Actions.CommandRegistration Command;
|
||||
|
||||
internal CommandListItem(Actions.CommandRegistration command)
|
||||
{
|
||||
Command = command;
|
||||
}
|
||||
|
||||
public string DisplayName => Command.Name;
|
||||
}
|
||||
|
||||
[SerializeField] private VisualTreeAsset? uxml;
|
||||
[SerializeField] private VisualTreeAsset? listItemUXML;
|
||||
[SerializeField] private StyleSheet? stylesheet;
|
||||
|
||||
private List<IListItem> listItems = new();
|
||||
private List<IListItem> filteredListItems = new();
|
||||
|
||||
[MenuItem("Window/Yarn Spinner/Commands...")]
|
||||
static void Summon()
|
||||
{
|
||||
var window = GetWindow<CommandsWindow>("Yarn Commands");
|
||||
window.Show();
|
||||
}
|
||||
|
||||
void CreateGUI()
|
||||
{
|
||||
if (uxml == null)
|
||||
{
|
||||
Debug.LogWarning($"{GetType()}'s {nameof(uxml)} is null");
|
||||
return;
|
||||
}
|
||||
uxml.CloneTree(rootVisualElement);
|
||||
var listView = rootVisualElement.Q<ListView>();
|
||||
|
||||
var searchField = rootVisualElement.Q<UnityEditor.UIElements.ToolbarSearchField>();
|
||||
|
||||
searchField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
UpdateFilter(listView, searchField.value);
|
||||
});
|
||||
|
||||
var commandsCollection = new CommandsCollection();
|
||||
|
||||
listItems = new List<IListItem>(commandsCollection.GetListItems().OrderBy(item => item.DisplayName));
|
||||
|
||||
UpdateFilter(listView, searchField.value);
|
||||
|
||||
// Set ListView.makeItem to initialize each entry in the list.
|
||||
listView.makeItem = () =>
|
||||
{
|
||||
if (listItemUXML == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Can't create new list item: {nameof(listItemUXML)} is null");
|
||||
}
|
||||
|
||||
var result = listItemUXML.CloneTree();
|
||||
result.styleSheets.Add(stylesheet);
|
||||
result.AddToClassList("commandListItem");
|
||||
return result;
|
||||
};
|
||||
|
||||
// Set ListView.bindItem to bind an initialized entry to a data item.
|
||||
listView.bindItem = (VisualElement element, int index) =>
|
||||
{
|
||||
var listItem = filteredListItems[index];
|
||||
element.Q<Label>("Title").text = listItem.DisplayName;
|
||||
|
||||
element.RemoveFromClassList("header");
|
||||
element.RemoveFromClassList("command");
|
||||
if (listItem is HeaderListItem)
|
||||
{
|
||||
element.AddToClassList("header");
|
||||
}
|
||||
else if (listItem is CommandListItem command)
|
||||
{
|
||||
element.AddToClassList("command");
|
||||
element.Q<Label>("Subtitle").text = "<<" + command.Command.UsageString + ">>";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void UpdateFilter(ListView listView, string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
filteredListItems = listItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
filteredListItems = listItems.Where(item =>
|
||||
{
|
||||
if (item is HeaderListItem)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (item is CommandListItem command)
|
||||
{
|
||||
return command.Command.Name.IndexOf(value, StringComparison.InvariantCultureIgnoreCase) != -1;
|
||||
}
|
||||
return true;
|
||||
}).ToList();
|
||||
}
|
||||
listView.itemsSource = filteredListItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 280f575059ceb49eabeb009efa8936bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_ViewDataDictionary: {instanceID: 0}
|
||||
- uxml: {fileID: 9197481963319205126, guid: e71e992188faa4d22b8bdd4b60f0b7bf, type: 3}
|
||||
- listItemUXML: {fileID: 9197481963319205126, guid: 90cfaddaa17c84dc79cd95f4448553b2, type: 3}
|
||||
- stylesheet: {fileID: 7433441132597879392, guid: f8653a3e6bb8c4c45aa986ef57baedbb, type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
.header #Title {
|
||||
-unity-font-style: bold;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.command {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.header #Subtitle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.command #Subtitle {
|
||||
white-space: normal;
|
||||
padding-left: 20px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8653a3e6bb8c4c45aa986ef57baedbb
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
@@ -0,0 +1,6 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
||||
<uie:Toolbar>
|
||||
<uie:ToolbarSearchField focusable="true" style="flex-grow: 1;" />
|
||||
</uie:Toolbar>
|
||||
<ui:ListView focusable="true" fixed-item-height="20" selection-type="None" virtualization-method="DynamicHeight" />
|
||||
</ui:UXML>
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e71e992188faa4d22b8bdd4b60f0b7bf
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d3f060740e1c4baab87c4307c7cc019
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/dev.yarnspinner.unity/Editor/Editors/Icons.meta
Normal file
8
Packages/dev.yarnspinner.unity/Editor/Editors/Icons.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e99b606795f943c1a4d8bbe8d7fef51
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 913322bbd06594c5a8f72636b1a06060
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37811d3829b0bfc42bfcd782271d279f
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 1
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2cbba4ddd142149b0a38697070990deb
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 1
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd59b44bd3514406197f8ceb53547969
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 1
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6a533d9225cd40ea9ded31d4f686e3b
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 1
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ed312066ea6f40f6af965f21c818b34
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 1
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Packages/dev.yarnspinner.unity/Editor/Editors/Icons/YarnSpinnerEditorWindow.psd
LFS
Normal file
BIN
Packages/dev.yarnspinner.unity/Editor/Editors/Icons/YarnSpinnerEditorWindow.psd
LFS
Normal file
Binary file not shown.
@@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5eb29ddb696b54505b296d1c7a049150
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 1
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Packages/dev.yarnspinner.unity/Editor/Editors/Icons/YarnSpinnerLogo.png
LFS
Normal file
BIN
Packages/dev.yarnspinner.unity/Editor/Editors/Icons/YarnSpinnerLogo.png
LFS
Normal file
Binary file not shown.
@@ -0,0 +1,127 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 528a6dd601766934abb8b1053bd798ef
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 1
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Packages/dev.yarnspinner.unity/Editor/Editors/Icons/YarnSpinnerLogoFull.png
LFS
Normal file
BIN
Packages/dev.yarnspinner.unity/Editor/Editors/Icons/YarnSpinnerLogoFull.png
LFS
Normal file
Binary file not shown.
@@ -0,0 +1,117 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16f8cd23bf0d0480bb8ecc39be853cda
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
|
||||
[CustomEditor(typeof(InMemoryVariableStorage))]
|
||||
public class InMemoryVariableStorageEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
var varStorage = (InMemoryVariableStorage)target;
|
||||
|
||||
varStorage.showDebug = EditorGUILayout.Foldout(varStorage.showDebug, "Debug Variables");
|
||||
|
||||
if (!varStorage.showDebug)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Not in Play Mode, so no variables to display!", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
var style = EditorStyles.label;
|
||||
var list = varStorage.GetDebugList();
|
||||
var height = style.CalcHeight(new GUIContent(list), EditorGUIUtility.currentViewWidth);
|
||||
EditorGUILayout.SelectableLabel(list, GUILayout.MaxHeight(height), GUILayout.ExpandHeight(true));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 230a34f0c8ffc4b45b5f098c65d69492
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
145
Packages/dev.yarnspinner.unity/Editor/Editors/LanguagePopup.cs
Normal file
145
Packages/dev.yarnspinner.unity/Editor/Editors/LanguagePopup.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
public class LanguageField : BaseField<string>
|
||||
{
|
||||
PopupField<string?> m_Popup;
|
||||
TextField m_TextField;
|
||||
|
||||
Dictionary<string, Culture> KnownCultures = new Dictionary<string, Culture>();
|
||||
CultureInfo? DefaultCulture;
|
||||
|
||||
public LanguageField() : this(null, false) { }
|
||||
|
||||
|
||||
public LanguageField(string? label, bool onlyNeutralCultures = false) : base(label, new Label() { })
|
||||
{
|
||||
var container = new VisualElement();
|
||||
container.style.flexDirection = FlexDirection.Column;
|
||||
container.style.flexGrow = 1;
|
||||
Add(container);
|
||||
// This is the input element instantiated for the base constructor.
|
||||
|
||||
KnownCultures = Cultures.GetCultures().Where(c => !onlyNeutralCultures || c.IsNeutralCulture).ToDictionary(kv => kv.Name);
|
||||
|
||||
DefaultCulture = System.Globalization.CultureInfo.CurrentCulture;
|
||||
|
||||
if (onlyNeutralCultures && DefaultCulture.IsNeutralCulture == false)
|
||||
{
|
||||
DefaultCulture = DefaultCulture.Parent;
|
||||
}
|
||||
|
||||
var cultureChoices = KnownCultures.Keys.Prepend(null).ToList();
|
||||
|
||||
static string FormatCulture(string? cultureName)
|
||||
{
|
||||
if (cultureName == null)
|
||||
{
|
||||
return "Custom";
|
||||
}
|
||||
else
|
||||
{
|
||||
return Cultures.TryGetCulture(cultureName, out var culture)
|
||||
? $"{culture.DisplayName} ({culture.Name})"
|
||||
: cultureName;
|
||||
}
|
||||
}
|
||||
|
||||
m_Popup = new PopupField<string?>(null, cultureChoices, DefaultCulture.Name, FormatCulture, FormatCulture);
|
||||
|
||||
m_Popup.style.flexGrow = 1;
|
||||
|
||||
m_Popup.RegisterValueChangedCallback(OnPopupValueChanged);
|
||||
|
||||
container.Add(m_Popup);
|
||||
|
||||
m_TextField = new TextField();
|
||||
m_TextField.style.flexGrow = 1;
|
||||
m_TextField.RegisterValueChangedCallback(OnTextFieldValueChanged);
|
||||
container.Add(m_TextField);
|
||||
|
||||
m_Popup.style.marginRight = 0;
|
||||
m_TextField.style.marginRight = 0;
|
||||
|
||||
this.style.flexGrow = 1;
|
||||
|
||||
//m_Input.RegisterValueChangedCallback(OnValueChanged);
|
||||
//m_Input2.RegisterValueChangedCallback(OnValueChanged);
|
||||
}
|
||||
|
||||
public override string value
|
||||
{
|
||||
get => base.value; set
|
||||
{
|
||||
Debug.Log($"Language value changed from {base.value} to {value}");
|
||||
base.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
void OnTextFieldValueChanged(ChangeEvent<string> evt)
|
||||
{
|
||||
this.value = evt.newValue;
|
||||
}
|
||||
|
||||
void OnPopupValueChanged(ChangeEvent<string?> evt)
|
||||
{
|
||||
if (evt.newValue != null)
|
||||
{
|
||||
this.value = evt.newValue;
|
||||
m_TextField.style.display = DisplayStyle.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The popup has changed to the 'custom' value; show the text field
|
||||
m_TextField.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetValueWithoutNotify(string newValue)
|
||||
{
|
||||
m_TextField.value = newValue;
|
||||
|
||||
if (m_TextField.focusController?.focusedElement == m_TextField)
|
||||
{
|
||||
// The text field has focus; do not change its visibility
|
||||
}
|
||||
else
|
||||
{
|
||||
m_TextField.style.display = (!KnownCultures.ContainsKey(newValue) || m_Popup.value == null) ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
}
|
||||
|
||||
if (KnownCultures.ContainsKey(newValue))
|
||||
{
|
||||
m_Popup.SetValueWithoutNotify(newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Popup.SetValueWithoutNotify(null);
|
||||
}
|
||||
|
||||
base.SetValueWithoutNotify(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LanguagePopup
|
||||
{
|
||||
// TODO: Remove, not needed in Unity 2022
|
||||
public static T ReplaceElement<T>(VisualElement oldElement, T newElement) where T : VisualElement
|
||||
{
|
||||
oldElement.parent.Insert(oldElement.parent.IndexOf(oldElement) + 1, newElement);
|
||||
oldElement.RemoveFromHierarchy();
|
||||
return newElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afcc06473aee040aa87e08d80c09c981
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity.Attributes;
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
|
||||
[CustomPropertyDrawer(typeof(LanguageAttribute))]
|
||||
public class LanguageAttributeEditor : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
using (var scope = new EditorGUI.PropertyScope(position, label, property))
|
||||
{
|
||||
// If this property is not a string, show an error label. (We
|
||||
// can't call EditorGUI.PropertyField, because that would cause
|
||||
// an infinite recursion - Unity would invoke this property
|
||||
// drawer again.)
|
||||
if (property.propertyType != SerializedPropertyType.String)
|
||||
{
|
||||
EditorGUI.HelpBox(position, $"{property.name} is not a string.", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Display this property as a dropdown that lets you select a
|
||||
// language.
|
||||
var allCultures = Cultures.GetCultures().ToList();
|
||||
var indices = Enumerable.Range(0, allCultures.Count());
|
||||
|
||||
var culturesToIndicies = allCultures.Zip(indices, (culture, index) => new { culture, index }).ToDictionary(pair => pair.culture.Name, pair => pair.index);
|
||||
|
||||
var value = property.stringValue;
|
||||
|
||||
int currentCultureIndex;
|
||||
|
||||
if (culturesToIndicies.ContainsKey(value))
|
||||
{
|
||||
currentCultureIndex = culturesToIndicies[value];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The property doesn't contain a valid culture name. Show
|
||||
// an 'empty' value, which will be replaced when the user
|
||||
// selects a valid value from the dropdown.
|
||||
currentCultureIndex = -1;
|
||||
}
|
||||
|
||||
var allCultureDisplayNames = allCultures.Select(c => (c.DisplayName + $":({c.Name})")).Select(n => new GUIContent(n)).ToArray();
|
||||
|
||||
using (var changeCheck = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
var selectedIndex = EditorGUI.Popup(position, label, currentCultureIndex, allCultureDisplayNames);
|
||||
if (changeCheck.changed)
|
||||
{
|
||||
property.stringValue = allCultures[selectedIndex].Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 321b50cd267214a08ba7310de9a39764
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
#if USE_ADDRESSABLES
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEditor.AddressableAssets;
|
||||
#endif
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
internal class ImportLocalizationFromAssetWindow : EditorWindow
|
||||
{
|
||||
private System.Type? assetType;
|
||||
|
||||
public LocalizationEditor? Target { get; private set; }
|
||||
|
||||
public string FieldLabel { get; set; } = "Source Asset";
|
||||
public string? HelpBox { get; set; }
|
||||
|
||||
public static ImportLocalizationFromAssetWindow Show<T>(LocalizationEditor target, string windowTitle, System.Action<T> onImport) where T : UnityEngine.Object
|
||||
{
|
||||
var window = EditorWindow.GetWindow<ImportLocalizationFromAssetWindow>(true, windowTitle);
|
||||
window.Target = target;
|
||||
window.assetType = typeof(T);
|
||||
window.maxSize = new Vector2(300, 200);
|
||||
window.onImport = (Object obj) => onImport((T)obj);
|
||||
window.ShowUtility();
|
||||
return window;
|
||||
}
|
||||
|
||||
UnityEngine.Object? asset = null;
|
||||
private System.Action<UnityEngine.Object>? onImport;
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (Target == null)
|
||||
{
|
||||
// Our target went away; close this window
|
||||
this.Close();
|
||||
}
|
||||
|
||||
asset = EditorGUILayout.ObjectField(FieldLabel, asset, assetType, allowSceneObjects: false);
|
||||
|
||||
if (string.IsNullOrEmpty(this.HelpBox) == false)
|
||||
{
|
||||
EditorGUILayout.HelpBox(this.HelpBox, MessageType.Info);
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
using (new EditorGUI.DisabledScope(asset == null))
|
||||
{
|
||||
if (GUILayout.Button("Import") && asset != null)
|
||||
{
|
||||
onImport?.Invoke(asset);
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[CustomEditor(typeof(Localization))]
|
||||
[CanEditMultipleObjects]
|
||||
public class LocalizationEditor : UnityEditor.Editor
|
||||
{
|
||||
private SerializedProperty? entriesProperty;
|
||||
private SerializedProperty? usesUnityAddressablesProperty;
|
||||
private AudioClip? lastPreviewed;
|
||||
private List<Culture>? cultures;
|
||||
private int currentPickerWindow;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
entriesProperty = serializedObject.FindProperty(nameof(Localization.entries));
|
||||
usesUnityAddressablesProperty = serializedObject.FindProperty(nameof(Localization._usesAddressableAssets));
|
||||
lastPreviewed = null;
|
||||
cultures = Cultures.GetCultures().ToList();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var target = this.target as Localization;
|
||||
if (target == null)
|
||||
{
|
||||
throw new System.InvalidOperationException($"Target is not a {typeof(Localization)}");
|
||||
}
|
||||
|
||||
var isSubAsset = AssetDatabase.IsSubAsset(target);
|
||||
|
||||
if (serializedObject.isEditingMultipleObjects)
|
||||
{
|
||||
EditorGUILayout.HelpBox($"Select a single {nameof(Localization).ToLowerInvariant()} to view its contents.", MessageType.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isSubAsset)
|
||||
{
|
||||
DrawLocalizationContentsPreview(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if USE_ADDRESSABLES
|
||||
EditorGUILayout.PropertyField(usesUnityAddressablesProperty);
|
||||
EditorGUILayout.Space();
|
||||
#else
|
||||
if (usesUnityAddressablesProperty != null && usesUnityAddressablesProperty.boolValue)
|
||||
{
|
||||
EditorGUILayout.HelpBox("This Localization uses Unity Addressables, but the package is not installed.", MessageType.Warning);
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
#endif
|
||||
if (GUILayout.Button("Import String from Yarn Project"))
|
||||
{
|
||||
var window = ImportLocalizationFromAssetWindow.Show<YarnProject>(this, "Import from Yarn Project", ImportFromYarnProject);
|
||||
window.FieldLabel = "Yarn Project";
|
||||
window.HelpBox = $"The lines in the base localisation of the selected Yarn Project will be imported into this {nameof(Localization)}.";
|
||||
}
|
||||
if (GUILayout.Button("Import Strings from CSV"))
|
||||
{
|
||||
var window = ImportLocalizationFromAssetWindow.Show<TextAsset>(this, "Import from Yarn Project", ImportFromCSV);
|
||||
window.FieldLabel = "CSV File";
|
||||
window.HelpBox = $"The string table entries from the selected CSV file will be imported into this {nameof(Localization)}.\n\nYou can generate a CSV file to use by selecting the Yarn Project and clicking {YarnProjectImporterEditor.AddStringTagsButtonLabel}. You can then translate the CSV file into your target language, and then import it using this window.";
|
||||
}
|
||||
if (GUILayout.Button("Import Assets from Folder"))
|
||||
{
|
||||
var window = ImportLocalizationFromAssetWindow.Show<DefaultAsset>(this, "Import from Yarn Project", (folder) =>
|
||||
{
|
||||
var lineIDs = target.entries.Keys;
|
||||
var paths = YarnProjectUtility.FindAssetPathsForLineIDs(lineIDs, AssetDatabase.GetAssetPath(folder), typeof(UnityEngine.Object));
|
||||
foreach (var path in paths)
|
||||
{
|
||||
var lineID = path.Key;
|
||||
var assetPath = path.Value;
|
||||
|
||||
var asset = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(assetPath);
|
||||
target.AddLocalizedObjectToAsset<UnityEngine.Object>(lineID, asset);
|
||||
|
||||
#if USE_ADDRESSABLES
|
||||
if (target.UsesAddressableAssets)
|
||||
{
|
||||
// If we're using addressable assets, make
|
||||
// sure that the asset we just added has an
|
||||
// address
|
||||
EnsureAssetIsAddressable(asset, Localization.GetAddressForLine(lineID, target.name));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
serializedObject.Update();
|
||||
|
||||
EditorUtility.SetDirty(target);
|
||||
AssetDatabase.SaveAssetIfDirty(target);
|
||||
});
|
||||
window.FieldLabel = "Folder";
|
||||
}
|
||||
EditorGUILayout.PropertyField(entriesProperty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (serializedObject.hasModifiedProperties)
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays the contents of <paramref name="target"/> as a table.
|
||||
/// </summary>
|
||||
/// <param name="target">The <see cref="Localization"/> to show the
|
||||
/// contents of.</param>
|
||||
/// <param name="showAssets">If true, this method will show any
|
||||
/// assets or addressable assets. If false, this method will only
|
||||
/// show the localized text.</param>
|
||||
private void DrawLocalizationContentsPreview(Localization target)
|
||||
{
|
||||
var lineKeys = target.GetLineIDs();
|
||||
|
||||
// Early out if we don't have any lines
|
||||
if (lineKeys.Count() == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox($"This {nameof(Localization).ToLowerInvariant()} does not contain any lines.", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
var localizedLineContent = new List<(string ID, string Line, Object? Asset)>();
|
||||
|
||||
var anyAssetsFound = false;
|
||||
|
||||
foreach (var key in lineKeys)
|
||||
{
|
||||
|
||||
if (target.entries.TryGetValue(key, out var entry) == false)
|
||||
{
|
||||
// We somehow don't have a value for this line ID?
|
||||
Debug.LogError($"Internal error: failed to find an entry for {key}");
|
||||
EditorGUILayout.HelpBox($"Internal error: failed to find an entry for {key}", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string? text = target.GetLocalizedString(key);
|
||||
Object? asset = null;
|
||||
|
||||
if (target.UsesAddressableAssets)
|
||||
{
|
||||
#if USE_ADDRESSABLES
|
||||
asset = entry.localizedAssetReference?.editorAsset;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
asset = entry.localizedAsset;
|
||||
}
|
||||
|
||||
anyAssetsFound |= asset != null;
|
||||
|
||||
localizedLineContent.Add((key, text ?? string.Empty, asset));
|
||||
}
|
||||
|
||||
foreach (var entry in localizedLineContent)
|
||||
{
|
||||
|
||||
var idContent = new GUIContent(entry.ID);
|
||||
|
||||
// Create a GUIContent that contains the string as its text
|
||||
// and also as its tooltip. This allows the user to mouse
|
||||
// over this line in the inspector and see more of it.
|
||||
var lineContent = new GUIContent(entry.Line, entry.Line);
|
||||
|
||||
// Show the line ID and localized text
|
||||
EditorGUILayout.LabelField(idContent, lineContent);
|
||||
|
||||
if (entry.Asset != null)
|
||||
{
|
||||
// Asset references are never editable here - they're
|
||||
// only updated by the Localization Database. Add a
|
||||
// DisabledGroup here to make all ObjectFields be
|
||||
// interactable, but read-only.
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
|
||||
// Show the object field
|
||||
EditorGUILayout.ObjectField(" ", entry.Asset, typeof(UnityEngine.Object), false);
|
||||
|
||||
// for AudioClips, add a little play preview button
|
||||
if (entry.Asset.GetType() == typeof(UnityEngine.AudioClip))
|
||||
{
|
||||
var rect = GUILayoutUtility.GetLastRect();
|
||||
|
||||
// Localization assets are displayed in an
|
||||
// Inspector that's always disabled, so we need to
|
||||
// manually set the enabled flag to 'true' in order
|
||||
// to let this button be clickable. We'll restore
|
||||
// it after we handle this button.
|
||||
var wasEnabled = GUI.enabled;
|
||||
GUI.enabled = true;
|
||||
|
||||
bool isPlaying = IsClipPlaying((AudioClip)entry.Asset);
|
||||
if (lastPreviewed == (AudioClip)entry.Asset && isPlaying)
|
||||
{
|
||||
rect.width = 54;
|
||||
rect.x += EditorGUIUtility.labelWidth - 56;
|
||||
|
||||
if (GUI.Button(rect, "▣ Stop"))
|
||||
{
|
||||
StopAllClips();
|
||||
lastPreviewed = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.width = 18;
|
||||
rect.x += EditorGUIUtility.labelWidth - 20;
|
||||
if (GUI.Button(rect, "▸"))
|
||||
{
|
||||
PlayClip((AudioClip)entry.Asset);
|
||||
lastPreviewed = (AudioClip)entry.Asset;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the enabled state
|
||||
GUI.enabled = wasEnabled;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
else if (anyAssetsFound)
|
||||
{
|
||||
// Other entries have assets, but not this one. TODO:
|
||||
// show a warning? probably need to make it really
|
||||
// prominent, and possibly allow filtering this view to
|
||||
// show only lines that have no assets?
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// below is some terrible reflection needed for the AudioClip
|
||||
// preview terrible hack from
|
||||
// https://forum.unity.com/threads/way-to-play-audio-in-editor-using-an-editor-script.132042/#post-4767824
|
||||
public static void PlayClip(AudioClip clip, int startSample = 0, bool loop = false)
|
||||
{
|
||||
System.Reflection.Assembly unityEditorAssembly = typeof(AudioImporter).Assembly;
|
||||
System.Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil");
|
||||
|
||||
// The name of the method we want to invoke changed in 2020.2,
|
||||
// so we'll do a little version testing here
|
||||
string methodName;
|
||||
|
||||
methodName = "PlayPreviewClip";
|
||||
|
||||
System.Reflection.MethodInfo method = audioUtilClass.GetMethod(
|
||||
methodName,
|
||||
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public,
|
||||
null,
|
||||
new System.Type[] { typeof(AudioClip), typeof(int), typeof(bool) },
|
||||
null
|
||||
);
|
||||
method.Invoke(
|
||||
null,
|
||||
new object[] { clip, startSample, loop }
|
||||
);
|
||||
}
|
||||
|
||||
public static void StopAllClips()
|
||||
{
|
||||
System.Reflection.Assembly unityEditorAssembly = typeof(AudioImporter).Assembly;
|
||||
System.Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil");
|
||||
|
||||
// The name of the method we want to invoke changed in 2020.2,
|
||||
// so we'll do a little version testing here
|
||||
string methodName = "StopAllPreviewClips";
|
||||
|
||||
System.Reflection.MethodInfo method = audioUtilClass.GetMethod(
|
||||
methodName,
|
||||
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public,
|
||||
null,
|
||||
new System.Type[] { },
|
||||
null
|
||||
);
|
||||
method.Invoke(
|
||||
null,
|
||||
new object[] { }
|
||||
);
|
||||
}
|
||||
|
||||
public static bool IsClipPlaying(AudioClip clip)
|
||||
{
|
||||
System.Reflection.Assembly unityEditorAssembly = typeof(AudioImporter).Assembly;
|
||||
System.Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil");
|
||||
|
||||
System.Reflection.MethodInfo method = audioUtilClass.GetMethod(
|
||||
"IsPreviewClipPlaying",
|
||||
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public
|
||||
);
|
||||
return (bool)method.Invoke(
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
internal void ImportFromYarnProject(YarnProject project)
|
||||
{
|
||||
var target = this.target as Localization;
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var lineIDs = project.baseLocalization.GetLineIDs();
|
||||
|
||||
target.UsesAddressableAssets = project.baseLocalization.UsesAddressableAssets;
|
||||
|
||||
foreach (var (id, entry) in project.baseLocalization.entries)
|
||||
{
|
||||
var localizedString = entry.localizedString;
|
||||
if (localizedString != null)
|
||||
{
|
||||
target.AddLocalisedStringToAsset(id, localizedString);
|
||||
}
|
||||
|
||||
Object? asset = null;
|
||||
|
||||
if (project.baseLocalization.UsesAddressableAssets)
|
||||
{
|
||||
#if USE_ADDRESSABLES
|
||||
asset = entry.localizedAssetReference?.editorAsset;
|
||||
#endif
|
||||
}
|
||||
else if (entry.localizedAsset != null)
|
||||
{
|
||||
asset = entry.localizedAsset;
|
||||
}
|
||||
|
||||
if (asset != null)
|
||||
{
|
||||
target.AddLocalizedObjectToAsset(id, asset);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
EditorUtility.SetDirty(target);
|
||||
AssetDatabase.SaveAssetIfDirty(target);
|
||||
}
|
||||
|
||||
internal void ImportFromCSV(TextAsset asset)
|
||||
{
|
||||
var target = this.target as Localization;
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var stringTable = StringTableEntry.ParseFromCSV(asset.text);
|
||||
|
||||
foreach (var entry in stringTable)
|
||||
{
|
||||
target.AddLocalisedStringToAsset(entry.ID, entry.Text ?? string.Empty);
|
||||
}
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
EditorUtility.SetDirty(target);
|
||||
AssetDatabase.SaveAssetIfDirty(target);
|
||||
|
||||
}
|
||||
catch (System.ArgumentException e)
|
||||
{
|
||||
Debug.LogWarning($"Failed to import localization from CSV because an error was encountered during text parsing: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_ADDRESSABLES
|
||||
internal static void EnsureAssetIsAddressable(Object asset, string defaultAddress)
|
||||
{
|
||||
if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(asset, out string guid, out long _) == false)
|
||||
{
|
||||
Debug.LogError($"Can't make {asset} addressable: no GUID found", asset);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the existing entry for this asset, if it has one.
|
||||
UnityEditor.AddressableAssets.Settings.AddressableAssetEntry entry = AddressableAssetSettingsDefaultObject.Settings.FindAssetEntry(guid);
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
// The asset already has an entry. Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
// This asset didn't have an entry. Create one in the default group.
|
||||
Debug.Log($"Marking asset {AssetDatabase.GetAssetPath(asset)} as addressable", asset);
|
||||
|
||||
entry = AddressableAssetSettingsDefaultObject.Settings.CreateOrMoveEntry(guid, AddressableAssetSettingsDefaultObject.Settings.DefaultGroup);
|
||||
|
||||
// Update the entry's address.
|
||||
entry.SetAddress(defaultAddress);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d221cff8c71dc4726a348d8b718becaa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user