chore(sdk): add SDK to project
8
Assets/ExternalDependencyManager.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c76035eb5ca0b504e9909b48a3b96131
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/ExternalDependencyManager/Editor.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5520642325e02e846ab317a30ab5ec46
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/ExternalDependencyManager/Editor/1.2.186.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3c7b44f7ef02738429b2850a72b59b60
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e2d7ea0845de4cf984265d2a444b7aa4
|
||||
labels:
|
||||
- gvh
|
||||
- gvh_version-1.2.186
|
||||
- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.186/Google.IOSResolver.dll
|
||||
- gvhp_targets-editor
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 3
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 0
|
||||
platformData:
|
||||
Any:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
Editor:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
WindowsStoreApps:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fa49a85d4ba140a0ae21528ed12d174c
|
||||
labels:
|
||||
- gvh
|
||||
- gvh_version-1.2.186
|
||||
- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.186/Google.JarResolver.dll
|
||||
- gvhp_targets-editor
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 3
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
Any:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
Editor:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
WindowsStoreApps:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d8bb10c56a0147bc855a6296778e025e
|
||||
labels:
|
||||
- gvh
|
||||
- gvh_version-1.2.186
|
||||
- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.186/Google.PackageManagerResolver.dll
|
||||
- gvhp_targets-editor
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 3
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
Any:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
Editor:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
WindowsStoreApps:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5980a684c61d42fbb6b74e2eb3477016
|
||||
labels:
|
||||
- gvh
|
||||
- gvh_version-1.2.186
|
||||
- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.186/Google.VersionHandlerImpl.dll
|
||||
- gvhp_targets-editor
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 3
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
Any:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
Editor:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
WindowsStoreApps:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1430
Assets/ExternalDependencyManager/Editor/CHANGELOG.md
Normal file
12
Assets/ExternalDependencyManager/Editor/CHANGELOG.md.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: aba4ee01c6d145f7bf2d944d892f709a
|
||||
labels:
|
||||
- gvh
|
||||
- gvh_version-1.2.186
|
||||
- gvhp_exportpath-ExternalDependencyManager/Editor/CHANGELOG.md
|
||||
timeCreated: 1584567712
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f7632a50b10045458c53a5ddf7b6d238
|
||||
labels:
|
||||
- gvh
|
||||
- gvh_version-1.2.186
|
||||
- gvhp_exportpath-ExternalDependencyManager/Editor/Google.VersionHandler.dll
|
||||
- gvhp_targets-editor
|
||||
timeCreated: 1480838400
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
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:
|
||||
245
Assets/ExternalDependencyManager/Editor/LICENSE
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
Copyright (C) 2014 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
====================================================================================================
|
||||
This package uses MiniJSON
|
||||
|
||||
Copyright (c) 2013 Calvin Rien
|
||||
|
||||
Based on the JSON parser by Patrick van Bergen
|
||||
http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
|
||||
|
||||
Simplified it so that it doesn't throw exceptions
|
||||
and can be used in Unity iPhone with maximum code stripping.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
12
Assets/ExternalDependencyManager/Editor/LICENSE.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ae8b2bc8d1ac4ad48f0ab2b2e7ac75fb
|
||||
labels:
|
||||
- gvh
|
||||
- gvh_version-1.2.186
|
||||
- gvhp_exportpath-ExternalDependencyManager/Editor/LICENSE
|
||||
timeCreated: 1584567712
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
903
Assets/ExternalDependencyManager/Editor/README.md
Normal file
|
|
@ -0,0 +1,903 @@
|
|||
# External Dependency Manager for Unity
|
||||
|
||||
[](https://openupm.com/packages/com.google.external-dependency-manager/)
|
||||
[](https://openupm.com/packages/com.google.external-dependency-manager/)
|
||||
|
||||
## Overview
|
||||
|
||||
The External Dependency Manager for Unity (EDM4U) (formerly Play Services
|
||||
Resolver/Jar Resolver) is intended to be used by any Unity package or user that
|
||||
requires:
|
||||
|
||||
* Android specific libraries (e.g
|
||||
[AARs](https://developer.android.com/studio/projects/android-library.html))
|
||||
|
||||
* iOS [CocoaPods](https://cocoapods.org/)
|
||||
|
||||
* Version management of transitive dependencies
|
||||
|
||||
* Management of Package Manager (PM) Registries
|
||||
|
||||
If you want to add and use iOS/Android dependencies directly in your project,
|
||||
then you should to install EDM4U in your project.
|
||||
|
||||
If you are a package user and the plugin you are using depends on EDM4U, *and*
|
||||
the package does not include EDM4U as a package dependency already, then you
|
||||
should to install EDM4U in your project.
|
||||
|
||||
If you are a UPM package maintainer and your package requires EDM4U, then you
|
||||
should add EDM4U as a
|
||||
[package dependency](https://docs.unity3d.com/2019.3/Documentation/Manual/upm-dependencies.html)
|
||||
in your package manifest (`package.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"com.google.external-dependency-manager": "1.2.178"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You should still install EDM4U to test out the package during development.
|
||||
|
||||
If you are a legacy `.unitypackage` package maintainer and your package requires
|
||||
EDM4U, please ask the user to install EDM4U separately. You should install EDM4U
|
||||
to test out the package during development.
|
||||
|
||||
Updated releases are available on
|
||||
[GitHub](https://github.com/googlesamples/unity-jar-resolver)
|
||||
|
||||
## Requirements
|
||||
|
||||
The *Android Resolver* and *iOS Resolver* components of the plugin only work
|
||||
with Unity version 4.6.8 or higher.
|
||||
|
||||
The *Version Handler* component only works with Unity 5.x or higher as it
|
||||
depends upon the `PluginImporter` UnityEditor API.
|
||||
|
||||
The *Package Manager Resolver* component only works with Unity 2018.4 or above,
|
||||
when [scoped registry](https://docs.unity3d.com/Manual/upm-scoped.html) support
|
||||
was added to the Package Manager.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Check out [troubleshooting](troubleshooting-faq.md) if you need help.
|
||||
|
||||
### Install via OpenUPM
|
||||
|
||||
EDM4U is available on
|
||||
[OpenUPM](https://openupm.com/packages/com.google.external-dependency-manager/):
|
||||
|
||||
```shell
|
||||
openupm add com.google.external-dependency-manager
|
||||
```
|
||||
|
||||
### Install via git URL
|
||||
1. Open Package Manager
|
||||
2. Click on the + icon on the top left corner of the "Package Manager" screen
|
||||
3. Click on "Install package from git url..."
|
||||
4. Paste: https://github.com/googlesamples/unity-jar-resolver.git?path=upm
|
||||
|
||||
### Install via Google APIs for Unity
|
||||
|
||||
EDM4U is available both in UPM and legacy `.unitypackage` formats on
|
||||
[Google APIs for Unity](https://developers.google.com/unity/archive#external_dependency_manager_for_unity).
|
||||
|
||||
You may install the UPM version (.tgz) as a
|
||||
[local UPM package](https://docs.unity3d.com/Manual/upm-ui-local.html).
|
||||
|
||||
You can also install EDM4U in your project as a `.unitypackage`. This is not
|
||||
recommended due to potential conflicts.
|
||||
|
||||
### Conflict Resolution
|
||||
|
||||
For historical reasons, a package maintainer may choose to embed EDM4U in their
|
||||
package for ease of installation. This will create a conflict when you try to
|
||||
install EDM4U with the steps above, or with another package with embedded EDM4U.
|
||||
If your project imported a `.unitypackage` that has a copy of EDM4U embedded in
|
||||
it, you may safely delete it from your Assets folder. If your project depends on
|
||||
another UPM package with EDM4U, please reach out to the package maintainer and
|
||||
ask them to replace it with a dependency to this package. In the meantime, you
|
||||
can workaround the issue by copying the package to your Packages folder (to
|
||||
create an
|
||||
[embedded package](https://docs.unity3d.com/Manual/upm-concepts.html#Embedded))
|
||||
and perform the steps yourself to avoid a dependency conflict.
|
||||
|
||||
### Config file
|
||||
|
||||
To start adding dependencies to your project, copy and rename the
|
||||
[SampleDependencies.xml](https://github.com/googlesamples/unity-jar-resolver/blob/master/sample/Assets/ExternalDependencyManager/Editor/SampleDependencies.xml)
|
||||
file into your plugin and add the dependencies your project requires.
|
||||
|
||||
The XML file needs to be under an `Editor` directory and match the name
|
||||
`*Dependencies.xml`. For example, `MyPlugin/Editor/MyPluginDependencies.xml`.
|
||||
|
||||
## Usages
|
||||
|
||||
### Android Resolver
|
||||
|
||||
The Android Resolver copies specified dependencies from local or remote Maven
|
||||
repositories into the Unity project when a user selects Android as the build
|
||||
target in the Unity editor.
|
||||
|
||||
For example, to add the Google Play Games library
|
||||
(`com.google.android.gms:play-services-games` package) at version `9.8.0` to the
|
||||
set of a plugin's Android dependencies:
|
||||
|
||||
```xml
|
||||
<dependencies>
|
||||
<androidPackages>
|
||||
<androidPackage spec="com.google.android.gms:play-services-games:9.8.0">
|
||||
<androidSdkPackageIds>
|
||||
<androidSdkPackageId>extra-google-m2repository</androidSdkPackageId>
|
||||
</androidSdkPackageIds>
|
||||
</androidPackage>
|
||||
</androidPackages>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
The version specification (last component) supports:
|
||||
|
||||
* Specific versions e.g `9.8.0`
|
||||
|
||||
* Partial matches e.g `9.8.+` would match 9.8.0, 9.8.1 etc. choosing the most
|
||||
recent version
|
||||
|
||||
* Latest version using `LATEST` or `+`. We do *not* recommend using this
|
||||
unless you're 100% sure the library you depend upon will not break your
|
||||
Unity plugin in future
|
||||
|
||||
The above example specifies the dependency as a component of the Android SDK
|
||||
manager such that the Android SDK manager will be executed to install the
|
||||
package if it's not found. If your Android dependency is located on Maven
|
||||
central it's possible to specify the package simply using the `androidPackage`
|
||||
element:
|
||||
|
||||
```xml
|
||||
<dependencies>
|
||||
<androidPackages>
|
||||
<androidPackage spec="com.google.api-client:google-api-client-android:1.22.0" />
|
||||
</androidPackages>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
#### Auto-resolution
|
||||
|
||||
By default the Android Resolver automatically monitors the dependencies you have
|
||||
specified and the `Plugins/Android` folder of your Unity project. The resolution
|
||||
process runs when the specified dependencies are not present in your project.
|
||||
|
||||
The *auto-resolution* process can be disabled via the `Assets > External
|
||||
Dependency Manager > Android Resolver > Settings` menu.
|
||||
|
||||
Manual resolution can be performed using the following menu options:
|
||||
|
||||
* `Assets > External Dependency Manager > Android Resolver > Resolve`
|
||||
|
||||
* `Assets > External Dependency Manager > Android Resolver > Force Resolve`
|
||||
|
||||
#### Deleting libraries
|
||||
|
||||
Resolved packages are tracked via asset labels by the Android Resolver. They can
|
||||
easily be deleted using the `Assets > External Dependency Manager > Android
|
||||
Resolver > Delete Resolved Libraries` menu item.
|
||||
|
||||
#### Android Manifest Variable Processing
|
||||
|
||||
Some AAR files (for example play-services-measurement) contain variables that
|
||||
are processed by the Android Gradle plugin. Unfortunately, Unity does not
|
||||
perform the same processing when using Unity's Internal Build System, so the
|
||||
Android Resolver plugin handles known cases of this variable substitution by
|
||||
exploding the AAR into a folder and replacing `${applicationId}` with the
|
||||
`bundleID`.
|
||||
|
||||
Disabling AAR explosion and therefore Android manifest processing can be done
|
||||
via the `Assets > External Dependency Manager > Android Resolver > Settings`
|
||||
menu. You may want to disable explosion of AARs if you're exporting a project to
|
||||
be built with Gradle/Android Studio.
|
||||
|
||||
#### ABI Stripping
|
||||
|
||||
Some AAR files contain native libraries (.so files) for each ABI supported by
|
||||
Android. Unfortunately, when targeting a single ABI (e.g x86), Unity does not
|
||||
strip native libraries for unused ABIs. To strip unused ABIs, the Android
|
||||
Resolver plugin explodes an AAR into a folder and removes unused ABIs to reduce
|
||||
the built APK size. Furthermore, if native libraries are not stripped from an
|
||||
APK (e.g you have a mix of Unity's x86 library and some armeabi-v7a libraries)
|
||||
Android may attempt to load the wrong library for the current runtime ABI
|
||||
completely breaking your plugin when targeting some architectures.
|
||||
|
||||
AAR explosion and therefore ABI stripping can be disabled via the `Assets >
|
||||
External Dependency Manager > Android Resolver > Settings` menu. You may want to
|
||||
disable explosion of AARs if you're exporting a project to be built with
|
||||
Gradle/Android Studio.
|
||||
|
||||
#### Resolution Strategies
|
||||
|
||||
By default the Android Resolver will use Gradle to download dependencies prior
|
||||
to integrating them into a Unity project. This works with Unity's internal build
|
||||
system and Gradle/Android Studio project export.
|
||||
|
||||
It's possible to change the resolution strategy via the `Assets > External
|
||||
Dependency Manager > Android Resolver > Settings` menu.
|
||||
|
||||
##### Download Artifacts with Gradle
|
||||
|
||||
Using the default resolution strategy, the Android resolver executes the
|
||||
following operations:
|
||||
|
||||
- Remove the result of previous Android resolutions. E.g Delete all files and
|
||||
directories labeled with "gpsr" under `Plugins/Android` from the project.
|
||||
|
||||
- Collect the set of Android dependencies (libraries) specified by a project's
|
||||
`*Dependencies.xml` files.
|
||||
|
||||
- Run `download_artifacts.gradle` with Gradle to resolve conflicts and, if
|
||||
successful, download the set of resolved Android libraries (AARs, JARs).
|
||||
|
||||
- Process each AAR/JAR so that it can be used with the currently selected
|
||||
Unity build system (e.g Internal vs. Gradle, Export vs. No Export). This
|
||||
involves patching each reference to `applicationId` in the
|
||||
`AndroidManifest.xml` with the project's bundle ID. This means resolution
|
||||
must be run again if the bundle ID has changed.
|
||||
|
||||
- Move the processed AARs to `Plugins/Android` so they will be included when
|
||||
Unity invokes the Android build.
|
||||
|
||||
##### Integrate into mainTemplate.gradle
|
||||
|
||||
Unity 5.6 introduced support for customizing the `build.gradle` used to build
|
||||
Unity projects with Gradle. When the *Patch mainTemplate.gradle* setting is
|
||||
enabled, rather than downloading artifacts before the build, Android resolution
|
||||
results in the execution of the following operations:
|
||||
|
||||
- Remove the result of previous Android resolutions. E.g Delete all files and
|
||||
directories labeled with "gpsr" under `Plugins/Android` from the project and
|
||||
remove sections delimited with `// Android Resolver * Start` and `// Android
|
||||
Resolver * End` lines.
|
||||
|
||||
- Collect the set of Android dependencies (libraries) specified by a project's
|
||||
`*Dependencies.xml` files.
|
||||
|
||||
- Rename any `.srcaar` files in the build to `.aar` and exclude them from
|
||||
being included directly by Unity in the Android build as
|
||||
`mainTemplate.gradle` will be patched to include them instead from their
|
||||
local maven repositories.
|
||||
|
||||
- Inject the required Gradle repositories into `mainTemplate.gradle` at the
|
||||
line matching the pattern `.*apply plugin:
|
||||
'com\.android\.(application|library)'.*` or the section starting at the line
|
||||
`// Android Resolver Repos Start`. If you want to control the injection
|
||||
point in the file, the section delimited by the lines `// Android Resolver
|
||||
Repos Start` and `// Android Resolver Repos End` should be placed in the
|
||||
global scope before the `dependencies` section.
|
||||
|
||||
- Inject the required Android dependencies (libraries) into
|
||||
`mainTemplate.gradle` at the line matching the pattern `***DEPS***` or the
|
||||
section starting at the line `// Android Resolver Dependencies Start`. If
|
||||
you want to control the injection point in the file, the section delimited
|
||||
by the lines `// Android Resolver Dependencies Start` and `// Android
|
||||
Resolver Dependencies End` should be placed in the `dependencies` section.
|
||||
|
||||
- Inject the packaging options logic, which excludes architecture specific
|
||||
libraries based upon the selected build target, into `mainTemplate.gradle`
|
||||
at the line matching the pattern `android +{` or the section starting at the
|
||||
line `// Android Resolver Exclusions Start`. If you want to control the
|
||||
injection point in the file, the section delimited by the lines `// Android
|
||||
Resolver Exclusions Start` and `// Android Resolver Exclusions End` should
|
||||
be placed in the global scope before the `android` section.
|
||||
|
||||
#### Dependency Tracking
|
||||
|
||||
The Android Resolver creates the
|
||||
`ProjectSettings/AndroidResolverDependencies.xml` to quickly determine the set
|
||||
of resolved dependencies in a project. This is used by the auto-resolution
|
||||
process to only run the expensive resolution process when necessary.
|
||||
|
||||
#### Displaying Dependencies
|
||||
|
||||
It's possible to display the set of dependencies the Android Resolver would
|
||||
download and process in your project via the `Assets > External Dependency
|
||||
Manager > Android Resolver > Display Libraries` menu item.
|
||||
|
||||
### iOS Resolver
|
||||
|
||||
The iOS resolver component of this plugin manages
|
||||
[CocoaPods](https://cocoapods.org/). A CocoaPods `Podfile` is generated and the
|
||||
`pod` tool is executed as a post build process step to add dependencies to the
|
||||
Xcode project exported by Unity.
|
||||
|
||||
Dependencies for iOS are added by referring to CocoaPods.
|
||||
|
||||
For example, to add the AdMob pod, version 7.0 or greater with bitcode enabled:
|
||||
|
||||
```xml
|
||||
<dependencies>
|
||||
<iosPods>
|
||||
<iosPod name="Google-Mobile-Ads-SDK" version="~> 7.0" bitcodeEnabled="true"
|
||||
minTargetSdk="6.0" addToAllTargets="false" />
|
||||
</iosPods>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
#### Integration Strategies
|
||||
|
||||
The `CocoaPods` are either:
|
||||
|
||||
* Downloaded and injected into the Xcode project file directly, rather than
|
||||
creating a separate xcworkspace. We call this `Xcode project` integration.
|
||||
|
||||
* If the Unity version supports opening a xcworkspace file, the `pod` tool is
|
||||
used as intended to generate a xcworkspace which references the CocoaPods.
|
||||
We call this `Xcode workspace` integration.
|
||||
|
||||
The resolution strategy can be changed via the `Assets > External Dependency
|
||||
Manager > iOS Resolver > Settings` menu.
|
||||
|
||||
##### Appending text to generated Podfile
|
||||
|
||||
In order to modify the generated Podfile you can create a script like this:
|
||||
|
||||
```csharp
|
||||
using System.IO;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.Callbacks;
|
||||
using UnityEngine;
|
||||
|
||||
public class PostProcessIOS : MonoBehaviour
|
||||
{
|
||||
// Must be between 40 and 50 to ensure that it's not overriden by Podfile generation (40) and
|
||||
// that it's added before "pod install" (50).
|
||||
[PostProcessBuildAttribute(45)]
|
||||
private static void PostProcessBuild_iOS(BuildTarget target, string buildPath)
|
||||
{
|
||||
if (target == BuildTarget.iOS)
|
||||
{
|
||||
using (StreamWriter sw = File.AppendText(buildPath + "/Podfile"))
|
||||
{
|
||||
// E.g. add an app extension
|
||||
sw.WriteLine("\ntarget 'NSExtension' do\n pod 'Firebase/Messaging', '6.6.0'\nend");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Package Manager Resolver
|
||||
|
||||
Adding registries to the
|
||||
[Package Manager](https://docs.unity3d.com/Manual/Packages.html) (PM) is a
|
||||
manual process. The Package Manager Resolver (PMR) component of this plugin
|
||||
makes it easy for plugin maintainers to distribute new PM registry servers and
|
||||
easy for plugin users to manage PM registry servers.
|
||||
|
||||
#### Adding Registries
|
||||
|
||||
For example, to add a registry for plugins in the scope `com.coolstuff`:
|
||||
|
||||
```xml
|
||||
<registries>
|
||||
<registry name="Cool Stuff"
|
||||
url="https://unityregistry.coolstuff.com"
|
||||
termsOfService="https://coolstuff.com/unityregistry/terms"
|
||||
privacyPolicy="https://coolstuff.com/unityregistry/privacy">
|
||||
<scopes>
|
||||
<scope>com.coolstuff</scope>
|
||||
</scopes>
|
||||
</registry>
|
||||
</registries>
|
||||
```
|
||||
|
||||
When PMR is loaded it will prompt the developer to add the registry to their
|
||||
project if it isn't already present in the `Packages/manifest.json` file.
|
||||
|
||||
For more information, see Unity's documentation on
|
||||
[scoped package registries](https://docs.unity3d.com/Manual/upm-scoped.html).
|
||||
|
||||
#### Managing Registries
|
||||
|
||||
It's possible to add and remove registries that are specified via PMR XML
|
||||
configuration files via the following menu options:
|
||||
|
||||
* `Assets > External Dependency Manager > Package Manager Resolver > Add
|
||||
Registries` will prompt the user with a window which allows them to add
|
||||
registries discovered in the project to the Package Manager.
|
||||
|
||||
* `Assets > External Dependency Manager > Package Manager Resolver > Remove
|
||||
Registries` will prompt the user with a window which allows them to remove
|
||||
registries discovered in the project from the Package Manager.
|
||||
|
||||
* `Assets > External Dependency Manager > Package Manager Resolver > Modify
|
||||
Registries` will prompt the user with a window which allows them to add or
|
||||
remove registries discovered in the project.
|
||||
|
||||
#### Migration
|
||||
|
||||
PMR can migrate Version Handler packages installed in the `Assets` folder to PM
|
||||
packages. This requires the plugins to implement the following:
|
||||
|
||||
* `.unitypackage` must include a Version Handler manifests that describes the
|
||||
components of the plugin. If the plugin has no dependencies the manifest
|
||||
would just include the files in the plugin.
|
||||
|
||||
* The PM package JSON provided by the registry must include a keyword (in the
|
||||
`versions.VERSION.keyword` list) that maps the PM package to a Version
|
||||
Handler package using the format `vh-name:VERSION_HANDLER_MANIFEST_NAME`
|
||||
where `VERSION_HANDLER_MANIFEST_NAME` is the name of the manifest defined in
|
||||
the `.unitypackage`. For more information see the description of the
|
||||
`gvhp_manifestname` asset label in the [Version Handler](#version-handler)
|
||||
section.
|
||||
|
||||
When using the `Assets > External Dependency Manager > Package Manager
|
||||
Resolver > Migrate Packages` menu option, PMR then will:
|
||||
|
||||
* List all Version Handler manager packages in the project.
|
||||
|
||||
* Search all available packages in the PM registries and fetch keywords
|
||||
associated with each package parsing the Version Handler manifest names for
|
||||
each package.
|
||||
|
||||
* Map each installed Version Handler package to a PM package.
|
||||
|
||||
* Prompt the user to migrate the discovered packages.
|
||||
|
||||
* Perform package migration for all selected packages if the user clicks the
|
||||
`Apply` button.
|
||||
|
||||
#### Configuration
|
||||
|
||||
PMR can be configured via the `Assets > External Dependency Manager > Package
|
||||
Manager Resolver > Settings` menu option:
|
||||
|
||||
* `Add package registries` when enabled, when the plugin loads or registry
|
||||
configuration files change, this will prompt the user to add registries that
|
||||
are not present in the Package Manager.
|
||||
|
||||
* `Prompt to add package registries` will cause a developer to be prompted
|
||||
with a window that will ask for confirmation before adding registries. When
|
||||
this is disabled registries are added silently to the project.
|
||||
|
||||
* `Prompt to migrate packages` will cause a developer to be prompted with a
|
||||
window that will ask for confirmation before migrating packages installed in
|
||||
the `Assets` directory to PM packages.
|
||||
|
||||
* `Enable Analytics Reporting` when enabled, reports the use of the plugin to
|
||||
the developers so they can make imrpovements.
|
||||
|
||||
* `Verbose logging` when enabled prints debug information to the console which
|
||||
can be useful when filing bug reports.
|
||||
|
||||
### Version Handler
|
||||
|
||||
The Version Handler component of this plugin manages:
|
||||
|
||||
* Shared Unity plugin dependencies.
|
||||
|
||||
* Upgrading Unity plugins by cleaning up old files from previous versions.
|
||||
|
||||
* Uninstallation of plugins that are distributed with manifest files.
|
||||
|
||||
* Restoration of plugin assets to their original install locations if assets
|
||||
are tagged with the `exportpath` label.
|
||||
|
||||
Since the Version Handler needs to modify Unity asset metadata (`.meta` files),
|
||||
to enable/disable components, rename and delete asset files it does not work
|
||||
with Package Manager installed packages. It's still possible to include EDM4U in
|
||||
Package Manager packages, the Version Handler component simply won't do anything
|
||||
to PM plugins in this case.
|
||||
|
||||
#### Using Version Handler Managed Plugins
|
||||
|
||||
If a plugin is imported at multiple different versions into a project, if the
|
||||
Version Handler is enabled, it will automatically check all managed assets to
|
||||
determine the set of assets that are out of date and assets that should be
|
||||
removed. To disable automatic checking managed assets disable the `Enable
|
||||
version management` option in the `Assets > External Dependency Manager >
|
||||
Version Handler > Settings` menu.
|
||||
|
||||
If version management is disabled, it's possible to check managed assets
|
||||
manually using the `Assets > External Dependency Manager > Version Handler >
|
||||
Update` menu option.
|
||||
|
||||
##### Listing Managed Plugins
|
||||
|
||||
Plugins managed by the Version Handler, those that ship with manifest files, can
|
||||
displayed using the `Assets > External Dependency Manager > Version Handler >
|
||||
Display Managed Packages` menu option. The list of plugins are written to the
|
||||
console window along with the set of files used by each plugin.
|
||||
|
||||
##### Uninstalling Managed Plugins
|
||||
|
||||
Plugins managed by the Version Handler, those that ship with manifest files, can
|
||||
be removed using the `Assets > External Dependency Manager > Version Handler >
|
||||
Uninstall Managed Packages` menu option. This operation will display a window
|
||||
that allows a developer to select a set of plugins to remove which will remove
|
||||
all files owned by each plugin excluding those that are in use by other
|
||||
installed plugins.
|
||||
|
||||
Files managed by the Version Handler, those labeled with the `gvh` asset label,
|
||||
can be checked to see whether anything needs to be upgraded, disabled or removed
|
||||
using the `Assets > External Dependency Manager > Version Handler > Update` menu
|
||||
option.
|
||||
|
||||
##### Restore Install Paths
|
||||
|
||||
Some developers move assets around in their project which can make it harder for
|
||||
plugin maintainers to debug issues if this breaks Unity's
|
||||
[special folders](https://docs.unity3d.com/Manual/SpecialFolders.html) rules. If
|
||||
assets are labeled with their original install/export path (see
|
||||
`gvhp_exportpath` below), Version Handler can restore assets to their original
|
||||
locations when using the `Assets > External Dependency Manager > Version
|
||||
Handler > Move Files To Install Locations` menu option.
|
||||
|
||||
##### Settings
|
||||
|
||||
Some behavior of the Version Handler can be configured via the `Assets >
|
||||
External Dependency Manager > Version Handler > Settings` menu option.
|
||||
|
||||
* `Enable version management` controls whether the plugin should automatically
|
||||
check asset versions and apply changes. If this is disabled the process
|
||||
should be run manually when installing or upgrading managed plugins using
|
||||
`Assets > External Dependency Manager > Version Handler > Update`.
|
||||
|
||||
* `Rename to canonical filenames` is a legacy option that will rename files to
|
||||
remove version numbers and other labels from filenames.
|
||||
|
||||
* `Prompt for obsolete file deletion` enables the display of a window when
|
||||
obsolete files are deleted allowing the developer to select which files to
|
||||
delete and those to keep.
|
||||
|
||||
* `Allow disabling files via renaming` controls whether obsolete or disabled
|
||||
files should be disabled by renaming them to `myfilename_DISABLED`. Renaming
|
||||
to disable files is required in some scenarios where Unity doesn't support
|
||||
removing files from the build via the PluginImporter.
|
||||
|
||||
* `Enable Analytics Reporting` enables/disables usage reporting to plugin
|
||||
developers to improve the product.
|
||||
|
||||
* `Verbose logging` enables *very* noisy log output that is useful for
|
||||
debugging while filing a bug report or building a new managed plugin.
|
||||
|
||||
* `Use project settings` saves settings for the plugin in the project rather
|
||||
than system-wide.
|
||||
|
||||
#### Redistributing a Managed Plugin
|
||||
|
||||
The Version Handler employs a couple of methods for managing version selection,
|
||||
upgrade and removal of plugins.
|
||||
|
||||
* Each plugin can ship with a manifest file that lists the files it includes.
|
||||
This makes it possible for Version Handler to calculate the difference in
|
||||
assets between the most recent release of a plugin and the previous release
|
||||
installed in a project. If a files are removed the Version Handler will
|
||||
prompt the user to clean up obsolete files.
|
||||
|
||||
* Plugins can ship using assets with unique names, unique GUIDs and version
|
||||
number labels. Version numbers can be attached to assets using labels or
|
||||
added to the filename (e.g `myfile.txt` would be `myfile_version-x.y.z.txt).
|
||||
This allows the Version Handler to determine which set of files are the same
|
||||
file at different versions, select the most recent version and prompt the
|
||||
developer to clean up old versions.
|
||||
|
||||
Unity plugins can be managed by the Version Handler using the following steps:
|
||||
|
||||
1. Add the `gvh` asset label to each asset (file) you want Version Handler to
|
||||
manage.
|
||||
|
||||
1. Add the `gvh_version-VERSION` label to each asset where `VERSION` is the
|
||||
version of the plugin you're releasing (e.g 1.2.3).
|
||||
|
||||
1. Add the `gvhp_exportpath-PATH` label to each asset where `PATH` is the
|
||||
export path of the file when the `.unitypackage` is created. This is used to
|
||||
track files if they're moved around in a project by developers.
|
||||
|
||||
1. Optional: Add `gvh_targets-editor` label to each editor DLL in your plugin
|
||||
and disable `editor` as a target platform for the DLL. The Version Handler
|
||||
will enable the most recent version of this DLL when the plugin is imported.
|
||||
|
||||
1. Optional: If your plugin is included in other Unity plugins, you should add
|
||||
the version number to each filename and change the GUID of each asset. This
|
||||
allows multiple versions of your plugin to be imported into a Unity project,
|
||||
with the Version Handler component activating only the most recent version.
|
||||
|
||||
1. Create a manifest text file named `MY_UNIQUE_PLUGIN_NAME_VERSION.txt` that
|
||||
lists all the files in your plugin relative to the project root. Then add
|
||||
the `gvh_manifest` label to the asset to indicate this file is a plugin
|
||||
manifest.
|
||||
|
||||
1. Optional: Add a `gvhp_manifestname-NAME` label to your manifest file to
|
||||
provide a human readable name for your package. If this isn't provided the
|
||||
name of the manifest file will be used as the package name. NAME can match
|
||||
the pattern `[0-9]+[a-zA-Z -]` where a leading integer will set the priority
|
||||
of the name where `0` is the highest priority and preferably used as the
|
||||
display name. The lowest value (i.e highest priority name) will be used as
|
||||
the display name and all other specified names will be aliases of the
|
||||
display name. Aliases can refer to previous names of the package allowing
|
||||
renaming across published versions.
|
||||
|
||||
1. Redistribute EDM4U Unity plugin with your plugin. See the
|
||||
[Plugin Redistribution](#plugin-redistribution) section for details.
|
||||
|
||||
If you follow these steps:
|
||||
|
||||
* When users import a newer version of your plugin, files referenced by the
|
||||
older version's manifest are cleaned up.
|
||||
|
||||
* The latest version of the plugin will be selected when users import multiple
|
||||
packages that include your plugin, assuming the steps in
|
||||
[Plugin Redistribution](#plugin-redistribution) are followed.
|
||||
|
||||
## Background
|
||||
|
||||
Many Unity plugins have dependencies upon Android specific libraries, iOS
|
||||
CocoaPods, and sometimes have transitive dependencies upon other Unity plugins.
|
||||
This causes the following problems:
|
||||
|
||||
* Integrating platform specific (e.g Android and iOS) libraries within a Unity
|
||||
project can be complex and a burden on a Unity plugin maintainer.
|
||||
* The process of resolving conflicting dependencies on platform specific
|
||||
libraries is pushed to the developer attempting to use a Unity plugin. The
|
||||
developer trying to use your plugin is very likely to give up when faced
|
||||
with Android or iOS specific build errors.
|
||||
* The process of resolving conflicting Unity plugins (due to shared Unity
|
||||
plugin components) is pushed to the developer attempting to use your Unity
|
||||
plugin. In an effort to resolve conflicts, the developer will very likely
|
||||
attempt to resolve problems by deleting random files in your plugin, report
|
||||
bugs when that doesn't work and finally give up.
|
||||
|
||||
EDM4U provides solutions for each of these problems.
|
||||
|
||||
### Android Dependency Management
|
||||
|
||||
The *Android Resolver* component of this plugin will download and integrate
|
||||
Android library dependencies and handle any conflicts between plugins that share
|
||||
the same dependencies.
|
||||
|
||||
Without the Android Resolver, typically Unity plugins bundle their AAR and JAR
|
||||
dependencies, e.g. a Unity plugin `SomePlugin` that requires the Google Play
|
||||
Games Android library would redistribute the library and its transitive
|
||||
dependencies in the folder `SomePlugin/Android/`. When a user imports
|
||||
`SomeOtherPlugin` that includes the same libraries (potentially at different
|
||||
versions) in `SomeOtherPlugin/Android/`, the developer using `SomePlugin` and
|
||||
`SomeOtherPlugin` will see an error when building for Android that can be hard
|
||||
to interpret.
|
||||
|
||||
Using the Android Resolver to manage Android library dependencies:
|
||||
|
||||
* Solves Android library conflicts between plugins.
|
||||
* Handles all of the various processing steps required to use Android
|
||||
libraries (AARs, JARs) in Unity 4.x and above projects. Almost all versions
|
||||
of Unity have - at best - partial support for AARs.
|
||||
* (Experimental) Supports minification of included Java components without
|
||||
exporting a project.
|
||||
|
||||
### iOS Dependency Management
|
||||
|
||||
The *iOS Resolver* component of this plugin integrates with
|
||||
[CocoaPods](https://cocoapods.org/) to download and integrate iOS libraries and
|
||||
frameworks into the Xcode project Unity generates when building for iOS. Using
|
||||
CocoaPods allows multiple plugins to utilize shared components without forcing
|
||||
developers to fix either duplicate or incompatible versions of libraries
|
||||
included through multiple Unity plugins in their project.
|
||||
|
||||
### Package Manager Registry Setup
|
||||
|
||||
The [Package Manager](https://docs.unity3d.com/Manual/Packages.html) (PM) makes
|
||||
use of [NPM](https://www.npmjs.com/) registry servers for package hosting and
|
||||
provides ways to discover, install, upgrade and uninstall packages. This makes
|
||||
it easier for developers to manage plugins within their projects.
|
||||
|
||||
However, installing additional package registries requires a few manual steps
|
||||
that can potentially be error prone. The *Package Manager Resolver* component of
|
||||
this plugin integrates with [PM](https://docs.unity3d.com/Manual/Packages.html)
|
||||
to provide a way to auto-install PM package registries when a `.unitypackage` is
|
||||
installed which allows plugin maintainers to ship a `.unitypackage` that can
|
||||
provide access to their own PM registry server to make it easier for developers
|
||||
to manage their plugins.
|
||||
|
||||
### Unity Plugin Version Management
|
||||
|
||||
Finally, the *Version Handler* component of this plugin simplifies the process
|
||||
of managing transitive dependencies of Unity plugins and each plugin's upgrade
|
||||
process.
|
||||
|
||||
For example, without the Version Handler plugin, if:
|
||||
|
||||
* Unity plugin `SomePlugin` includes `EDM4U` plugin at version 1.1.
|
||||
* Unity plugin `SomeOtherPlugin` includes `EDM4U` plugin at version 1.2.
|
||||
|
||||
The version of `EDM4U` included in the developer's project depends upon the
|
||||
order the developer imports `SomePlugin` or `SomeOtherPlugin`.
|
||||
|
||||
This results in:
|
||||
|
||||
* `EDM4U` at version 1.2, if `SomePlugin` is imported then `SomeOtherPlugin`
|
||||
is imported.
|
||||
* `EDM4U` at version 1.1, if `SomeOtherPlugin` is imported then `SomePlugin`
|
||||
is imported.
|
||||
|
||||
The Version Handler solves the problem of managing transitive dependencies by:
|
||||
|
||||
* Specifying a set of packaging requirements that enable a plugin at different
|
||||
versions to be imported into a Unity project.
|
||||
* Providing activation logic that selects the latest version of a plugin
|
||||
within a project.
|
||||
|
||||
When using the Version Handler to manage `EDM4U` included in `SomePlugin` and
|
||||
`SomeOtherPlugin`, from the prior example, version 1.2 will always be the
|
||||
version activated in a developer's Unity project.
|
||||
|
||||
Plugin creators are encouraged to adopt this library to ease integration for
|
||||
their customers. For more information about integrating EDM4U into your own
|
||||
plugin, see the [Plugin Redistribution](#plugin-redistribution) section of this
|
||||
document.
|
||||
|
||||
## Analytics
|
||||
|
||||
The External Dependency Manager for Unity plugin by default logs usage to Google
|
||||
Analytics. The purpose of the logging is to quantitatively measure the usage of
|
||||
functionality, to gather reports on integration failures and to inform future
|
||||
improvements to the developer experience of the External Dependency Manager
|
||||
plugin. Note that the analytics collected are limited to the scope of the EDM4U
|
||||
plugin’s usage.
|
||||
|
||||
For details of what is logged, please refer to the usage of
|
||||
`EditorMeasurement.Report()` in the source code.
|
||||
|
||||
## Plugin Redistribution
|
||||
|
||||
If you are a package maintainer and your package depends on EDM4U, it is highly
|
||||
recommended to use the UPM format and add EDM4U as a dependency. If you must
|
||||
include it in your `.unitypackage`, redistributing `EDM4U` inside your own
|
||||
plugin might ease the integration process for your users.
|
||||
|
||||
If you wish to redistribute `EDM4U` inside your plugin, you **must** follow
|
||||
these steps when importing the `external-dependency-manager-*.unitypackage`, and
|
||||
when exporting your own plugin package:
|
||||
|
||||
1. Import the `external-dependency-manager-*.unitypackage` into your plugin
|
||||
project by
|
||||
[running Unity from the command line](https://docs.unity3d.com/Manual/CommandLineArguments.html),
|
||||
ensuring that you add the `-gvh_disable` option.
|
||||
1. Export your plugin by
|
||||
[running Unity from the command line](https://docs.unity3d.com/Manual/CommandLineArguments.html),
|
||||
ensuring that you:
|
||||
- Include the contents of the `Assets/PlayServicesResolver` and
|
||||
`Assets/ExternalDependencyManager` directory.
|
||||
- Add the `-gvh_disable` option.
|
||||
|
||||
You **must** specify the `-gvh_disable` option in order for the Version Handler
|
||||
to work correctly!
|
||||
|
||||
For example, the following command will import the
|
||||
`external-dependency-manager-1.2.46.0.unitypackage` into the project
|
||||
`MyPluginProject` and export the entire Assets folder to
|
||||
`MyPlugin.unitypackage`:
|
||||
|
||||
```shell
|
||||
Unity -gvh_disable \
|
||||
-batchmode \
|
||||
-importPackage external-dependency-manager-1.2.46.0.unitypackage \
|
||||
-projectPath MyPluginProject \
|
||||
-exportPackage Assets MyPlugin.unitypackage \
|
||||
-quit
|
||||
```
|
||||
|
||||
### Background
|
||||
|
||||
The *Version Handler* component relies upon deferring the load of editor DLLs so
|
||||
that it can run first and determine the latest version of a plugin component to
|
||||
activate. The build of `EDM4U` plugin has Unity asset metadata that is
|
||||
configured so that the editor components are not initially enabled when it's
|
||||
imported into a Unity project. To maintain this configuration when importing the
|
||||
`external-dependency-manager.unitypackage` into a Unity plugin project, you
|
||||
*must* specify the command line option `-gvh_disable` which will prevent the
|
||||
Version Handler component from running and changing the Unity asset metadata.
|
||||
|
||||
## Building from Source
|
||||
|
||||
To build this plugin from source you need the following tools installed: * Unity
|
||||
2021 and below (with iOS and Android modules installed) * Java 11
|
||||
|
||||
You can build the plugin by running the following from your shell (Linux / OSX):
|
||||
|
||||
```shell
|
||||
./gradlew build
|
||||
|
||||
```
|
||||
|
||||
or Windows:
|
||||
|
||||
```shell
|
||||
./gradlew.bat build
|
||||
```
|
||||
|
||||
If Java 11 is not your default Java command, add
|
||||
`-Dorg.gradle.java.home=<PATH_TO_JAVA_HOME>` to the command above.
|
||||
|
||||
## Testing
|
||||
|
||||
You can run the tests by running the following from your shell (Linux / OSX):
|
||||
|
||||
```shell
|
||||
./gradlew test
|
||||
```
|
||||
|
||||
or Windows:
|
||||
|
||||
```shell
|
||||
./gradlew.bat test
|
||||
```
|
||||
|
||||
The following properties can be set to narrow down the tests to run or change
|
||||
the test run behavior.
|
||||
|
||||
* `INTERACTIVE_MODE_TESTS_ENABLED` - Default to `1`. Set to `1` to enable
|
||||
interactive mode tests, which requires GPU on the machine. Otherwise, only
|
||||
run tests in the batch mode.
|
||||
* `INCLUDE_TEST_TYPES` - Default to empty string, which means to include every
|
||||
type of the test. To narrow down the types of test to run, set this
|
||||
properties with a list of case-insensitive type strings separated by comma.
|
||||
For instance, `-PINCLUDE_TEST_TYPES="Python,NUnit"` means to include only
|
||||
Python tests and NUnit tests. See `TestTypeEnum` in `build.gradle` for
|
||||
available options.
|
||||
* `EXCLUDE_TEST_TYPES` - Default to empty string, which means to exclude none.
|
||||
To add types of tests to exclude, set this properties with a list of
|
||||
case-insensitive type strings separated by comma. For instance,
|
||||
`-PEXCLUDE_TEST_TYPES="Python,NUnit"` means to exclude Python tests and
|
||||
NUnit tests. See `TestTypeEnum` in `build.gradle` for available options.
|
||||
* `INCLUDE_TEST_MODULES` - Default to empty string, which means to include the
|
||||
tests for every modules. To narrow down modules to test, set this properties
|
||||
with a list of case-insensitive module strings separated by comma. For
|
||||
instance, `-PINCLUDE_TEST_MODULES="Tool,AndroidResolver"` means to run tests
|
||||
for tools and Android Resolver only. See `TestModuleEnum` in `build.gradle`
|
||||
for available options.
|
||||
* `EXCLUDE_TEST_MODULES` - Default to empty string, which means to exclude
|
||||
none. To add modules to exclude, set this properties with a list of
|
||||
case-insensitive module strings separated by comma. For instance,
|
||||
`-PEXCLUDE_TEST_MODULES="Tool,AndroidResolver"` means to run tests for any
|
||||
modules other than tools and Android Resolver. See `TestModuleEnum` in
|
||||
`build.gradle` for available options.
|
||||
* `EXCLUDE_TESTS` - Default to empty string, which means to exclude none. To
|
||||
add tests to exclude, set this properties with a list of case-insensitive
|
||||
test names separated by comma. For instance,
|
||||
`-PEXCLUDE_TESTS="testGenGuids,testDownloadArtifacts"` means to run tests
|
||||
except the tests with name of `testGenGuids` and `testDownloadArtifacts`.
|
||||
* `CONTINUE_ON_FAIL_FOR_TESTS_ENABLED` - Default to `1`. Set to `1` to
|
||||
continue running the next test when the current one fails. Otherwise, the
|
||||
build script stops whenever any test fails.
|
||||
|
||||
For instance, by running the following command, it only runs the Unity
|
||||
integration tests that does not requires GPU, but exclude tests for Android
|
||||
Resolver module and iOS Resolver module.
|
||||
|
||||
```shell
|
||||
./gradlew test \
|
||||
-PINTERACTIVE_MODE_TESTS_ENABLED=0 \
|
||||
-PINCLUDE_TEST_TYPES="Integration" \
|
||||
-PEXCLUDE_TEST_MODULES="AndroidResolver,iOSResolver"
|
||||
```
|
||||
|
||||
## Releasing
|
||||
|
||||
Each time a new build of this plugin is checked into the source tree you need to
|
||||
do the following:
|
||||
|
||||
* Bump the plugin version variable `pluginVersion` in `build.gradle`
|
||||
* Update `CHANGELOG.md` with the new version number and changes included in
|
||||
the release.
|
||||
* Build the release using `./gradlew release` which performs the following:
|
||||
* Updates `external-dependency-manager-*.unitypackage`
|
||||
* Copies the unpacked plugin to the `exploded` directory.
|
||||
* Updates template metadata files in the `plugin` directory. The GUIDs of
|
||||
all asset metadata is modified due to the version number change. Each
|
||||
file within the plugin is versioned to allow multiple versions of the
|
||||
plugin to be imported into a Unity project which allows the most recent
|
||||
version to be activated by the Version Handler component.
|
||||
* Create release commit using `./gradlew gitCreateReleaseCommit` which
|
||||
performs `git commit -a -m "description from CHANGELOG.md"`
|
||||
* Once the release commit is merge, tag the release using `./gradlew
|
||||
gitTagRelease` which performs the following:
|
||||
* `git tag -a pluginVersion -m "version RELEASE"` to tag the release.
|
||||
* Update tags on remote branch using `git push --tag REMOTE HEAD:master`
|
||||
12
Assets/ExternalDependencyManager/Editor/README.md.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 77919e84cef8419ab4b725fc16e83d52
|
||||
labels:
|
||||
- gvh
|
||||
- gvh_version-1.2.186
|
||||
- gvhp_exportpath-ExternalDependencyManager/Editor/README.md
|
||||
timeCreated: 1584567712
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
Assets/ExternalDependencyManager/Editor/1.2.186/Google.IOSResolver.dll
|
||||
Assets/ExternalDependencyManager/Editor/1.2.186/Google.IOSResolver.pdb
|
||||
Assets/ExternalDependencyManager/Editor/1.2.186/Google.JarResolver.dll
|
||||
Assets/ExternalDependencyManager/Editor/1.2.186/Google.JarResolver.pdb
|
||||
Assets/ExternalDependencyManager/Editor/1.2.186/Google.PackageManagerResolver.dll
|
||||
Assets/ExternalDependencyManager/Editor/1.2.186/Google.PackageManagerResolver.pdb
|
||||
Assets/ExternalDependencyManager/Editor/1.2.186/Google.VersionHandlerImpl.dll
|
||||
Assets/ExternalDependencyManager/Editor/1.2.186/Google.VersionHandlerImpl.pdb
|
||||
Assets/ExternalDependencyManager/Editor/CHANGELOG.md
|
||||
Assets/ExternalDependencyManager/Editor/Google.VersionHandler.dll
|
||||
Assets/ExternalDependencyManager/Editor/Google.VersionHandler.pdb
|
||||
Assets/ExternalDependencyManager/Editor/LICENSE
|
||||
Assets/ExternalDependencyManager/Editor/README.md
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c9a3138961c74d99b7046b783112fceb
|
||||
labels:
|
||||
- gvh
|
||||
- gvh_manifest
|
||||
- gvh_version-1.2.186
|
||||
- gvhp_exportpath-ExternalDependencyManager/Editor/external-dependency-manager_version-1.2.186_manifest.txt
|
||||
- gvhp_manifestname-0External Dependency Manager
|
||||
- gvhp_manifestname-play-services-resolver
|
||||
timeCreated: 1474401009
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/ShiroginSDK.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4bc1c52626077d846b784d8d9b511534
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
90
Assets/ShiroginSDK/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# 🧾 ShiroginSDK Changelog
|
||||
|
||||
Tüm önemli değişiklikler bu dosyada tutulacaktır.
|
||||
Her sürüm, SDK mimarisine eklenen yeni sistemleri ve servisleri içerir.
|
||||
|
||||
---
|
||||
## [1.1.1] - 2025-10-23
|
||||
### ✨ Eklendi
|
||||
|
||||
- 🔧 **Core Düzeltmeler**
|
||||
- `AnalyticsEventListener` AnalyticsEventListenerService'e dönüştürüldü ve analiz event bug düzeltildi..
|
||||
|
||||
---
|
||||
|
||||
## [1.1.0] - 2025-10-15
|
||||
### ✨ Eklendi
|
||||
|
||||
- 📦 **Asset Registry Manager & Setup Wizard**
|
||||
- **Akıllı Kurulum Sihirbazı:** SDK ilk yüklendiğinde açılan ve projenin eksiklerini (Core Missing) analiz eden bir sihirbaz eklendi.
|
||||
- **Queue (Kuyruk) Sistemi:** "Download & Install All Core" butonu ile birden fazla paket (IAP, Ads, Analytics vb.) sırasıyla indirilir ve kurulur.
|
||||
- **UPM Entegrasyonu:** Unity IAP, TextMeshPro ve Android Logcat gibi Unity paketleri artık Asset Manager üzerinden otomatik (`Client.Add`) komutuyla kuruluyor.
|
||||
- **Versiyon Kontrolü:** Yüklü paketlerin versiyonları denetlenir. Eğer farklı bir versiyon yüklüyse arayüzde "Update" veya "Switch" seçenekleri belirir.
|
||||
- **Cache Yönetimi:** İndirilen `.unitypackage` dosyaları cache'de tutulur, tekrar indirme yapmadan "Import (Cached)" özelliği ile hızlı kurulum sağlanır.
|
||||
- **Görsel Durum Bildirimi:** Paketlerin durumu (Yüklü, İndirilmiş, Eksik) renkli kutular (Yeşil, Mavi, Kırmızı, Gri) ile görselleştirildi.
|
||||
|
||||
- 📚 **Entegre Dokümantasyon Sistemi**
|
||||
- Asset Manager üzerinden paketlerin dokümantasyonları (Markdown) direkt olarak projeye indirilebiliyor.
|
||||
- Web butonu ile ilgili paketin online dokümantasyonuna yönlendirme eklendi.
|
||||
|
||||
- 🔧 **Core İyileştirmeler**
|
||||
- `AssetRegistryEditor` UPM isteklerini asenkron takip edecek şekilde güncellendi.
|
||||
- Setup Wizard modunda, temel paketlerin (Essential Packages) versiyonları kilitlendi, böylece uyumsuz versiyon kurulumu engellendi.
|
||||
- `DOTween``DOTweenPro`'ya dönüştürüldü.
|
||||
|
||||
---
|
||||
|
||||
## [1.0.0] - 2025-10-01
|
||||
### ✨ Eklendi
|
||||
|
||||
- 🎯 **IAP Service (In-App Purchasing)**
|
||||
- `IAPService` sınıfı eklendi. Unity IAP üzerinden satın alma, ödül verme ve restore işlemleri destekleniyor.
|
||||
- `StoreRepository`, `StoreSection`, `StoreItem` ScriptableObject yapıları oluşturuldu.
|
||||
- `RewardDefinition` ile oyun içi ödüller merkezi olarak tanımlanabiliyor.
|
||||
- `UIStoreItem_*` sınıfları (Consumable, NonConsumable, Bundle, Rewarded, Chest) ile dinamik mağaza UI sistemi kuruldu.
|
||||
- `EconomyData` ve `StoreData` entegrasyonu sağlandı.
|
||||
|
||||
- 💳 **Economy & Data System**
|
||||
- `BaseData` mimarisi kuruldu. Veriler JSON tabanlı kayıt ve yükleme destekliyor.
|
||||
- `EconomyData`, `InventoryData`, `StatsData` yapılandırıldı.
|
||||
- `DataService` merkezi kayıt erişimi sağlıyor.
|
||||
- Oyunlara özel veri kullanımı seçilebilir hale getirildi (örnek: sadece Gold/Gems/Tickets tutma).
|
||||
|
||||
- 📊 **Analytics System (Firebase • AppsFlyer • Facebook)**
|
||||
- `AnalyticsService` merkezi çoklu SDK entegrasyonu eklendi.
|
||||
- `AnalyticsEventMapper` ile oyun içi eventler (LevelUp, Purchase vb.) otomatik olarak ilgili SDK'nın formatına dönüştürülüyor.
|
||||
|
||||
- 🔥 **Firebase Service**
|
||||
- `FirebaseService` eklendi (Analytics + Remote Config).
|
||||
- Remote Config değerleri `RemoteConfigDefinition` ScriptableObject üzerinden tanımlanabiliyor.
|
||||
- İnternet yoksa son başarılı config değerlerini kullanan Cache sistemi eklendi.
|
||||
|
||||
- 📱 **Facebook Service**
|
||||
- `FacebookService` eklendi (Init, Login, LogEvent).
|
||||
- iOS/Android için otomatik App Activation desteği.
|
||||
|
||||
- 🎯 **Ads Service (AppLovin MAX)**
|
||||
- `AdsService` eklendi.
|
||||
- Banner, Interstitial ve Rewarded reklamlar için event-based yönetim (Load, Show, Fail, Reward).
|
||||
- `AdAnalyticsEvent` ile reklam gelirleri analitik servisine otomatik raporlanıyor.
|
||||
|
||||
- 📺 **UI & Popup System**
|
||||
- `PopupService` ve `PopupBase` mimarisi kuruldu.
|
||||
- Popuplar, öncelik sırasına (Priority Queue) göre gösteriliyor.
|
||||
- `ThemeService` ile UI görselleri dinamik olarak değiştirilebiliyor (Örn: Yılbaşı teması).
|
||||
- CanvasGroup tabanlı Fade-In/Out ve şeffaflık animasyonu desteği getirildi.
|
||||
|
||||
- 🎨 **Theme Service**
|
||||
- `ThemeService` eklendi.
|
||||
- Her oyun için özel tema setleri (örnek: Fire, Snow, Dungeon, etc.) tanımlanabiliyor.
|
||||
- UI elementleri tema bazlı otomatik güncellenebiliyor.
|
||||
|
||||
- 🧰 **Editor Tools**
|
||||
- `SDKConfigurator` ve `PlayerPrefs Editor` arayüzleri oluşturuldu.
|
||||
- SDK modülleri Unity Editor üzerinden kolayca açılıp kapatılabiliyor.
|
||||
- Otomatik versiyonlama ve konfigürasyon denetimi sağlandı.
|
||||
|
||||
- ⚙️ **Core Improvements**
|
||||
- `SDKInitializer` eklendi — tüm servisleri sırasıyla başlatıyor.
|
||||
- Servislerin `DontDestroyOnLoad` yaşam döngüsü standardize edildi.
|
||||
- Konsol log’ları ShiroginSDK etiketiyle birleştirildi.
|
||||
7
Assets/ShiroginSDK/CHANGELOG.md.meta
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6db0fc2e192287047b11c849d60c1a6a
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/ShiroginSDK/Documents.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 927923e41e42e2f4287b9fab1dda50e7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Assets/ShiroginSDK/Documents/Analytics.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 00f3ad63bef944008dba51a3801a9542
|
||||
timeCreated: 1760703697
|
||||
191
Assets/ShiroginSDK/Documents/Analytics/AnalyticsService.md
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
# 📊 ShiroginSDK Analytics System (v1.0.0 Updated)
|
||||
|
||||
**Firebase • AppsFlyer • Facebook**
|
||||
Tam Otomatik Event Forwarding + Çok Katmanlı Servis Mimarisi
|
||||
|
||||
Bu doküman, **ShiroginSDK v1.0.0** sürümüyle birlikte gelen yeni analiz servis mimarisini açıklar.
|
||||
Yeni sistem, `ShiroginServiceRegistry` üzerinden otomatik başlatılır ve **Firebase**, **AppsFlyer** ve **Facebook** SDK’larına merkezi olarak bağlanır.
|
||||
Tüm loglama işlemleri event tabanlıdır — geliştirici sadece `EventService.Invoke()` çağrısı yapar.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 1. Genel Bakış
|
||||
|
||||
Yeni analiz sistemi üç ana katmandan oluşur:
|
||||
|
||||
1. **EventService (Core)**
|
||||
→ Oyun içi tüm `ShiroginEvents`’leri yönetir.
|
||||
→ `AnalyticsService`, `FirebaseService`, `AppsFlyerService` gibi servislerle otomatik iletişim kurar.
|
||||
|
||||
2. **AnalyticsService (Coordinator)**
|
||||
→ Eventleri dinler, `AnalyticsEventMapper` üzerinden uygun SDK formatına dönüştürür.
|
||||
→ Aktif SDK’lara log iletir (`FirebaseService`, `AppsFlyerService`, `FacebookService`).
|
||||
|
||||
3. **Platform Servisleri (Backends)**
|
||||
→ Her SDK’ya özel bağlantı, initialization ve log gönderim süreçlerini yönetir.
|
||||
|
||||
> Tüm servisler `ShiroginServiceRegistry.InitializeAll()` çağrısı ile otomatik olarak başlatılır.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 2. Yeni Servis Mimarisi
|
||||
|
||||
### 🔹 Başlatma (Yeni Sistem)
|
||||
|
||||
```csharp
|
||||
ShiroginServiceRegistry.InitializeAll();
|
||||
```
|
||||
|
||||
Bu çağrı aşağıdaki servisleri sırayla oluşturur:
|
||||
|
||||
* **EventService** → Event iletişimi
|
||||
* **DataService** → Kalıcı veri yönetimi
|
||||
* **FirebaseService** → Firebase Analytics + RemoteConfig
|
||||
* **AppsFlyerService** → AppsFlyer SDK
|
||||
* **FacebookService** → Meta SDK
|
||||
* **AnalyticsService** → Otomatik event yönlendirme
|
||||
|
||||
---
|
||||
|
||||
### 🔹 Örnek Event Akışı
|
||||
|
||||
```csharp
|
||||
EventService.Invoke(new ShiroginEvents.PurchaseCompletedEvent(product));
|
||||
```
|
||||
|
||||
Bu çağrıdan sonra sistem sırasıyla:
|
||||
|
||||
1. `EventService` event’i yakalar.
|
||||
2. `AnalyticsService` event tipini analiz eder.
|
||||
3. `AnalyticsEventMapper` parametreleri uygun SDK formatına çevirir.
|
||||
4. `FirebaseService`, `AppsFlyerService` ve `FacebookService` log gönderir.
|
||||
|
||||
Tam akış:
|
||||
|
||||
```
|
||||
[Game Event]
|
||||
↓
|
||||
EventService
|
||||
↓
|
||||
AnalyticsService
|
||||
↓
|
||||
Firebase / AppsFlyer / Facebook
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔥 3. Servis Güncellemeleri
|
||||
|
||||
### 🔸 AnalyticsService
|
||||
|
||||
Artık doğrudan `ServiceBase`’den türetilir ve `ServiceLocator` üzerinden erişilir.
|
||||
Kendi `Initialize()` metodunda bağlı SDK’ları otomatik bulur.
|
||||
|
||||
```csharp
|
||||
var analytics = ServiceLocator.Get<IAnalyticsService>();
|
||||
analytics.LogEvent(AnalyticsEventType.Purchase, parameters);
|
||||
```
|
||||
|
||||
### 🔸 FirebaseService
|
||||
|
||||
Yeni sistemde hem **RemoteConfig** hem **Analytics** aynı instance üzerinden yönetilir.
|
||||
Başarılı başlatma sonrası artık `FirebaseReadyEvent` yayınlanır.
|
||||
|
||||
```csharp
|
||||
_eventService.Invoke(new ShiroginEvents.FirebaseReadyEvent());
|
||||
```
|
||||
|
||||
### 🔸 AppsFlyerService
|
||||
|
||||
Tamamen `ServiceBase` yapısına geçti.
|
||||
Başlatma işlemi otomatik olarak `ShiroginServiceRegistry` içinde gerçekleşir.
|
||||
|
||||
### 🔸 EventService
|
||||
|
||||
Artık SDK’nin ana “event bus” yapısıdır.
|
||||
Tüm servisler (Firebase, Ads, IAP, RemoteConfig) kendi event’lerini bu sistem üzerinden yayınlar.
|
||||
Oyun içi tüm veri akışı **tek bir hat üzerinden** ilerler.
|
||||
|
||||
---
|
||||
|
||||
## 🧠 4. Otomatik Event Forwarding (Yeni)
|
||||
|
||||
Yeni versiyonda, `AnalyticsEventListener` artık doğrudan kullanılmaz.
|
||||
Onun yerine `AnalyticsService` kendisi `EventService`’e subscribe olur ve dinleme işlemini merkezi hale getirir.
|
||||
|
||||
Örnek:
|
||||
|
||||
```csharp
|
||||
EventService.Invoke(new ShiroginEvents.AdWatchedEvent("rewarded", true));
|
||||
```
|
||||
|
||||
→ Otomatik olarak üç platforma log gönderilir.
|
||||
|
||||
---
|
||||
|
||||
## 🧰 5. SDKConfig Entegrasyonu
|
||||
|
||||
Yeni `SDKConfig` sınıfı üzerinden tüm analitik modüller yönetilir:
|
||||
|
||||
```csharp
|
||||
public bool enableFirebaseAnalytics = true;
|
||||
public bool enableAppsFlyerAnalytics = true;
|
||||
public bool enableFacebookAnalytics = true;
|
||||
```
|
||||
|
||||
Bu alanlar `AnalyticsService.Initialize()` aşamasında kontrol edilir, aktif olmayan SDK’lara log gönderimi yapılmaz.
|
||||
|
||||
---
|
||||
|
||||
## 🧾 6. Örnek Kullanım: Satın Alma Event’i
|
||||
|
||||
```csharp
|
||||
EventService.Invoke(new ShiroginEvents.PurchaseCompletedEvent("com.game.removeads", 4.99f, "USD"));
|
||||
```
|
||||
|
||||
Arka planda:
|
||||
|
||||
* `AnalyticsService` → `Purchase` event’ini tanır.
|
||||
* `AnalyticsEventMapper` → Parametreleri dönüştürür.
|
||||
* `FirebaseService`, `AppsFlyerService`, `FacebookService` → Aynı anda log gönderir.
|
||||
* `FirebaseReadyEvent` ve `PurchaseLoggedEvent` tetiklenir.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 7. Güncellenen Özellikler
|
||||
|
||||
✅ Yeni Service Registry sistemi (otomatik init & dispose)
|
||||
✅ EventService tabanlı otomatik log forwarding
|
||||
✅ Firebase + AppsFlyer + Facebook tam entegrasyon
|
||||
✅ Async initialization + error fallback
|
||||
✅ Tek config kaynağı (`SDKConfig`)
|
||||
✅ Event bazlı hata loglama (örneğin `NoConnectionEvent`, `RewardedAdUnavailableEvent`)
|
||||
|
||||
---
|
||||
|
||||
## 📘 8. Uyumlu Modüller
|
||||
|
||||
Yeni sistem doğrudan şu modüllerle entegre çalışır:
|
||||
|
||||
* `IAPService` → Satın alma logları
|
||||
* `AdsService` → Ad impression + revenue logları
|
||||
* `PopupService` → UI etkileşimleri
|
||||
* `RemoteConfigService` → Firebase senkronizasyon eventleri
|
||||
|
||||
---
|
||||
|
||||
## 🧠 9. Özet
|
||||
|
||||
ShiroginSDK Analytics System v1.0.0 artık tamamen **service-driven ve event-driven** mimari üzerinde çalışır.
|
||||
Tüm SDK’lar ortak bir event hattını kullanır, initialization sırası `ShiroginServiceRegistry` tarafından yönetilir.
|
||||
Bu yapı hem oyun entegrasyonunu sadeleştirir hem de log takibini merkezi hale getirir.
|
||||
|
||||
---
|
||||
|
||||
**Prepared by:** Emir Han MAMAK
|
||||
|
||||
**Version:** 1.1.0 (2025.12)
|
||||
|
||||
**Module:** ShiroginSDK.Runtime.Services.Implementations.Analytics
|
||||
|
||||
---
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ec1723ff3a314f6c81983487e251813e
|
||||
timeCreated: 1759957415
|
||||
3
Assets/ShiroginSDK/Documents/Facebook.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 203a4f02da8b4acda8478c9a876451c4
|
||||
timeCreated: 1760703707
|
||||
78
Assets/ShiroginSDK/Documents/Facebook/FacebookService.md
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# 📘 Shirogin SDK – Facebook Entegrasyonu
|
||||
**Güncelleme Tarihi:** 08.10.2025
|
||||
|
||||
Bu doküman, Shirogin SDK kullanan Unity projelerinde **Facebook SDK entegrasyonunu** adım adım nasıl yapacağınızı açıklar. Kurulum sürecinde dikkat edilmesi gereken noktalar, hata önleme ipuçları ve gerekli bağlantılar da dahildir.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 1. Facebook SDK Kurulumu
|
||||
|
||||
ShiroginSDK, üçüncü parti entegrasyonlar için hazır klasör yapısı ile gelir. Eğer proje içinde Facebook SDK bulunmuyorsa aşağıdaki adımları izleyin:
|
||||
|
||||
1. [Facebook SDK for Unity](https://github.com/facebook/facebook-sdk-for-unity/releases) sayfasına gidin.
|
||||
2. En güncel sürümü indirelim.
|
||||
3. **Package Manager üzerinden kurulum yaparken. Packages'ın eklemeyin çünkü projeyi bozuyor**
|
||||
4. Kurulum esnasında çıkan pencerede **“IAPWarper”** gibi hata veren bileşenlerin işaretini kaldırın veya bu kodları projeden kaldırın.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 2. Facebook Ayarlarını Yapılandırma
|
||||
|
||||
Kurulum tamamlandıktan sonra, Facebook SDK ayarlarını Unity üzerinden yapılandırın:
|
||||
|
||||
1. Menüden şu yolu izleyin:
|
||||
**Facebook → Edit Settings**
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 🌐 3. Facebook Geliştirici Paneli Ayarları
|
||||
|
||||
Facebook uygulama bilgilerinizi almak için [Facebook Developers](https://developers.facebook.com/apps/) adresine gidin:
|
||||
|
||||
1. Oyununuzu veya uygulamanızı seçin.
|
||||
2. Aşağıdaki bilgileri bulun:
|
||||
|
||||
- **App ID:** Uygulamanızın benzersiz kimliği
|
||||

|
||||
|
||||
- **Client Token:** Kimlik doğrulama için gerekli
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 🧰 4. Unity Üzerinde Son Ayarların Yapılması
|
||||
|
||||
Facebook panelinden aldığınız bilgileri Unity’de açtığınız **Edit Settings** ekranına girin:
|
||||
|
||||
- **App Name** → Uygulama adınız
|
||||
- **App ID** → Uygulama kimliğiniz
|
||||
- **Client Token** → Kimlik doğrulama anahtarınız
|
||||
|
||||
Ardından **Regenerate Android Manifest** butonuna tıklayarak gerekli Android izinlerini ve yapılandırmaları otomatik oluşturun.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## ✅ Sonuç
|
||||
|
||||
Bu adımlar tamamlandığında Shirogin SDK projeniz, Facebook SDK ile tamamen entegre şekilde çalışmaya hazır hale gelir.
|
||||
Artık Facebook ile giriş, analiz olayları takibi ve sosyal özellikleri sorunsuzca kullanabilirsiniz.
|
||||
|
||||
---
|
||||
|
||||
📌 **Not:** Entegrasyon sırasında hatalarla karşılaşırsanız `Console` sekmesini kontrol edin. Eksik izinler veya hatalı kimlik bilgileri çoğu zaman burada detaylı şekilde listelenir.
|
||||
|
||||
---
|
||||
|
||||
**Hazırlayan:** Emir Han MAMAK
|
||||
|
||||
**Version:** 1.1.0 (2025.12)
|
||||
|
||||
**Module:** ShiroginSDK.Runtime.Services.Implementations.Facebook
|
||||
|
||||
---
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7b7c45874a7f8d94abfaf69611b88084
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Assets/ShiroginSDK/Documents/IAP.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 471745bf357b458ca01b2080f4d14094
|
||||
timeCreated: 1760703774
|
||||
213
Assets/ShiroginSDK/Documents/IAP/IAPService.md
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
# 🛒 ShiroginSDK IAP System (v1.0.0)
|
||||
|
||||
**Unity In-App Purchase Entegrasyonu + Oyun İçi Ekonomi + Ödül + Event-Driven Mimari**
|
||||
|
||||
Bu doküman, **ShiroginSDK v1.0.0** sürümüyle güncellenen IAP (In-App Purchase) altyapısını açıklar.
|
||||
Yeni sistem, **ShiroginServiceRegistry** üzerinden başlatılan **modüler servis yapısına** sahiptir.
|
||||
Tüm satın alma işlemleri, **event tabanlı** olarak SDK genelindeki diğer servislerle otomatik senkronize edilir.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 1. Genel Bakış
|
||||
|
||||
ShiroginSDK IAP sistemi:
|
||||
|
||||
* ✅ `ServiceBase` tabanlı, modüler ve bağımsız servis yapısı
|
||||
* ✅ `EventService` ile tam event forwarding desteği
|
||||
* ✅ Unity IAP, oyun içi ekonomi, sandık, bundle ve reklamla ödül sistemleri
|
||||
* ✅ Otomatik `AnalyticsService` & `PopupService` entegrasyonu
|
||||
* ✅ Tek konfigürasyon noktası: `SDKConfig.storeRepository`
|
||||
|
||||
---
|
||||
|
||||
## 🧩 2. Servis Mimarisi
|
||||
|
||||
### 🔹 IAPService (Yeni Sistem)
|
||||
|
||||
`IAPService`, artık `ServiceBase`’ten türetilen bir servis olarak `ShiroginServiceRegistry` tarafından otomatik olarak başlatılır.
|
||||
Kendi bağımlılıklarını `ServiceLocator` aracılığıyla çözer.
|
||||
|
||||
**Başlatma:**
|
||||
|
||||
```csharp
|
||||
ShiroginServiceRegistry.InitializeAll();
|
||||
````
|
||||
|
||||
Bu çağrı, IAPService dahil tüm servisleri (`EventService`, `DataService`, `FirebaseService`, `AnalyticsService`) otomatik olarak oluşturur.
|
||||
|
||||
**IAPService Görevleri:**
|
||||
|
||||
* Unity IAP sistemini başlatır (`UnityPurchasing.Initialize()`).
|
||||
* Satın alma işlemlerini yönetir.
|
||||
* Başarılı işlemlerde ödül verir (`StoreItem.GiveReward()`).
|
||||
* EventService üzerinden satın alma event’lerini yayınlar.
|
||||
|
||||
**Kilit Eventler:**
|
||||
|
||||
```csharp
|
||||
_eventService.Invoke(new ShiroginEvents.PurchaseCompletedEvent(product, 1)); // Analytics
|
||||
_eventService.Invoke(new ShiroginEvents.Shop_UIStoreItem_Rewarded(item.GetRewards())); // Popup
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🔹 DataService Entegrasyonu (v1.0.0 Güncel)
|
||||
|
||||
Yeni sistemde `DataService`, `ServiceBase`’ten türetilen bağımsız bir servistir.
|
||||
`ServiceLocator` aracılığıyla erişilir ve oyun boyunca tüm veri nesnelerini (`RuntimeData`, `EconomyData`, `StoreData`, `InventoryData` vb.) yönetir.
|
||||
|
||||
```csharp
|
||||
var dataService = ServiceLocator.Get<IDataService>();
|
||||
|
||||
var storeData = dataService.Get<StoreData>();
|
||||
storeData.MarkPurchased(productId, 1, item.category);
|
||||
|
||||
var runtime = dataService.Get<RuntimeData>();
|
||||
runtime.UpdatePlaySessionCount();
|
||||
```
|
||||
|
||||
Artık **`DataService.Get<T>()`** gibi statik çağrılar yerine, `ServiceLocator` üzerinden interface tabanlı erişim kullanılmalıdır.
|
||||
Bu sayede her servis, kendi yaşam döngüsünde `OnInitialize()` içinde `IDataService`’i çözer ve paylaşılan state’i korur.
|
||||
|
||||
> 🔹 `IDataService` → `Get<T>()`, `Save<T>()`, `Delete<T>()` gibi tip güvenli fonksiyonlar sağlar.
|
||||
> 🔹 `DataService` runtime'da `DontDestroyOnLoad` olarak yaşar.
|
||||
> 🔹 Oyun verileri JSON tabanlı olarak `Application.persistentDataPath || PlayerPrefs` altında tutulur.
|
||||
|
||||
---
|
||||
|
||||
### 🔹 EventService Entegrasyonu
|
||||
|
||||
Her önemli işlem event tabanlı çalışır.
|
||||
IAPService, `EventService` üzerinden ShiroginEvents yayınlayarak SDK içindeki diğer sistemlere sinyal gönderir.
|
||||
|
||||
Örneğin:
|
||||
|
||||
* `PurchaseCompletedEvent` → `AnalyticsService` tarafından loglanır
|
||||
* `Shop_UIStoreItem_Rewarded` → `PopupService` tarafından UI bildirimi gösterilir
|
||||
|
||||
---
|
||||
|
||||
## 💳 3. IAPService API Özeti
|
||||
|
||||
| Metod | Açıklama |
|
||||
| ------------------------------------ | ------------------------------------------ |
|
||||
| `Buy(StoreItem item)` | Belirtilen ürünü satın alır. |
|
||||
| `Buy(string productId)` | Product ID ile satın alma başlatır. |
|
||||
| `RestorePurchases()` | Kalıcı ürünleri geri yükler (iOS/Android). |
|
||||
| `GetLocalizedPriceString(productId)` | Cihazın mağaza diline uygun fiyat döner. |
|
||||
|
||||
---
|
||||
|
||||
## 🧠 4. Akış Diyagramı
|
||||
|
||||
```
|
||||
[UIStoreItem_Consumable.OnPurchaseButton]
|
||||
↓
|
||||
[IAPService.Buy()]
|
||||
↓
|
||||
Unity IAP Purchase Flow
|
||||
↓
|
||||
[IAPService.ProcessPurchase()]
|
||||
↓
|
||||
[StoreItem.GiveReward()]
|
||||
↓
|
||||
[EventService.Invoke(ShiroginEvents.PurchaseCompletedEvent)]
|
||||
↓
|
||||
[AnalyticsService + PopupService]
|
||||
```
|
||||
|
||||
Tüm veri ve event akışı tek hattan ilerler.
|
||||
Bu sayede loglama, ödül ve UI işlemleri birbiriyle senkronize yürür.
|
||||
|
||||
---
|
||||
|
||||
## 🧰 5. Editor & Test Özellikleri
|
||||
|
||||
* **FakeStore Modu:**
|
||||
Unity Editor içinde `StandardPurchasingModule` otomatik olarak FakeStore’u açar.
|
||||
Test sırasında gerçek ödeme yapılmaz.
|
||||
|
||||
```csharp
|
||||
module.useFakeStoreAlways = true;
|
||||
module.useFakeStoreUIMode = FakeStoreUIMode.StandardUser;
|
||||
```
|
||||
|
||||
* **Loglama:**
|
||||
Başarılı ve başarısız tüm işlemler konsola `[IAPService]` etiketiyle yazılır.
|
||||
|
||||
---
|
||||
|
||||
## 🪙 6. Ekonomi & Ödül Yönetimi
|
||||
|
||||
IAP sistemi, **EconomyData** ve **RewardDefinition** ile entegredir:
|
||||
|
||||
* Satın alma sonrası ödül → `StoreItem.GiveReward()`
|
||||
* Sandık → `StoreItem.GiveRandomReward()`
|
||||
* Kaldırılan reklamlar → `RewardType.RemoveAds`
|
||||
* Currency tabanlı satın alma → `EconomyData.SpendCurrency()`
|
||||
|
||||
---
|
||||
|
||||
## 🔔 7. Event Referansları
|
||||
|
||||
| Event | Açıklama |
|
||||
| ---------------------------- | ---------------------------------------- |
|
||||
| `PurchaseCompletedEvent` | Satın alma başarıyla tamamlandı. |
|
||||
| `PurchaseFailedEvent` | Satın alma başarısız oldu. |
|
||||
| `RewardGivenEvent` | Ödül verildi. |
|
||||
| `Shop_UIStoreItem_Rewarded` | Mağaza ödül popup’ı tetiklendi. |
|
||||
| `NoConnectionEvent` | İnternet bağlantısı yok. |
|
||||
| `RewardedAdUnavailableEvent` | Reklam izlenemedi (AdsService kaynaklı). |
|
||||
|
||||
---
|
||||
|
||||
## 🧩 8. Yeni Mimarideki Geliştirmeler
|
||||
|
||||
| Alan | Yenilik |
|
||||
| ---------------------------- | ------------------------------------------------------------ |
|
||||
| **Lifecycle** | Tüm servisler `ServiceBase` üstünden yönetilir. |
|
||||
| **Bağımlılıklar** | `ServiceLocator` ile otomatik çözülür. |
|
||||
| **Otomatik EventForwarding** | `EventService` ile doğrudan bağlı. |
|
||||
| **Firebase Entegrasyonu** | Satın alma logları otomatik olarak `FirebaseService`’e akar. |
|
||||
| **Gelişmiş Restore Logic** | Android ve iOS için unified restore desteği. |
|
||||
| **UI Bağımsızlık** | Tüm item’ler `UIStoreItemBase` tabanlı. |
|
||||
|
||||
---
|
||||
|
||||
## 🧠 9. Örnek Kod: Mağaza Butonu
|
||||
|
||||
```csharp
|
||||
public void OnGemPackButton()
|
||||
{
|
||||
var store = ServiceLocator.Get<IIAPService>();
|
||||
var item = store.StoreRepository.GetByProductId("com.shirogin.gem_pack_1");
|
||||
store.Buy(item);
|
||||
}
|
||||
```
|
||||
|
||||
Satın alma tamamlandığında:
|
||||
|
||||
* Oyuncuya ödül verilir.
|
||||
* `AnalyticsService` log gönderir.
|
||||
* `PopupService` başarı mesajı gösterir.
|
||||
|
||||
---
|
||||
|
||||
## 🧾 10. Özet
|
||||
|
||||
ShiroginSDK IAP System v1.0.0,
|
||||
tamamen **event-driven**, **service-oriented** ve **UI-modüler** bir yapıdadır.
|
||||
Tüm işlemler `ServiceRegistry` tarafından kontrol edilir,
|
||||
ve sonuçlar SDK genelinde otomatik olarak paylaşılır.
|
||||
|
||||
> 🔗 Tam uyumlu servisler:
|
||||
> **EventService**, **AnalyticsService**, **PopupService**, **EconomyData**, **RemoteConfigService**
|
||||
|
||||
---
|
||||
|
||||
**Prepared by:** Emir Han MAMAK
|
||||
|
||||
**Version:** 1.1.0 (2025.12)
|
||||
|
||||
**Module:** ShiroginSDK.Runtime.Services.Implementations.IAP
|
||||
|
||||
3
Assets/ShiroginSDK/Documents/IAP/IAPService.md.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e3e15d2313f244849429fc3d1b530798
|
||||
timeCreated: 1760522167
|
||||
3
Assets/ShiroginSDK/Documents/RemoteConfig.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3562bf0ca8ce484a8189bddcdd5c9177
|
||||
timeCreated: 1760703724
|
||||
244
Assets/ShiroginSDK/Documents/RemoteConfig/RemoteConfigService.md
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
# 📘 ShiroginSDK Remote Config (v1.0.0)
|
||||
|
||||
**Firebase Remote Config Integration • ServiceLocator Architecture • Local Fallback System**
|
||||
|
||||
Bu doküman, **ShiroginSDK v1.0.0** sürümünde güncellenen Remote Config sistemini açıklar.
|
||||
Sistem, Firebase Remote Config verilerini dinamik olarak çeker, `RemoteConfigData` ile birleştirir ve local cache sayesinde offline durumda dahi çalışmaya devam eder.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 1. Firebase Remote Config Kurulumu
|
||||
|
||||
### 🔹 Adım 1 — Firebase Projesini Aç
|
||||
1. [https://console.firebase.google.com](https://console.firebase.google.com) adresine gidin.
|
||||
2. Projenizi seçin ve sol menüden **Remote Config** sekmesini açın.
|
||||
|
||||
---
|
||||
|
||||
### 🔹 Adım 2 — Yeni Parametre veya Grup Oluştur
|
||||
Firebase Remote Config ekranında, SDK’daki `RemoteConfigData` değişkenlerini temsil edecek parametreleri oluşturun.
|
||||
|
||||
#### 🖼️ Yeni Parametre Ekleme:
|
||||

|
||||
|
||||
#### 🖼️ Yeni Grup Oluşturma:
|
||||

|
||||
|
||||
Parametrelerinizi mantıksal gruplar hâlinde düzenlemek, **ShiroginSDK**’nin `selectedRemoteGroup` seçeneğiyle eşleşmesini kolaylaştırır.
|
||||
|
||||
---
|
||||
|
||||
### 🔹 Adım 3 — JSON Formatı ile Firebase’e Aktarma
|
||||
`RemoteConfigDefinition` ScriptableObject üzerinden **Import from RemoteConfigData** butonu ile tüm değişkenleri otomatik olarak senkronize edebilirsiniz.
|
||||
Daha sonra **Copy JSON to Clipboard** diyerek aşağıdaki formatta Firebase’e yapıştırın:
|
||||

|
||||
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"shiroginsdk_remote_config": {
|
||||
"hp_scale": 100,
|
||||
"target_fps": 60,
|
||||
"rewarded_after_interstitial_time": 50
|
||||
}
|
||||
}
|
||||
````
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 2. Sistem Mimarisi
|
||||
|
||||
| Bileşen | Tür | Açıklama |
|
||||
| ----------------------- | ------------- | -------------------------------------------------------------- |
|
||||
| **RemoteConfigService** | `ServiceBase` | Firebase’den verileri çeker, cache’ler ve event yayınlar. |
|
||||
| **RemoteConfigData** | `BaseData` | Çekilen verilerin local kopyasını ve erişim API’sini tutar. |
|
||||
| **FirebaseService** | `ServiceBase` | Firebase bağlantı yönetimini sağlar. |
|
||||
| **IEventService** | `Interface` | Güncelleme event’lerini tetikler (`RemoteConfigUpdatedEvent`). |
|
||||
|
||||
---
|
||||
|
||||
## 🧠 3. Başlatma ve Yaşam Döngüsü
|
||||
|
||||
Tüm servisler `ShiroginServiceRegistry` tarafından yönetilir:
|
||||
|
||||
```csharp
|
||||
ShiroginServiceRegistry.InitializeAll();
|
||||
```
|
||||
|
||||
Bu çağrı ile:
|
||||
|
||||
* `FirebaseService`
|
||||
* `DataService`
|
||||
* `RemoteConfigService`
|
||||
* `EventService`
|
||||
otomatik olarak başlatılır ve `ServiceLocator`’a kaydedilir.
|
||||
|
||||
---
|
||||
|
||||
## 🔄 4. Çalışma Akışı
|
||||
|
||||
```
|
||||
Firebase Remote Config
|
||||
↓
|
||||
RemoteConfigService (Fetch + Cache)
|
||||
↓
|
||||
RemoteConfigData (Merge)
|
||||
↓
|
||||
EventService → RemoteConfigUpdatedEvent
|
||||
↓
|
||||
SDK Modülleri (Economy, Ads, Gameplay)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧩 5. Kullanım
|
||||
|
||||
### 🔹 Verilere Erişim
|
||||
|
||||
Artık `ServiceLocator` tabanlı erişim kullanılır:
|
||||
|
||||
```csharp
|
||||
var dataService = ServiceLocator.Get<IDataService>();
|
||||
var config = dataService.Get<RemoteConfigData>();
|
||||
|
||||
int hpScale = config.GetInt("hp_scale", 100);
|
||||
float fps = config.GetFloat("target_fps", 60f);
|
||||
string storeJson = config.GetString("store_data");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🔹 Firebase’den Manuel Veri Yenileme
|
||||
|
||||
```csharp
|
||||
var remoteConfig = ServiceLocator.Get<IRemoteConfigService>();
|
||||
remoteConfig.ForceRefresh();
|
||||
```
|
||||
|
||||
Bu işlem, Firebase’den en son JSON’u çeker, cache’i günceller ve
|
||||
otomatik olarak `RemoteConfigUpdatedEvent` yayınlar.
|
||||
|
||||
---
|
||||
|
||||
### 🔹 Event Dinleme
|
||||
|
||||
Güncellenmiş Remote Config verisini yakalamak için:
|
||||
|
||||
```csharp
|
||||
var eventService = ServiceLocator.Get<IEventService>();
|
||||
eventService.Subscribe<ShiroginEvents.RemoteConfigUpdatedEvent>(e =>
|
||||
{
|
||||
Debug.Log($"RemoteConfig updated: {e.RawJson}");
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🪙 6. Local Fallback (Offline Çalışma)
|
||||
|
||||
* Remote fetch başarısız olursa, `RemoteConfigService` local cache’i (`RemoteConfigData`) kullanır.
|
||||
* Cache 24 saatten daha yeni ise remote fetch atlanır.
|
||||
* Veriler `Application.persistentDataPath || PlayerPrefs` altında JSON olarak saklanır.
|
||||
|
||||
```csharp
|
||||
var data = ServiceLocator.Get<IDataService>().Get<RemoteConfigData>();
|
||||
Debug.Log($"Cached HP Scale: {data.GetInt("hp_scale")}");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧾 7. Firebase JSON Yapısı
|
||||
|
||||
**Örnek:**
|
||||
|
||||
```json
|
||||
{
|
||||
"ShiroginSDK": {
|
||||
"hp_scale": 120,
|
||||
"target_fps": 60,
|
||||
"remove_ads_popup_active": true,
|
||||
"enemy_hp_multiplier": "1,1.5,2,2.5,3",
|
||||
"store_data": "{\"shopItems\":[{\"id\":1,\"name\":\"Starter Pack\",\"price\":100}]}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bu JSON, `SDKConfig.selectedRemoteGroup` alanında belirtilen grup adıyla eşleşir (örnek: `"ShiroginSDK"`).
|
||||
|
||||
---
|
||||
|
||||
## 🧩 8. RemoteConfigService API’si
|
||||
|
||||
| Fonksiyon | Açıklama |
|
||||
| -------------------------------------------- | -------------------------------------- |
|
||||
| `ForceRefresh()` | Firebase’den manuel veri çekimi yapar. |
|
||||
| `GetInt(string key, int defaultValue)` | Sayısal değer döner. |
|
||||
| `GetFloat(string key, float defaultValue)` | Ondalık değer döner. |
|
||||
| `GetBool(string key, bool defaultValue)` | Mantıksal değer döner. |
|
||||
| `GetString(string key, string defaultValue)` | Metin döner. |
|
||||
|
||||
---
|
||||
|
||||
## 🧰 9. RemoteConfigDefinition (Editor Tool)
|
||||
|
||||
### Konum
|
||||
|
||||
`Assets/ShiroginSDK/Editor/RemoteConfig/RemoteConfigDefinitionEditor.cs`
|
||||
|
||||
Bu araç, Firebase Remote Config parametrelerini düzenlemek, senkronize etmek ve JSON oluşturmak için görsel arayüz sağlar.
|
||||
|
||||
| Buton | İşlev |
|
||||
| ----------------------------------- | ---------------------------------------------- |
|
||||
| ✅ **Validate Keys** | Boş veya tekrarlanan anahtarları kontrol eder. |
|
||||
| 🔤 **Sort by Key** | Anahtarları alfabetik sıraya dizer. |
|
||||
| 📋 **Copy JSON to Clipboard** | Firebase’e yapıştırılabilir JSON oluşturur. |
|
||||
| ⬆️ **Import from RemoteConfigData** | SDK tarafındaki alanları otomatik ekler. |
|
||||
|
||||
---
|
||||
|
||||
## 🌍 10. Offline & Event Akışı
|
||||
|
||||
**Senaryo 1 – Online:**
|
||||
|
||||
1. Firebase bağlantısı kurulur
|
||||
2. JSON çekilir
|
||||
3. Cache güncellenir
|
||||
4. `RemoteConfigUpdatedEvent` tetiklenir
|
||||
5. SDK modülleri (Ads, Economy vb.) yeni ayarları uygular
|
||||
|
||||
**Senaryo 2 – Offline:**
|
||||
|
||||
1. Remote fetch başarısız olur
|
||||
2. Local cache kullanılır
|
||||
3. Oyun eski verilerle devam eder
|
||||
|
||||
---
|
||||
|
||||
## 📹 11. Kurulum Videosu
|
||||
|
||||
🎥 [Remote Config Setup Video](https://dl.dropboxusercontent.com/scl/fi/vm3z2wpcgudm3th15pkwb/NVIDIA_Overlay_IM0A21PVZv.mp4?rlkey=olnmi1xn4qzfp8ug04w3qfaoo&dl=0)
|
||||
|
||||
---
|
||||
|
||||
## 🧱 12. Özet
|
||||
|
||||
| Konsept | Açıklama |
|
||||
| ----------------------- | --------------------------------------------------- |
|
||||
| **Mimari** | `ServiceLocator` tabanlı bağımsız servis yapısı |
|
||||
| **Firebase Bağlantısı** | `FirebaseService` event’leriyle senkronize |
|
||||
| **Cache Yönetimi** | 24 saatlik otomatik yenileme kontrolü |
|
||||
| **Event Forwarding** | `RemoteConfigUpdatedEvent` ile global bildirim |
|
||||
| **Offline Desteği** | Local cache fallback mekanizması |
|
||||
| **Tip Güvenli Erişim** | `GetInt`, `GetString`, `GetBool` yardımcı metotları |
|
||||
|
||||
---
|
||||
|
||||
**Prepared by:** Emir Han MAMAK
|
||||
|
||||
**Version:** 1.1.0 (2025.12)
|
||||
|
||||
**Module:** ShiroginSDK.Runtime.Services.Implementations.RemoteConfig
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 52b42bbed015431e9025e5b5eb0952cb
|
||||
timeCreated: 1760369687
|
||||
3
Assets/ShiroginSDK/Documents/Service.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f255a838e5b64d92a828601e2e1d7da0
|
||||
timeCreated: 1760705299
|
||||
326
Assets/ShiroginSDK/Documents/Service/Services.md
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
# 🧩 ShiroginSDK Service Architecture (v1.0.0)
|
||||
|
||||
**Modular • Service-Oriented • Event-Driven Core Framework**
|
||||
|
||||
ShiroginSDK’nin servis çekirdeği, tüm SDK modüllerinin (IAP, Popup, Theme, Analytics, RemoteConfig vb.) **tek merkezden yönetilmesini** sağlayan soyut bir sistemdir.
|
||||
Bu sistem, Unity projelerinde **bağımlılık enjeksiyonu**, **servis yaşam döngüsü** ve **event forwarding** gibi prensipleri uygular.
|
||||
|
||||
---
|
||||
|
||||
## 🧱 Temel Yapı
|
||||
|
||||
| Bileşen | Görev |
|
||||
|----------|--------|
|
||||
| **IShiroginService** | Her servisin uyması gereken temel sözleşme (interface) |
|
||||
| **ServiceBase** | Ortak yaşam döngüsü (Initialize / Dispose) davranışını sağlar |
|
||||
| **ServiceLocator** | Global erişim noktası, tüm servis örneklerini saklar |
|
||||
| **ShiroginServiceRegistry** | Servislerin otomatik başlatılmasını ve kayıt edilmesini yönetir |
|
||||
| **IDataService**, **IEventService** vb. | Özelleşmiş interface türleri (örnek: veri yönetimi, event yönetimi) |
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Mimarinin Amacı
|
||||
|
||||
- 🔁 Servislerin bağımlılıklarını merkezi olarak yönetmek
|
||||
- 🧩 Servislerin birbiriyle loosely coupled (gevşek bağlı) çalışmasını sağlamak
|
||||
- 🧠 Modül bazlı mimariyle SDK’nın kolay genişletilmesini mümkün kılmak
|
||||
- 🧰 Editor araçları, runtime servisler ve sistem olaylarını tek lifecycle üzerinden yürütmek
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Servis Yaşam Döngüsü
|
||||
|
||||
Tüm servisler aşağıdaki sırayla çalışır:
|
||||
|
||||
```
|
||||
|
||||
SDKInitializer
|
||||
↓
|
||||
ShiroginServiceRegistry.InitializeAll()
|
||||
↓
|
||||
ServiceLocator.Register<T>()
|
||||
↓
|
||||
OnInitialize() çağrısı
|
||||
↓
|
||||
EventService aracılığıyla sistem olayları
|
||||
↓
|
||||
OnDispose() (Oyun kapanışı veya reset)
|
||||
|
||||
````
|
||||
|
||||
---
|
||||
|
||||
## 🧠 1. IShiroginService
|
||||
|
||||
Tüm servislerin temel interface’i.
|
||||
|
||||
```csharp
|
||||
public interface IShiroginService
|
||||
{
|
||||
void Initialize();
|
||||
void Dispose();
|
||||
bool IsInitialized { get; }
|
||||
}
|
||||
````
|
||||
|
||||
Amaç: Her servisin başlatma ve temizleme rutinini standartlaştırmak.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 2. ServiceBase
|
||||
|
||||
`MonoBehaviour`’e ihtiyaç duymadan servislerin yaşam döngüsünü yönetir.
|
||||
Tüm custom servisler bu sınıftan türetilir.
|
||||
|
||||
```csharp
|
||||
public abstract class ServiceBase : IShiroginService
|
||||
{
|
||||
public bool IsInitialized { get; private set; }
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (IsInitialized) return;
|
||||
OnInitialize();
|
||||
IsInitialized = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
OnDispose();
|
||||
IsInitialized = false;
|
||||
}
|
||||
|
||||
protected abstract void OnInitialize();
|
||||
protected virtual void OnDispose() { }
|
||||
}
|
||||
```
|
||||
|
||||
> 🔹 Her servis `OnInitialize()` ve `OnDispose()` metodlarını override ederek kendi kurulum/temizlik işlemlerini yapar.
|
||||
> 🔹 `DontDestroyOnLoad` kullanımı veya `MonoBehaviour` bağımlılığı olmadan çalışır.
|
||||
|
||||
---
|
||||
|
||||
## 🧭 3. ServiceLocator
|
||||
|
||||
Servislerin global erişim noktasını oluşturur.
|
||||
İçerisinde **tip güvenli bir dictionary** tutar ve `Get<T>()` ile erişim sağlar.
|
||||
|
||||
```csharp
|
||||
var dataService = ServiceLocator.Get<IDataService>();
|
||||
var eventService = ServiceLocator.Get<IEventService>();
|
||||
```
|
||||
|
||||
Yeni servis kaydı:
|
||||
|
||||
```csharp
|
||||
ServiceLocator.Register<IDataService>(new DataService());
|
||||
```
|
||||
|
||||
> 📌 ServiceLocator, **Singleton yerine Dependency Injection** felsefesine yakındır.
|
||||
> Servislerin instance yönetimi `ShiroginServiceRegistry` tarafından yapılır.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 4. ShiroginServiceRegistry
|
||||
|
||||
Tüm servislerin oluşturulmasından, sırayla başlatılmasından ve kapatılmasından sorumludur.
|
||||
|
||||
```csharp
|
||||
public static class ShiroginServiceRegistry
|
||||
{
|
||||
public static void InitializeAll()
|
||||
{
|
||||
// ------------------------------------------------------------------
|
||||
// 🧩 CORE LAYER
|
||||
// ------------------------------------------------------------------
|
||||
RegisterAndInit<IEventService>(new EventService()); // Events backbone
|
||||
RegisterAndInit<IDataService>(new DataService()); // Save/Load system
|
||||
RegisterAndInit<ICoroutineRunnerService>(new CoroutineRunnerService()); // Global coroutine executor
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 🔥 BACKEND LAYER
|
||||
// ------------------------------------------------------------------
|
||||
RegisterAndInit<IFirebaseService>(new FirebaseService()); // Firebase Analytics + Remote Config
|
||||
RegisterAndInit<IRemoteConfigService>(new RemoteConfigService()); // Uses FirebaseService
|
||||
RegisterAndInit<IAppsFlyerService>(new AppsFlyerService()); // AppsFlyer analytics SDK
|
||||
RegisterAndInit<IFacebookService>(new FacebookService()); // Facebook SDK
|
||||
RegisterAndInit<IAnalyticsService>(new AnalyticsService()); // Unified analytics forwarding
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 💰 ECONOMY & ADS
|
||||
// ------------------------------------------------------------------
|
||||
RegisterAndInit<IIAPService>(new IAPService()); // In-app purchases
|
||||
RegisterAndInit<IAdsService>(new AdsService()); // Rewarded & Interstitial ads
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 🎨 UI / PRESENTATION LAYER
|
||||
// ------------------------------------------------------------------
|
||||
RegisterAndInit<IThemeService>(new ThemeService()); // UI themes / skins
|
||||
RegisterAndInit<IPopupService>(new PopupService()); // Global popup queue system
|
||||
|
||||
UnityEngine.Debug.Log("[ShiroginSDK] ✅ All services initialized successfully.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers and initializes a service with its interface type.
|
||||
/// </summary>
|
||||
private static void RegisterAndInit<TInterface>(ServiceBase service) where TInterface : class
|
||||
{
|
||||
// Register by interface type
|
||||
ServiceLocator.Register<TInterface>((TInterface)(object)service);
|
||||
service.Initialize();
|
||||
}
|
||||
|
||||
public static void DisposeAll()
|
||||
{
|
||||
ServiceLocator.Clear();
|
||||
UnityEngine.Debug.Log("[ShiroginSDK] 🧹 All services disposed.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> ✅ Servisler initialize sırasına göre çalışır, dispose’da ters sırayla kapanır.
|
||||
> 🧩 Yeni servis eklemek yalnızca ` RegisterAndInit<IPopupService>(new MyService());` satırı eklemek kadar kolaydır.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 5. Yeni Servis Oluşturma
|
||||
|
||||
Aşağıda yeni bir servis (örnek: `AudioService`) nasıl ekleneceği gösterilmiştir.
|
||||
|
||||
```csharp
|
||||
using ShiroginSDK.Runtime.Services.Base;
|
||||
using ShiroginSDK.Runtime.Services.Interfaces;
|
||||
using UnityEngine;
|
||||
|
||||
public class AudioService : ServiceBase, IAudioService
|
||||
{
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
Debug.Log("[AudioService] Initialized");
|
||||
// Audio mixer setup, volume cache, etc.
|
||||
}
|
||||
|
||||
protected override void OnDispose()
|
||||
{
|
||||
Debug.Log("[AudioService] Disposed");
|
||||
}
|
||||
|
||||
public void PlaySFX(string clipName)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Kayıt etmek için:**
|
||||
|
||||
```csharp
|
||||
RegisterAndInit<IEventService>(new AudioService());
|
||||
```
|
||||
|
||||
Artık global erişim mümkündür:
|
||||
|
||||
```csharp
|
||||
ServiceLocator.Get<IAudioService>().PlaySFX("coin_pickup");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 6. Servis Arası Etkileşim
|
||||
|
||||
Her servis `ServiceLocator` aracılığıyla diğer servislere erişebilir:
|
||||
|
||||
```csharp
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
var dataService = ServiceLocator.Get<IDataService>();
|
||||
var eventService = ServiceLocator.Get<IEventService>();
|
||||
eventService.Invoke(new GameStartedEvent());
|
||||
}
|
||||
```
|
||||
|
||||
> Bu sayede servisler birbirine doğrudan bağımlı değil, **aracılı** çalışır.
|
||||
> Bu yapı **test edilebilirliği** ve **mock servis** kullanımını kolaylaştırır.
|
||||
|
||||
---
|
||||
|
||||
## 🧠 7. İleri Konular
|
||||
|
||||
### 🔹 CoroutineRunnerService
|
||||
|
||||
`MonoBehaviour` bağlamında coroutine çalıştırmak için soyut bir arayüz sunar.
|
||||
`CoroutineRunner.Start(...)` ile tüm SDK servisleri coroutine başlatabilir.
|
||||
|
||||
### 🔹 IDataService
|
||||
|
||||
Oyun verilerinin (`BaseData`) yönetimini sağlar: `Get<T>()`, `SaveAll()`, `ToJson()` vb.
|
||||
|
||||
### 🔹 IEventService
|
||||
|
||||
SDK genelinde event forwarding sağlar.
|
||||
Tüm servisler event’leri publish/subscribe ile paylaşır.
|
||||
Örneğin:
|
||||
|
||||
```csharp
|
||||
_eventService.Invoke(new ShiroginEvents.PurchaseCompletedEvent());
|
||||
```
|
||||
|
||||
### 🔹 Extensibility (Genişletilebilirlik)
|
||||
|
||||
Yeni servisler yalnızca şu 3 adıma ihtiyaç duyar:
|
||||
|
||||
1. `ServiceBase`’ten türet
|
||||
2. Gerekirse bir `IYourService` interface tanımla
|
||||
3. `ShiroginServiceRegistry.Register(new YourService())` çağrısı ekle
|
||||
|
||||
---
|
||||
|
||||
## 🔍 8. Debugging & Logging
|
||||
|
||||
Tüm servisler initialization sırasında log üretir.
|
||||
Hatalar `[ShiroginSDK]` etiketiyle konsola basılır.
|
||||
|
||||
Örnek:
|
||||
|
||||
```
|
||||
[PopupService] ✅ Initialized and bound to SDKConfig.
|
||||
[ThemeService] 🌈 Active theme set to 'Snow'
|
||||
[IAPService] 💳 Unity Purchasing initialized.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ 9. Performans Notları
|
||||
|
||||
* Servisler `DontDestroyOnLoad` veya `MonoBehaviour` objelerine bağlı değildir.
|
||||
* Tüm bağımlılıklar `ServiceLocator` üzerinden çözülür, böylece yükleme sırası kontrol altındadır.
|
||||
* Gereksiz singleton oluşturulmaz, yalnızca kullanılan servisler bellekte kalır.
|
||||
|
||||
---
|
||||
|
||||
## 🧾 10. Özet
|
||||
|
||||
| Özellik | Açıklama |
|
||||
| -------------------------- | --------------------------------------------- |
|
||||
| 🔄 **Lifecycle Yönetimi** | `ServiceBase` ve `ServiceRegistry` üzerinden |
|
||||
| 🧩 **Bağımlılık Yönetimi** | `ServiceLocator` ile type-safe çözüm |
|
||||
| 🚀 **Modüler Yapı** | Her modül bağımsız servis olarak çalışır |
|
||||
| 🧱 **Event-Driven** | `IEventService` ile sistem içi iletişim |
|
||||
| ⚙️ **Kolay Genişletme** | 3 satırda yeni servis ekleme |
|
||||
| 🧠 **Test Edilebilir** | Mock servislerle bağımsız testler yapılabilir |
|
||||
|
||||
---
|
||||
|
||||
**Prepared by:** Emir Han MAMAK
|
||||
|
||||
**Version:** 1.1.0 (2025.12)
|
||||
|
||||
**Module:** ShiroginSDK.Runtime.Services
|
||||
|
||||
---
|
||||
|
||||
> 📘 İpucu:
|
||||
> Servis sisteminin amacı “oyun sistemleri arasındaki sınırları netleştirmek”tir.
|
||||
> Bu yapıyı doğru kullandığında, SDK’nın her yeni modülü — IAP, Popup, RemoteConfig, Theme — sadece **bir servis olarak** eklenir.
|
||||
> Böylece ShiroginSDK, Unity’nin üstünde kendi mini operating system’ini oluşturur.
|
||||
3
Assets/ShiroginSDK/Documents/Service/Services.md.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 628d5666b26b45d683592368eac9c010
|
||||
timeCreated: 1760705260
|
||||
3
Assets/ShiroginSDK/Documents/UI.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 678e9dc85a964935a34eb45f1a113498
|
||||
timeCreated: 1760703765
|
||||
261
Assets/ShiroginSDK/Documents/UI/PopupService.md
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
# 📦 ShiroginSDK Popup Service (v1.0.0)
|
||||
|
||||
**Event-Driven Popup Management • ServiceLocator Integration • DOTween Animations**
|
||||
|
||||
Bu doküman, **ShiroginSDK v1.0.0** sürümünde güncellenen `PopupService` sistemini açıklar.
|
||||
Yeni mimari, `ServiceBase` tabanlı olup tüm servisler `ShiroginServiceRegistry` tarafından başlatılır.
|
||||
`PopupService`, `EventService` üzerinden tetiklenen event’lere yanıt verir ve `PopupRepository`’deki prefab’lar aracılığıyla popup’ları yönetir.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 1. Genel Bakış
|
||||
|
||||
`PopupService`, oyun boyunca kullanıcıya gösterilen tüm popup’ları (ödül, hata, bağlantı hatası, satın alma, reklam vb.) kontrol eder.
|
||||
|
||||
**Özellikler:**
|
||||
* ✅ `ServiceBase` tabanlı bağımsız servis yapısı
|
||||
* ✅ `ServiceLocator` ile erişim
|
||||
* ✅ `EventService` üzerinden otomatik popup tetikleme
|
||||
* ✅ `DOTween` tabanlı açılış / kapanış animasyonları
|
||||
* ✅ `PopupRepository` üzerinden prefab yönetimi
|
||||
* ✅ Otomatik queue sistemi (popup’lar sırayla gösterilir)
|
||||
|
||||
---
|
||||
|
||||
## 🧩 2. Mimari Bileşenler
|
||||
|
||||
| Bileşen | Tip | Açıklama |
|
||||
|---------------------|------------------|-----------|
|
||||
| **PopupService** | `ServiceBase` | Tüm popup kuyruğunu ve animasyonları yönetir. |
|
||||
| **PopupRepository** | `ScriptableObject` | Popup prefab referanslarını tutar. |
|
||||
| **UIPopupBase** | `MonoBehaviour` | Her popup prefab’ının temel sınıfıdır. |
|
||||
|
||||
---
|
||||
|
||||
## 🧠 3. Servis Mimarisi
|
||||
|
||||
### 🔹 Başlatma
|
||||
|
||||
Tüm servisler otomatik olarak `ShiroginServiceRegistry.InitializeAll()` çağrısı ile başlatılır.
|
||||
|
||||
```csharp
|
||||
ShiroginServiceRegistry.InitializeAll();
|
||||
````
|
||||
|
||||
Bu çağrı `EventService`, `PopupService`, `AnalyticsService`, `IAPService` gibi tüm servisleri oluşturur ve `ServiceLocator`’a kaydeder.
|
||||
|
||||
---
|
||||
|
||||
### 🔹 Erişim
|
||||
|
||||
`PopupService` artık singleton değil.
|
||||
Servise erişim `ServiceLocator` üzerinden yapılır:
|
||||
|
||||
```csharp
|
||||
var popupService = ServiceLocator.Get<IPopupService>();
|
||||
popupService.Show(PopupType.RewardClaimed, eventData);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🪄 4. Popup Gösterme Yöntemleri
|
||||
|
||||
### 🔸 1️⃣ EventService Üzerinden Otomatik Gösterim
|
||||
|
||||
`PopupService`, `IEventService`’e abonedir ve belirli `ShiroginEvents` event’lerine yanıt verir.
|
||||
Aşağıdaki event’ler otomatik olarak popup tetikler:
|
||||
|
||||
| Event Tipi | Gösterilen PopupType |
|
||||
| ---------------------------- | --------------------------------- |
|
||||
| `RewardClaimedEvent` | `PopupType.RewardClaimed` |
|
||||
| `PurchaseCompletedEvent` | `PopupType.PurchaseSuccess` |
|
||||
| `PurchaseFailedEvent` | `PopupType.PurchaseFailed` |
|
||||
| `NoConnectionEvent` | `PopupType.NoConnection` |
|
||||
| `RewardedAdUnavailableEvent` | `PopupType.RewardedAdUnavailable` |
|
||||
|
||||
**Örnek:**
|
||||
|
||||
```csharp
|
||||
var eventService = ServiceLocator.Get<IEventService>();
|
||||
eventService.Invoke(new ShiroginEvents.RewardClaimedEvent("daily_bonus", "Daily Reward", 100, "Gold"));
|
||||
```
|
||||
|
||||
`PopupService`, bu event’i dinler ve otomatik olarak `RewardClaimed` popup’ını sıraya alır.
|
||||
|
||||
---
|
||||
|
||||
### 🔸 2️⃣ Kod Üzerinden Manuel Gösterim
|
||||
|
||||
```csharp
|
||||
var popupService = ServiceLocator.Get<IPopupService>();
|
||||
popupService.Show(PopupType.NoConnection, new ShiroginEvents.NoConnectionEvent());
|
||||
```
|
||||
|
||||
Bu yöntemle event olmadan da popup manuel olarak sıraya eklenebilir.
|
||||
|
||||
---
|
||||
|
||||
## 🧩 5. Yeni Popup Eklemek
|
||||
|
||||
### 1️⃣ Yeni Prefab Oluştur
|
||||
|
||||
1. `Assets/ShiroginSDK/UI/Popups/` klasörüne git.
|
||||
2. Yeni prefab oluştur (örnek: `UIPopup_LevelUp`).
|
||||
3. `UIPopupBase`’den türeyen script ekle:
|
||||
|
||||
```csharp
|
||||
using UnityEngine;
|
||||
using ShiroginSDK.Runtime.UI.Scripts.UI.Base;
|
||||
|
||||
public class UIPopup_LevelUp : PopupBase
|
||||
{
|
||||
[SerializeField] private TMPro.TextMeshProUGUI levelText;
|
||||
|
||||
public override void Initialize(object data)
|
||||
{
|
||||
if (data is ShiroginEvents.PlayerLevelUpEvent e)
|
||||
levelText.text = $"LEVEL {e.NewLevel}";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ PopupType Enum’una Ekle
|
||||
|
||||
```csharp
|
||||
public enum PopupType
|
||||
{
|
||||
RewardClaimed,
|
||||
PurchaseSuccess,
|
||||
LevelUp,
|
||||
NoConnection,
|
||||
PurchaseFailed,
|
||||
RewardedAdUnavailable
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ PopupRepository’ye Ekle
|
||||
|
||||
1. `Assets/Resources/PopupRepository.asset` dosyasını aç.
|
||||
2. Yeni satır ekle:
|
||||
|
||||
* **PopupType:** `LevelUp`
|
||||
* **Prefab:** `UIPopup_LevelUp`
|
||||
|
||||
---
|
||||
|
||||
### 4️⃣ Test Et
|
||||
|
||||
```csharp
|
||||
var popupService = ServiceLocator.Get<IPopupService>();
|
||||
popupService.Show(PopupType.LevelUp, new ShiroginEvents.PlayerLevelUpEvent(9, 10, 500));
|
||||
```
|
||||
|
||||
veya event tabanlı:
|
||||
|
||||
```csharp
|
||||
ServiceLocator.Get<IEventService>().Invoke(new ShiroginEvents.PlayerLevelUpEvent(9, 10, 500));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎬 6. Animasyon ve Kuyruk Sistemi
|
||||
|
||||
Popup’lar sırayla gösterilir.
|
||||
Yeni bir popup çağrıldığında, mevcut popup kapanana kadar bekler.
|
||||
Kapanış tamamlandığında sıradaki popup açılır.
|
||||
|
||||
**Akış:**
|
||||
|
||||
```
|
||||
RewardClaimed → PurchaseSuccess → NoConnection
|
||||
```
|
||||
|
||||
**DOTween Animasyonları:**
|
||||
|
||||
* Fade in/out (arka plan karartması)
|
||||
* Scale up (açılış animasyonu)
|
||||
* Scale down (kapanış animasyonu)
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 7. Kullanılabilir API
|
||||
|
||||
| Fonksiyon / Özellik | Açıklama |
|
||||
| ------------------------------------- | ------------------------------------------- |
|
||||
| `Show(PopupType, object)` | Popup gösterir. |
|
||||
| `Enqueue(PopupType, object)` | Popup’ı sıraya ekler. |
|
||||
| `SetCanvas(Canvas canvas)` | Root canvas atanır. |
|
||||
| `SetRepository(PopupRepository repo)` | Repository dinamik olarak değiştirilebilir. |
|
||||
|
||||
---
|
||||
---
|
||||
|
||||
## 🧩 8. Servis Entegrasyonu
|
||||
|
||||
PopupService, şu servislerle entegre çalışır:
|
||||
|
||||
| Servis | Amaç |
|
||||
| ------------------- | ----------------------------------- |
|
||||
| `IEventService` | Popup tetikleme event’lerini dinler |
|
||||
| `IDataService` | Gerekirse popup bazlı veri erişimi |
|
||||
| `IAnalyticsService` | Popup açılma logları (isteğe bağlı) |
|
||||
|
||||
Bu sistem, SDK genelinde **event-driven** iletişim modeline bağlıdır.
|
||||
Hiçbir servis diğerine doğrudan referans vermez — tüm bağlantılar `ServiceLocator` üzerinden yapılır.
|
||||
|
||||
---
|
||||
|
||||
## 🧱 10. Örnek Dosya Yapısı
|
||||
|
||||
```
|
||||
Assets/
|
||||
└── ShiroginSDK/
|
||||
├── Runtime/
|
||||
│ ├── Core/
|
||||
│ │ └── SDKInitializer.cs
|
||||
│ ├── Services/
|
||||
│ │ ├── Base/
|
||||
│ │ └── Implementations/
|
||||
│ │ └── PopupService.cs
|
||||
│ └── UI/
|
||||
│ ├── PopupBase.cs
|
||||
│ └── UIPopup_LevelUp.cs
|
||||
└── Resources/
|
||||
└── PopupRepository.asset
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧾 11. Özet
|
||||
|
||||
| İşlem | Nasıl Yapılır | Örnek |
|
||||
| --------------- | ------------------------------------- | ----------------------------------------------------------------- |
|
||||
| Popup göster | `ServiceLocator.Get<IPopupService>()` | `popupService.Show(PopupType.RewardClaimed, data)` |
|
||||
| Event tetikle | `ServiceLocator.Get<IEventService>()` | `eventService.Invoke(new ShiroginEvents.RewardClaimedEvent(...))` |
|
||||
| Yeni popup ekle | Prefab + Enum + Repository | `UIPopup_LevelUp` |
|
||||
| Kuyruk sistemi | Otomatik | Popup kapanmadan yeni popup gösterilmez |
|
||||
|
||||
---
|
||||
|
||||
## ✅ 12. Örnek Akış
|
||||
|
||||
1. Oyuncu günlük ödül alır
|
||||
2. `RewardClaimedEvent` tetiklenir
|
||||
3. `IEventService` popup servisine sinyal gönderir
|
||||
4. `PopupService` `RewardClaimed` popup’ını sıraya ekler
|
||||
5. DOTween ile popup açılır
|
||||
6. Kapanış sonrası sıradaki popup gösterilir
|
||||
|
||||
---
|
||||
|
||||
**Prepared by:** Emir Han MAMAK
|
||||
|
||||
**Version:** 1.1.0 (2025.12)
|
||||
|
||||
**Module:** ShiroginSDK.Runtime.Services.Implementations.UI.PopupService
|
||||
|
||||
---
|
||||
3
Assets/ShiroginSDK/Documents/UI/PopupService.md.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 78d0c951bdfc443e97d3e13bf874f549
|
||||
timeCreated: 1760031740
|
||||
251
Assets/ShiroginSDK/Documents/UI/ThemeService.md
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
# 🎨 ShiroginSDK Theme System (v1.0.0)
|
||||
|
||||
**Dynamic UI Skin Management • ServiceLocator Architecture • Scriptable Themes**
|
||||
|
||||
ShiroginSDK’nin **Theme System**’i, oyun içi UI öğelerinin (ikonlar, arka planlar, butonlar vb.) görünümünü merkezi ve modüler bir şekilde yönetmeni sağlar.
|
||||
Tüm temalar **enum tabanlı**, **ScriptableObject destekli**, **event-driven** bir yapıda çalışır.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 1. Amaç
|
||||
|
||||
Bu sistemin hedefi, farklı temalar arasında **anında geçiş** sağlamak ve
|
||||
UI öğelerinin görünümünü **kod değiştirmeden** yönetmektir.
|
||||
|
||||
**Temel Hedefler:**
|
||||
- 🎨 Farklı temalar arasında runtime geçiş
|
||||
- 🔁 Tema değiştiğinde tüm UI’nın otomatik yenilenmesi
|
||||
- 💾 Oyuncunun seçtiği temanın kaydedilmesi (`ThemeData`)
|
||||
- 🧩 Enum tabanlı erişim (string hatalarına karşı güvenli)
|
||||
- ⚡ `ScriptableObject` tabanlı profil yapısı
|
||||
|
||||
---
|
||||
|
||||
## 🧱 2. Sistem Bileşenleri
|
||||
|
||||
| Bileşen | Açıklama |
|
||||
|----------|-----------|
|
||||
| **ThemeAssetType** | Görsel tiplerini (ikon, arka plan, vb.) enum olarak listeler |
|
||||
| **ThemeProfile** | Tek bir temaya ait sprite eşlemelerini tutar |
|
||||
| **ThemeRepository** | Tüm `ThemeProfile` varlıklarını barındırır |
|
||||
| **ThemeService** | Aktif temayı yönetir, `ServiceLocator` ile erişilir |
|
||||
| **ThemeImage** | UI `Image` bileşenlerine otomatik sprite ataması yapar |
|
||||
| **ThemeData** | Oyuncunun aktif temasını ve açılmış temaları saklar |
|
||||
|
||||
---
|
||||
|
||||
## 🧩 3. ThemeAssetType.cs
|
||||
|
||||
UI görsellerinin türlerini `enum` olarak tanımlar.
|
||||
Kod içinde string kullanmadan, **type-safe** erişim sağlar.
|
||||
|
||||
```csharp
|
||||
public enum ThemeAssetType
|
||||
{
|
||||
None = 0,
|
||||
|
||||
// ICONS
|
||||
Icon_SettingsButton,
|
||||
Icon_VibrationButton,
|
||||
|
||||
// BACKGROUNDS
|
||||
Background_MainMenu,
|
||||
Background_PopupSuccess,
|
||||
|
||||
// CURRENCIES
|
||||
Icon_Currency_Gold,
|
||||
Icon_Currency_Gem,
|
||||
}
|
||||
````
|
||||
---
|
||||
|
||||
## 🗂️ 5. ThemeRepository
|
||||
|
||||
Tüm temaları tek bir ScriptableObject altında toplar.
|
||||
|
||||
Örneğin:
|
||||
|
||||
* `Default`
|
||||
* `Dark`
|
||||
* `Snow`
|
||||
* `Halloween`
|
||||
|
||||
Unity’de oluşturmak için:
|
||||
|
||||
> **Right Click → Create → ShiroginSDK → Theme → Theme Repository**
|
||||
|
||||
Ardından `ThemeProfile` varlıklarını listeye ekle.
|
||||
|
||||
---
|
||||
|
||||
## 🧠 6. ThemeService (Yeni Sistem)
|
||||
|
||||
`ThemeService`, artık `ServiceBase`’ten türetilir ve `ServiceLocator` aracılığıyla erişilir.
|
||||
Tüm bağımlılıklarını (`IDataService`, `IEventService`) otomatik çözer.
|
||||
|
||||
### Başlatma
|
||||
|
||||
`ShiroginServiceRegistry.InitializeAll();` çağrısı ile otomatik olarak başlatılır.
|
||||
`SDKConfig.themeRepository` üzerinden `ThemeRepository` referansını yükler.
|
||||
|
||||
```csharp
|
||||
var themeService = ServiceLocator.Get<IThemeService>();
|
||||
themeService.SetTheme("Snow");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🎨 Aktif Tema Değiştirme
|
||||
|
||||
```csharp
|
||||
var themeService = ServiceLocator.Get<IThemeService>();
|
||||
themeService.SetTheme("Dark");
|
||||
```
|
||||
|
||||
Bu işlem:
|
||||
|
||||
1. `_repository` içinden “Dark” temasını bulur
|
||||
2. `ThemeChanged` event’ini yayınlar
|
||||
3. `ThemeData.ActiveTheme`’i kaydeder
|
||||
4. Tüm `ThemeImage` bileşenlerini otomatik yeniler
|
||||
|
||||
---
|
||||
|
||||
### 🧩 Sprite Alma
|
||||
|
||||
```csharp
|
||||
var themeService = ServiceLocator.Get<IThemeService>();
|
||||
var icon = themeService.GetSprite(ThemeAssetType.Icon_SettingsButton);
|
||||
myButton.image.sprite = icon;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 💾 Kaydetme & Yükleme
|
||||
|
||||
Aktif tema `ThemeData` aracılığıyla otomatik olarak saklanır ve oyun açılışında geri yüklenir.
|
||||
|
||||
```csharp
|
||||
var dataService = ServiceLocator.Get<IDataService>();
|
||||
var themeData = dataService.Get<ThemeData>();
|
||||
|
||||
Debug.Log($"Active Theme: {themeData.ActiveTheme}");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧰 7. ThemeImage.cs
|
||||
|
||||
Herhangi bir `Image` bileşenine eklenir.
|
||||
Seçilen `ThemeAssetType`’a göre sprite’ı otomatik günceller.
|
||||
Tema değiştiğinde event’ler aracılığıyla yeniden sprite ataması yapılır.
|
||||
|
||||
**Kullanım:**
|
||||
|
||||
1. UI objene `ThemeImage` component’i ekle
|
||||
2. `assetType` alanında örneğin `Icon_SettingsButton` seç
|
||||
3. Tema değiştiğinde sprite otomatik değişir
|
||||
|
||||
---
|
||||
|
||||
## 💾 8. ThemeData.cs
|
||||
|
||||
Oyuncunun aktif temasını ve açılmış temalarını saklar.
|
||||
Oyun açılışında `DataService` tarafından otomatik yüklenir.
|
||||
|
||||
```csharp
|
||||
public class ThemeData : BaseData
|
||||
{
|
||||
protected override string PrefsKey => "THEME_DATA";
|
||||
|
||||
public string ActiveTheme = "Default";
|
||||
public List<string> UnlockedThemes = new() { "Default" };
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 9. Akış Mantığı
|
||||
|
||||
```
|
||||
[SDKInitializer]
|
||||
↓
|
||||
ThemeService → Load from ThemeRepository
|
||||
↓
|
||||
ThemeData.ActiveTheme → Set Active
|
||||
↓
|
||||
ThemeChanged Event
|
||||
↓
|
||||
ThemeImage components update automatically
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌈 10. Tema Geçişi Örneği
|
||||
|
||||
```csharp
|
||||
using ShiroginSDK.Runtime.Services.Interfaces;
|
||||
using UnityEngine;
|
||||
|
||||
public class ThemeSwitcher : MonoBehaviour
|
||||
{
|
||||
public void OnClick_SnowTheme()
|
||||
{
|
||||
ServiceLocator.Get<IThemeService>().SetTheme("Snow");
|
||||
}
|
||||
|
||||
public void OnClick_DefaultTheme()
|
||||
{
|
||||
ServiceLocator.Get<IThemeService>().SetTheme("Default");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌟 11. Özellikler
|
||||
|
||||
| Özellik | Açıklama |
|
||||
| ---------------------------- | -------------------------------------------- |
|
||||
| 💾 Kalıcı Kayıt | `ThemeData` aracılığıyla otomatik kaydedilir |
|
||||
| 🔄 Gerçek Zamanlı Güncelleme | Tema değişince tüm UI otomatik yenilenir |
|
||||
| 🧩 Modüler | Yeni tema eklemek yalnızca 1 dakika sürer |
|
||||
| 🎨 Editor Dostu | ScriptableObject tabanlı sistem |
|
||||
| ⚡ Optimize | Sadece aktif tema bellekte tutulur |
|
||||
| 🧱 Tip Güvenli | Enum tabanlı erişim ile string hatası yok |
|
||||
|
||||
---
|
||||
|
||||
## 💡 12. Geliştirici Tavsiyeleri
|
||||
|
||||
* Her temaya kısa, net bir isim ver (`Default`, `Dark`, `Snow`)
|
||||
* Sprite atlaslarını kullanarak performansı artır
|
||||
* `ThemeImage` ile manuel sprite değişiminden kaçın
|
||||
* Tema varlıklarını düzenli tut (`Assets/ShiroginSDK/Themes/`)
|
||||
* `ThemeRepository` içine tüm temaları dahil etmeyi unutma
|
||||
|
||||
---
|
||||
|
||||
## ✅ 13. Özet
|
||||
|
||||
ShiroginSDK Theme System v1.0.0:
|
||||
|
||||
* UI görsellerini tek yerden yönetmeni sağlar
|
||||
* Oyuncu seçimini kaydeder ve yeniden yükler
|
||||
* Enum tabanlı tip güvenli sistemle çalışır
|
||||
* `ServiceLocator` mimarisiyle SDK’nın diğer servisleriyle uyumludur
|
||||
|
||||
---
|
||||
|
||||
**Prepared by:** Emir Han MAMAK
|
||||
|
||||
**Version:** 1.1.0 (2025.12)
|
||||
|
||||
**Module:** ShiroginSDK.Runtime.Services.Implementations.UI.ThemeService
|
||||
|
||||
---
|
||||
**Scriptable Objects :**
|
||||
|
||||

|
||||

|
||||

|
||||
3
Assets/ShiroginSDK/Documents/UI/ThemeService.md.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e8bbe50da2eb4c5799bac59716cc0616
|
||||
timeCreated: 1760341956
|
||||
8
Assets/ShiroginSDK/Editor.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 71f30c3bc79174444af5a06024dd58d2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/ShiroginSDK/Editor/Bitbucket.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 557403d2360a1f84ab6d8e1d9ba77438
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
925
Assets/ShiroginSDK/Editor/Bitbucket/AssetRegistryEditor.cs
Normal file
|
|
@ -0,0 +1,925 @@
|
|||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.PackageManager;
|
||||
using UnityEditor.PackageManager.Requests;
|
||||
using UnityEngine.Networking;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using ShiroginSDK.Runtime.Core.SDK;
|
||||
using ShiroginSDK.Editor.Core;
|
||||
|
||||
namespace ShiroginSDK.Editor.Bitbucket
|
||||
{
|
||||
// --- DATA STRUCTURES ---
|
||||
[Serializable]
|
||||
public class VersionData
|
||||
{
|
||||
public string version;
|
||||
public string packageName; // NEW: Specific ID for this version (e.g., shirogin.sdk.appsflyer.6.17.72)
|
||||
public string url;
|
||||
public string docsWebUrl;
|
||||
public string docsDownloadUrl;
|
||||
public string releaseNotes;
|
||||
public string fileSize;
|
||||
public bool isExternal;
|
||||
public bool isUpm;
|
||||
public string upmId;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class PackageData
|
||||
{
|
||||
public string uniqueId;
|
||||
public string displayName;
|
||||
public string category;
|
||||
public VersionData[] versions;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class PackageManifest
|
||||
{
|
||||
public PackageData[] packages;
|
||||
}
|
||||
|
||||
// --- CONFIG EDITOR ---
|
||||
[CustomEditor(typeof(ShiroginConfig))]
|
||||
public class ShiroginConfigEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
GUILayout.Space(20);
|
||||
GUILayout.Label("SDK Compilation Control", EditorStyles.boldLabel);
|
||||
|
||||
GUI.backgroundColor = new Color(0.2f, 0.8f, 0.2f);
|
||||
if (GUILayout.Button("✅ Apply Changes & Compile", GUILayout.Height(40)))
|
||||
{
|
||||
bool confirm = EditorUtility.DisplayDialog("Apply SDK Defines?",
|
||||
"This will trigger a script recompilation.\nEnsure required packages are installed.",
|
||||
"Yes, Compile", "Cancel");
|
||||
|
||||
if (confirm) ShiroginDefinesManager.UpdateDefines();
|
||||
}
|
||||
GUI.backgroundColor = Color.white;
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
GUI.backgroundColor = new Color(0.2f, 0.6f, 1f);
|
||||
if (GUILayout.Button("OPEN ASSET MANAGER", GUILayout.Height(40)))
|
||||
{
|
||||
AssetRegistryEditor.ShowWindow();
|
||||
}
|
||||
GUI.backgroundColor = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
// --- EDITOR WINDOW ---
|
||||
[InitializeOnLoad]
|
||||
public class AssetRegistryEditor : EditorWindow
|
||||
{
|
||||
private ShiroginConfig _config;
|
||||
|
||||
private static AddRequest _upmAddRequest;
|
||||
private static bool _isInstallingUpm;
|
||||
|
||||
// Essential Packages (Uses EXACT packageName from VersionData)
|
||||
private readonly List<string> _essentialPackages = new List<string>
|
||||
{
|
||||
"shirogin.sdk.googleexternaldependencymanager.1.2.186.Shirogin",
|
||||
"shirogin.sdk.dotweenpro.1.0.380.Shirogin",
|
||||
"com.unity.purchasing.4.13.0",
|
||||
"shirogin.sdk.applovinmax.8.5.1.Shirogin",
|
||||
"shirogin.sdk.firebaseanalytics.13.6.0.Shirogin",
|
||||
"shirogin.sdk.appsflyer.6.17.72.Shirogin",
|
||||
"shirogin.sdk.facebooksdk.18.0.0.Shirogin",
|
||||
"shirogin.sdk.firebaseremoteconfig.13.6.0.Shirogin"
|
||||
};
|
||||
|
||||
private readonly List<string> _rootPackages = new List<string>
|
||||
{
|
||||
"Firebase", "Facebook", "AppLovin", "AppsFlyer", "External"
|
||||
};
|
||||
|
||||
private Queue<PackageData> _downloadQueue = new Queue<PackageData>();
|
||||
private PackageData _currentQueueItem;
|
||||
private VersionData _currentQueueVersion;
|
||||
private bool _isQueueRunning = false;
|
||||
|
||||
private List<PackageData> allPackages = new List<PackageData>();
|
||||
private List<PackageData> filteredPackages = new List<PackageData>();
|
||||
private HashSet<string> existingFolderNames = new HashSet<string>();
|
||||
|
||||
private bool _isSetupMode = false;
|
||||
private string searchString = "";
|
||||
private string selectedCategory = "All";
|
||||
private string[] categories = new string[] { "All" };
|
||||
private Vector2 scrollPos;
|
||||
private bool showSettings = false;
|
||||
|
||||
private string jsonListUrl = "";
|
||||
private string repoToken = "";
|
||||
private Dictionary<string, int> packageVersionSelection = new Dictionary<string, int>();
|
||||
|
||||
private bool isWorking = false;
|
||||
private string statusMessage = "Waiting for download...";
|
||||
private float downloadProgress = 0f;
|
||||
|
||||
private EditorApplication.CallbackFunction downloadDelegate;
|
||||
private UnityWebRequest currentRequest;
|
||||
|
||||
static AssetRegistryEditor()
|
||||
{
|
||||
EditorApplication.delayCall += CheckFirstTimeInstall;
|
||||
EditorApplication.update += UpmProgressUpdate;
|
||||
}
|
||||
|
||||
private static void CheckFirstTimeInstall()
|
||||
{
|
||||
if (!EditorPrefs.GetBool("ShiroginSDK_WelcomeShown_V2", false))
|
||||
{
|
||||
EditorPrefs.SetBool("ShiroginSDK_WelcomeShown_V2", true);
|
||||
ShowWindow(true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpmProgressUpdate()
|
||||
{
|
||||
if (_isInstallingUpm && _upmAddRequest != null)
|
||||
{
|
||||
if (_upmAddRequest.IsCompleted)
|
||||
{
|
||||
_isInstallingUpm = false;
|
||||
var wnd = GetWindow<AssetRegistryEditor>();
|
||||
|
||||
if (_upmAddRequest.Status == StatusCode.Success)
|
||||
{
|
||||
Debug.Log($"[ShiroginSDK] UPM Package Installed: {_upmAddRequest.Result.packageId}");
|
||||
if(wnd) wnd.RefreshFolderCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[ShiroginSDK] UPM Install Failed: {_upmAddRequest.Error.message}");
|
||||
}
|
||||
|
||||
if(wnd)
|
||||
{
|
||||
wnd.ProcessNextQueueItem();
|
||||
wnd.Repaint();
|
||||
}
|
||||
_upmAddRequest = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("ShiroginSDK/Shirogin Asset Manager")]
|
||||
public static void ShowWindow() => ShowWindow(false);
|
||||
|
||||
public static void ShowWindow(bool forceSetupMode)
|
||||
{
|
||||
AssetRegistryEditor wnd = GetWindow<AssetRegistryEditor>("Asset Manager");
|
||||
wnd.minSize = new Vector2(650, 750);
|
||||
if (forceSetupMode) wnd.SetSetupMode(true);
|
||||
wnd.Show();
|
||||
}
|
||||
|
||||
public void SetSetupMode(bool active)
|
||||
{
|
||||
_isSetupMode = active;
|
||||
ApplyFilters();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_config = ShiroginConfig.Load();
|
||||
jsonListUrl = EditorPrefs.GetString("Shirogin_RepoUrl", "https://api.bitbucket.org/2.0/repositories/batud/studio-asset-registry/src/main/packages.json");
|
||||
repoToken = EditorPrefs.GetString("Shirogin_RepoToken", _config != null ? _config.bitbucketAccessToken : "");
|
||||
|
||||
RefreshFolderCache();
|
||||
|
||||
if (!string.IsNullOrEmpty(jsonListUrl) && !string.IsNullOrEmpty(repoToken))
|
||||
FetchPackageList();
|
||||
else
|
||||
showSettings = true;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
AbortDownload();
|
||||
_downloadQueue.Clear();
|
||||
_isQueueRunning = false;
|
||||
}
|
||||
|
||||
private void OnFocus() => RefreshFolderCache();
|
||||
|
||||
private void RefreshFolderCache()
|
||||
{
|
||||
existingFolderNames.Clear();
|
||||
string internalSdkPath = Path.Combine(Application.dataPath, "ShiroginSDK", "ThirdPartySDKs");
|
||||
if (Directory.Exists(internalSdkPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] dirs = Directory.GetDirectories(internalSdkPath, "*", SearchOption.AllDirectories);
|
||||
foreach (var d in dirs) existingFolderNames.Add(new DirectoryInfo(d).Name.ToLower());
|
||||
} catch {}
|
||||
}
|
||||
try
|
||||
{
|
||||
string[] rootDirs = Directory.GetDirectories(Application.dataPath, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (var d in rootDirs) existingFolderNames.Add(new DirectoryInfo(d).Name.ToLower());
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// --- GUI ---
|
||||
private void OnGUI()
|
||||
{
|
||||
EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height), new Color(0.22f, 0.22f, 0.22f));
|
||||
DrawModernHeader();
|
||||
GUILayout.BeginVertical();
|
||||
|
||||
if (_isSetupMode) DrawSetupWizardUI();
|
||||
else
|
||||
{
|
||||
DrawToolbar();
|
||||
if (showSettings) DrawSettings();
|
||||
GUILayout.Space(5);
|
||||
DrawCategories();
|
||||
GUILayout.Space(5);
|
||||
DrawPackageList();
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.FlexibleSpace();
|
||||
DrawStaticStatusBar();
|
||||
}
|
||||
|
||||
private void DrawModernHeader()
|
||||
{
|
||||
Rect headerRect = new Rect(0, 0, position.width, 60);
|
||||
Color headerColor = _isSetupMode ? new Color(0.1f, 0.3f, 0.5f) : new Color(0.15f, 0.15f, 0.15f);
|
||||
EditorGUI.DrawRect(headerRect, headerColor);
|
||||
|
||||
GUILayout.BeginArea(headerRect);
|
||||
GUILayout.BeginVertical();
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUIStyle titleStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 18, normal = { textColor = new Color(0.95f, 0.95f, 0.95f) }, alignment = TextAnchor.MiddleCenter };
|
||||
GUIStyle subStyle = new GUIStyle(EditorStyles.label) { fontSize = 11, normal = { textColor = new Color(0.8f, 0.8f, 0.8f) }, alignment = TextAnchor.MiddleCenter };
|
||||
|
||||
string title = _isSetupMode ? "WELCOME TO SHIROGIN SDK" : "SHIROGIN ASSET MANAGER";
|
||||
string sub = _isSetupMode ? "Setup Wizard & Essential Packages" : "Package Management System";
|
||||
|
||||
GUILayout.Label(title, titleStyle);
|
||||
GUILayout.Label(sub, subStyle);
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.EndArea();
|
||||
GUILayout.Space(65);
|
||||
}
|
||||
|
||||
private void DrawSetupWizardUI()
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
|
||||
// --- CORE MISSING CHECK ---
|
||||
int missingCount = 0;
|
||||
if(filteredPackages != null)
|
||||
{
|
||||
foreach(var p in filteredPackages)
|
||||
{
|
||||
// Find the REQUIRED version data
|
||||
VersionData requiredVer = p.versions.FirstOrDefault(v => _essentialPackages.Contains(v.packageName));
|
||||
if(requiredVer != null && !IsPackageInstalled(p, requiredVer))
|
||||
missingCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (missingCount > 0)
|
||||
{
|
||||
GUI.backgroundColor = new Color(1f, 0.6f, 0.6f);
|
||||
EditorGUILayout.HelpBox($"⚠ SDK CORE MISSING ({missingCount} packages). Please install essential packages below.", MessageType.Error);
|
||||
GUI.backgroundColor = Color.white;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.backgroundColor = Color.green;
|
||||
EditorGUILayout.HelpBox("✅ SDK Core is fully installed and ready!", MessageType.Info);
|
||||
GUI.backgroundColor = Color.white;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(repoToken))
|
||||
{
|
||||
if(GUILayout.Button("Open Settings to Enter Token")) showSettings = !showSettings;
|
||||
if(showSettings) DrawSettings();
|
||||
}
|
||||
|
||||
GUILayout.Space(10);
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
bool canDownloadAll = !isWorking && !_isInstallingUpm && missingCount > 0;
|
||||
EditorGUI.BeginDisabledGroup(!canDownloadAll);
|
||||
|
||||
GUI.backgroundColor = missingCount > 0 ? new Color(0.2f, 0.6f, 1f) : Color.gray;
|
||||
string btnLabel = missingCount > 0 ? $"⬇ Download & Install All Core ({missingCount})" : "All Core Installed ✓";
|
||||
|
||||
if (GUILayout.Button(btnLabel, GUILayout.Height(35), GUILayout.Width(300)))
|
||||
{
|
||||
StartDownloadAllQueue();
|
||||
}
|
||||
GUI.backgroundColor = Color.white;
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(10);
|
||||
DrawPackageList();
|
||||
GUILayout.Space(15);
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("Continue to Full Dashboard ➔", GUILayout.Height(40), GUILayout.Width(250))) SetSetupMode(false);
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void DrawToolbar()
|
||||
{
|
||||
GUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
if (GUILayout.Button("⚙ Settings", EditorStyles.toolbarButton, GUILayout.Width(80))) showSettings = !showSettings;
|
||||
if (GUILayout.Button("★ Setup Wizard", EditorStyles.toolbarButton, GUILayout.Width(100))) SetSetupMode(true);
|
||||
if (GUILayout.Button("Refresh", EditorStyles.toolbarButton, GUILayout.Width(60))) { RefreshFolderCache(); FetchPackageList(); }
|
||||
if (GUILayout.Button("Clear Cache", EditorStyles.toolbarButton, GUILayout.Width(80))) { ClearCache(); Repaint(); }
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.Label("Search:", GUILayout.Width(50));
|
||||
string newSearch = EditorGUILayout.TextField(searchString, EditorStyles.toolbarTextField, GUILayout.Width(150));
|
||||
if (newSearch != searchString) { searchString = newSearch; ApplyFilters(); }
|
||||
if (GUILayout.Button("×", EditorStyles.toolbarButton, GUILayout.Width(25))) { searchString = ""; GUI.FocusControl(null); ApplyFilters(); }
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void DrawCategories()
|
||||
{
|
||||
if (categories == null || categories.Length == 0) return;
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(10);
|
||||
foreach (var cat in categories)
|
||||
{
|
||||
bool isSelected = selectedCategory == cat;
|
||||
GUIStyle btnStyle = new GUIStyle(EditorStyles.miniButton);
|
||||
if (isSelected) GUI.backgroundColor = new Color(0.3f, 0.6f, 1f);
|
||||
else if(cat.Contains("Core")) GUI.backgroundColor = new Color(1f, 0.8f, 0.8f);
|
||||
|
||||
if (GUILayout.Button(cat, btnStyle, GUILayout.MinWidth(80)))
|
||||
{
|
||||
selectedCategory = cat;
|
||||
searchString = "";
|
||||
GUI.FocusControl(null);
|
||||
ApplyFilters();
|
||||
}
|
||||
GUI.backgroundColor = Color.white;
|
||||
}
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void DrawSettings()
|
||||
{
|
||||
GUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
GUILayout.Label("Connection Settings", EditorStyles.boldLabel);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
jsonListUrl = EditorGUILayout.TextField("JSON List URL", jsonListUrl);
|
||||
repoToken = EditorGUILayout.PasswordField("Access Token", repoToken);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
EditorPrefs.SetString("Shirogin_RepoUrl", jsonListUrl);
|
||||
EditorPrefs.SetString("Shirogin_RepoToken", repoToken);
|
||||
}
|
||||
if (GUILayout.Button("Save Token to Config File"))
|
||||
{
|
||||
if (_config == null) _config = ShiroginConfig.Load();
|
||||
if (_config != null)
|
||||
{
|
||||
_config.bitbucketAccessToken = repoToken;
|
||||
EditorUtility.SetDirty(_config); AssetDatabase.SaveAssets();
|
||||
}
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void DrawStaticStatusBar()
|
||||
{
|
||||
Rect bar = GUILayoutUtility.GetRect(position.width, 30);
|
||||
EditorGUI.DrawRect(bar, new Color(0.1f, 0.2f, 0.1f));
|
||||
|
||||
if (_isQueueRunning)
|
||||
{
|
||||
EditorGUI.DrawRect(bar, new Color(0.5f, 0.2f, 0.8f));
|
||||
string qText = _currentQueueItem != null ? $"Batch Installing: {_currentQueueItem.displayName} ({_downloadQueue.Count} left)" : "Batch Processing...";
|
||||
GUI.Label(bar, qText, new GUIStyle(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleCenter, normal = { textColor = Color.white } });
|
||||
}
|
||||
else if (_isInstallingUpm)
|
||||
{
|
||||
EditorGUI.DrawRect(bar, new Color(0.2f, 0.4f, 0.8f));
|
||||
GUI.Label(bar, "Installing Package via Unity Package Manager...", new GUIStyle(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleCenter, normal = { textColor = Color.white } });
|
||||
}
|
||||
else if (isWorking && downloadProgress > 0)
|
||||
{
|
||||
float w = bar.width * downloadProgress;
|
||||
EditorGUI.DrawRect(new Rect(bar.x, bar.y, w, bar.height), new Color(0.2f, 0.8f, 0.2f));
|
||||
GUI.Label(bar, $"{statusMessage} {(downloadProgress * 100):F0}%", new GUIStyle(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleCenter, normal = { textColor = Color.white } });
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.Label(bar, "Ready", new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleCenter, normal = { textColor = Color.gray } });
|
||||
}
|
||||
|
||||
if (isWorking || _isQueueRunning)
|
||||
{
|
||||
Rect btnRect = new Rect(bar.width - 85, bar.y + 2, 80, 26);
|
||||
GUI.backgroundColor = new Color(0.9f, 0.3f, 0.3f);
|
||||
if (GUI.Button(btnRect, "CANCEL"))
|
||||
{
|
||||
AbortDownload();
|
||||
_downloadQueue.Clear();
|
||||
_isQueueRunning = false;
|
||||
}
|
||||
GUI.backgroundColor = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPackageList()
|
||||
{
|
||||
if (filteredPackages == null || filteredPackages.Count == 0)
|
||||
{
|
||||
GUILayout.Label("No packages found.", EditorStyles.centeredGreyMiniLabel);
|
||||
return;
|
||||
}
|
||||
scrollPos = GUILayout.BeginScrollView(scrollPos);
|
||||
foreach (var pkg in filteredPackages) DrawPackageItem(pkg);
|
||||
GUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private void DrawPackageItem(PackageData pkg)
|
||||
{
|
||||
if (pkg.versions == null || pkg.versions.Length == 0) return;
|
||||
|
||||
// SETUP MODE LOGIC: Force specific version
|
||||
int selectedIndex = 0;
|
||||
bool forceVersion = false;
|
||||
|
||||
if (_isSetupMode)
|
||||
{
|
||||
for (int i = 0; i < pkg.versions.Length; i++)
|
||||
{
|
||||
if (_essentialPackages.Contains(pkg.versions[i].packageName))
|
||||
{
|
||||
selectedIndex = i;
|
||||
forceVersion = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!packageVersionSelection.ContainsKey(pkg.uniqueId)) packageVersionSelection[pkg.uniqueId] = 0;
|
||||
selectedIndex = packageVersionSelection[pkg.uniqueId];
|
||||
if (selectedIndex >= pkg.versions.Length) selectedIndex = 0;
|
||||
}
|
||||
|
||||
VersionData vData = pkg.versions[selectedIndex];
|
||||
|
||||
// Status Logic
|
||||
bool isInstalled = IsPackageInstalled(pkg, vData);
|
||||
string installedVer = EditorPrefs.GetString("RepoManager_Version_" + pkg.uniqueId, "");
|
||||
bool isVersionMatch = isInstalled && (installedVer == vData.version);
|
||||
|
||||
// UPM Hack: Assume version match if folder exists because checking UPM version is slow
|
||||
if (vData.isUpm && isInstalled) isVersionMatch = true;
|
||||
|
||||
string cachePath = Path.Combine(Application.temporaryCachePath, $"{pkg.uniqueId}_{vData.version}.unitypackage");
|
||||
bool isCached = !vData.isUpm && File.Exists(cachePath);
|
||||
|
||||
// COLOR LOGIC
|
||||
Color boxColor = Color.gray;
|
||||
if (isInstalled)
|
||||
{
|
||||
if (isVersionMatch) boxColor = new Color(0.2f, 0.6f, 0.2f); // Green (Correct Version)
|
||||
else boxColor = new Color(0.2f, 0.5f, 0.9f); // Blue (Wrong Version)
|
||||
}
|
||||
else if (isCached)
|
||||
{
|
||||
boxColor = new Color(0.2f, 0.8f, 0.8f); // Cyan (Cached)
|
||||
}
|
||||
else if (_isSetupMode)
|
||||
{
|
||||
boxColor = new Color(0.8f, 0.3f, 0.3f); // Red (Missing in Setup)
|
||||
}
|
||||
else
|
||||
{
|
||||
boxColor = new Color(0.3f, 0.3f, 0.3f); // Gray (Missing)
|
||||
}
|
||||
|
||||
GUI.backgroundColor = boxColor;
|
||||
GUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
GUI.backgroundColor = Color.white;
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
string icon = vData.isUpm ? "📦" : (vData.isExternal ? "🌍" : "📦");
|
||||
GUIStyle labelStyle = new GUIStyle(EditorStyles.boldLabel);
|
||||
labelStyle.normal.textColor = Color.white;
|
||||
GUILayout.Label(new GUIContent($" {pkg.displayName}", icon), labelStyle, GUILayout.Width(200));
|
||||
|
||||
// Version Selection
|
||||
if (forceVersion)
|
||||
{
|
||||
GUIStyle staticVerStyle = new GUIStyle(EditorStyles.label);
|
||||
staticVerStyle.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
|
||||
GUILayout.Label($"v{vData.version} (Required)", staticVerStyle, GUILayout.Width(200));
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] options = pkg.versions.Select(v => v.version).ToArray();
|
||||
int newIndex = EditorGUILayout.Popup(selectedIndex, options, GUILayout.Width(80));
|
||||
if (newIndex != selectedIndex) packageVersionSelection[pkg.uniqueId] = newIndex;
|
||||
}
|
||||
|
||||
// Docs
|
||||
if (!string.IsNullOrEmpty(vData.docsWebUrl))
|
||||
{
|
||||
if (GUILayout.Button("🌐", EditorStyles.miniButton, GUILayout.Width(30)))
|
||||
Application.OpenURL(vData.docsWebUrl);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(vData.docsDownloadUrl))
|
||||
{
|
||||
if (GUILayout.Button("⬇", EditorStyles.miniButton, GUILayout.Width(30)))
|
||||
StartDownloadDocs(vData.docsDownloadUrl, pkg.category, pkg.displayName, vData.version);
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
// Status Label
|
||||
GUIStyle statusStyle = new GUIStyle(EditorStyles.label) { alignment = TextAnchor.MiddleRight, normal = { textColor = Color.white } };
|
||||
if (isInstalled)
|
||||
{
|
||||
string statusText = isVersionMatch ? "✔ Installed" : $"⚠ v{installedVer}";
|
||||
GUILayout.Label(statusText, statusStyle, GUILayout.Width(80));
|
||||
}
|
||||
else if (isCached)
|
||||
{
|
||||
GUILayout.Label("⬇ Cached", statusStyle, GUILayout.Width(80));
|
||||
}
|
||||
|
||||
// ACTION BUTTON
|
||||
EditorGUI.BeginDisabledGroup(isWorking || _isInstallingUpm);
|
||||
|
||||
string btnText = "Install";
|
||||
if (isInstalled)
|
||||
{
|
||||
if (isVersionMatch) btnText = "Re-Install";
|
||||
else btnText = "Update";
|
||||
}
|
||||
else if (isCached)
|
||||
{
|
||||
btnText = "Import (Cached)";
|
||||
}
|
||||
else
|
||||
{
|
||||
btnText = "Download";
|
||||
}
|
||||
|
||||
if (GUILayout.Button(btnText, GUILayout.Width(110)))
|
||||
{
|
||||
_downloadQueue.Clear();
|
||||
_isQueueRunning = false;
|
||||
InstallSpecificPackage(pkg, vData);
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
// Delete / Verify
|
||||
if (!vData.isUpm)
|
||||
{
|
||||
if (isInstalled || isCached)
|
||||
{
|
||||
if (GUILayout.Button("🗑", GUILayout.Width(25)))
|
||||
{
|
||||
if (isCached) try { File.Delete(cachePath); } catch {}
|
||||
if (isInstalled) EditorPrefs.DeleteKey("RepoManager_Version_" + pkg.uniqueId);
|
||||
RefreshFolderCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if(!string.IsNullOrEmpty(vData.releaseNotes))
|
||||
{
|
||||
GUIStyle noteStyle = new GUIStyle(EditorStyles.miniLabel) { normal = { textColor = new Color(0.9f,0.9f,0.9f) } };
|
||||
GUILayout.Label(vData.releaseNotes, noteStyle);
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
// --- INSTALL LOGIC ---
|
||||
|
||||
private void InstallSpecificPackage(PackageData pkg, VersionData vData)
|
||||
{
|
||||
if (vData.isUpm)
|
||||
{
|
||||
InstallUpmPackage(vData.upmId, vData.version);
|
||||
}
|
||||
else
|
||||
{
|
||||
string cachePath = Path.Combine(Application.temporaryCachePath, $"{pkg.uniqueId}_{vData.version}.unitypackage");
|
||||
if (File.Exists(cachePath)) InstallPackageLocal(cachePath, pkg.uniqueId, vData.version);
|
||||
else StartDownloadPackage(vData.url, pkg.uniqueId, vData.version);
|
||||
}
|
||||
}
|
||||
|
||||
// --- QUEUE ---
|
||||
|
||||
private void StartDownloadAllQueue()
|
||||
{
|
||||
if (filteredPackages == null || filteredPackages.Count == 0) return;
|
||||
|
||||
_downloadQueue.Clear();
|
||||
|
||||
foreach (var pkg in filteredPackages)
|
||||
{
|
||||
VersionData targetVer = null;
|
||||
|
||||
// Setup Mode: Find exact version
|
||||
if (_isSetupMode)
|
||||
{
|
||||
targetVer = pkg.versions.FirstOrDefault(v => _essentialPackages.Contains(v.packageName));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal Mode: Selected version
|
||||
int index = 0;
|
||||
if(packageVersionSelection.ContainsKey(pkg.uniqueId)) index = packageVersionSelection[pkg.uniqueId];
|
||||
if(index < pkg.versions.Length) targetVer = pkg.versions[index];
|
||||
}
|
||||
|
||||
if (targetVer != null && !IsPackageInstalled(pkg, targetVer))
|
||||
{
|
||||
_downloadQueue.Enqueue(pkg);
|
||||
}
|
||||
}
|
||||
|
||||
if (_downloadQueue.Count > 0)
|
||||
{
|
||||
_isQueueRunning = true;
|
||||
ProcessNextQueueItem();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayDialog("Setup Wizard", "All required packages are already installed!", "OK");
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessNextQueueItem()
|
||||
{
|
||||
if (!_isQueueRunning) return;
|
||||
|
||||
if (_downloadQueue.Count > 0)
|
||||
{
|
||||
_currentQueueItem = _downloadQueue.Dequeue();
|
||||
|
||||
// Determine Version again
|
||||
VersionData vData = null;
|
||||
if (_isSetupMode)
|
||||
{
|
||||
vData = _currentQueueItem.versions.FirstOrDefault(v => _essentialPackages.Contains(v.packageName));
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = 0;
|
||||
if(packageVersionSelection.ContainsKey(_currentQueueItem.uniqueId)) index = packageVersionSelection[_currentQueueItem.uniqueId];
|
||||
vData = _currentQueueItem.versions[index];
|
||||
}
|
||||
|
||||
if (vData != null)
|
||||
{
|
||||
Debug.Log($"[Queue] Processing: {_currentQueueItem.displayName} ({vData.version})");
|
||||
InstallSpecificPackage(_currentQueueItem, vData);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessNextQueueItem(); // Skip if invalid
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_isQueueRunning = false;
|
||||
_currentQueueItem = null;
|
||||
EditorUtility.DisplayDialog("Setup Wizard", "All packages have been installed!", "OK");
|
||||
}
|
||||
}
|
||||
|
||||
// --- HELPERS ---
|
||||
|
||||
private bool IsPackageInstalled(PackageData pkg, VersionData vData)
|
||||
{
|
||||
if (vData.isUpm && !string.IsNullOrEmpty(vData.upmId))
|
||||
{
|
||||
string upmPath = Path.Combine("Packages", vData.upmId);
|
||||
if (AssetDatabase.IsValidFolder(upmPath)) return true;
|
||||
|
||||
string manifestPath = Path.Combine(Application.dataPath, "..", "Packages", "manifest.json");
|
||||
if (File.Exists(manifestPath))
|
||||
{
|
||||
string content = File.ReadAllText(manifestPath);
|
||||
if (content.Contains($"\"{vData.upmId}\"")) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool folderFound = IsPackageFolderFound(pkg);
|
||||
string storedVer = EditorPrefs.GetString("RepoManager_Version_" + pkg.uniqueId, "");
|
||||
return folderFound || !string.IsNullOrEmpty(storedVer);
|
||||
}
|
||||
|
||||
private void InstallUpmPackage(string packageId, string version)
|
||||
{
|
||||
_isInstallingUpm = true;
|
||||
string id = string.IsNullOrEmpty(version) ? packageId : $"{packageId}@{version}";
|
||||
Debug.Log($"[Asset Manager] Requesting UPM Install: {id}");
|
||||
_upmAddRequest = Client.Add(id);
|
||||
}
|
||||
|
||||
private bool IsPackageFolderFound(PackageData pkg)
|
||||
{
|
||||
string simpleName = pkg.displayName.Replace(" SDK", "").Replace(" ", "").ToLower();
|
||||
if (existingFolderNames.Contains(simpleName)) return true;
|
||||
if (existingFolderNames.Contains(pkg.displayName.ToLower())) return true;
|
||||
if (_rootPackages.Contains(pkg.displayName) && existingFolderNames.Contains(pkg.displayName.ToLower())) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void FetchPackageList()
|
||||
{
|
||||
if (isWorking) return;
|
||||
StartWebOperation(jsonListUrl, OnJsonListDownloaded, null);
|
||||
}
|
||||
|
||||
private void StartDownloadPackage(string url, string pkgId, string version)
|
||||
{
|
||||
if (isWorking) return;
|
||||
string fileName = $"{pkgId}_{version}.unitypackage";
|
||||
string tempPath = Path.Combine(Application.temporaryCachePath, fileName);
|
||||
StartWebOperation(url, (data) => InstallPackageLocal(tempPath, pkgId, version), tempPath);
|
||||
}
|
||||
|
||||
private void StartDownloadDocs(string url, string category, string pkgName, string version)
|
||||
{
|
||||
if (isWorking) return;
|
||||
|
||||
string safeName = string.Join("_", pkgName.Split(Path.GetInvalidFileNameChars()));
|
||||
string docsRoot = Path.Combine(Application.dataPath, "ShiroginSDK", "ThirdPartySDKs");
|
||||
string targetFolder = Path.Combine(docsRoot, category, safeName);
|
||||
|
||||
if (!Directory.Exists(targetFolder)) Directory.CreateDirectory(targetFolder);
|
||||
string targetPath = Path.Combine(targetFolder, $"{safeName}_{version}.md");
|
||||
|
||||
StartWebOperation(url, (data) =>
|
||||
{
|
||||
if (data != null && data.Length > 0)
|
||||
{
|
||||
File.WriteAllBytes(targetPath, data);
|
||||
EditorUtility.DisplayDialog("Download Complete", $"Documentation saved to:\n{targetPath}", "OK");
|
||||
string relPath = "Assets" + targetPath.Substring(Application.dataPath.Length);
|
||||
AssetDatabase.ImportAsset(relPath);
|
||||
var obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(relPath);
|
||||
EditorGUIUtility.PingObject(obj);
|
||||
}
|
||||
}, targetPath);
|
||||
}
|
||||
|
||||
private void InstallPackageLocal(string path, string pkgId, string version)
|
||||
{
|
||||
if (!File.Exists(path)) return;
|
||||
AssetDatabase.ImportPackage(path, true);
|
||||
EditorPrefs.SetString("RepoManager_Version_" + pkgId, version);
|
||||
RefreshFolderCache();
|
||||
Repaint();
|
||||
|
||||
if (_isQueueRunning) ProcessNextQueueItem();
|
||||
}
|
||||
|
||||
private void AbortDownload()
|
||||
{
|
||||
if (currentRequest != null) { currentRequest.Abort(); currentRequest.Dispose(); currentRequest = null; }
|
||||
if (downloadDelegate != null) { EditorApplication.update -= downloadDelegate; downloadDelegate = null; }
|
||||
isWorking = false; statusMessage = "Waiting..."; downloadProgress = 0f; Repaint();
|
||||
}
|
||||
|
||||
private void StartWebOperation(string url, Action<byte[]> onComplete, string savePath = null)
|
||||
{
|
||||
AbortDownload(); isWorking = true; statusMessage = "Connecting..."; downloadProgress = 0f;
|
||||
downloadDelegate = () => WebRequestRoutine(url, savePath, onComplete);
|
||||
EditorApplication.update += downloadDelegate;
|
||||
}
|
||||
|
||||
private void WebRequestRoutine(string url, string savePath, Action<byte[]> onComplete)
|
||||
{
|
||||
if (currentRequest == null)
|
||||
{
|
||||
currentRequest = UnityWebRequest.Get(url);
|
||||
if (url.Contains("bitbucket.org") && !string.IsNullOrEmpty(repoToken))
|
||||
currentRequest.SetRequestHeader("Authorization", "Bearer " + repoToken);
|
||||
|
||||
if (!string.IsNullOrEmpty(savePath))
|
||||
currentRequest.downloadHandler = new DownloadHandlerFile(savePath);
|
||||
else
|
||||
currentRequest.downloadHandler = new DownloadHandlerBuffer();
|
||||
|
||||
currentRequest.SendWebRequest();
|
||||
}
|
||||
|
||||
if (!currentRequest.isDone)
|
||||
{
|
||||
downloadProgress = currentRequest.downloadProgress;
|
||||
statusMessage = "Downloading...";
|
||||
Repaint();
|
||||
return;
|
||||
}
|
||||
|
||||
bool success = currentRequest.result == UnityWebRequest.Result.Success;
|
||||
byte[] data = null;
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (string.IsNullOrEmpty(savePath) && currentRequest.downloadHandler is DownloadHandlerBuffer)
|
||||
{
|
||||
data = currentRequest.downloadHandler.data;
|
||||
}
|
||||
if(!string.IsNullOrEmpty(savePath)) data = new byte[1];
|
||||
}
|
||||
else if (currentRequest.error != "Request aborted")
|
||||
{
|
||||
Debug.LogError($"Network Error: {currentRequest.error}");
|
||||
EditorUtility.DisplayDialog("Download Failed", currentRequest.error, "OK");
|
||||
if (!string.IsNullOrEmpty(savePath) && File.Exists(savePath)) try { File.Delete(savePath); } catch {}
|
||||
}
|
||||
|
||||
currentRequest.Dispose(); currentRequest = null;
|
||||
EditorApplication.update -= downloadDelegate; downloadDelegate = null;
|
||||
isWorking = false; Repaint();
|
||||
|
||||
if(success) onComplete?.Invoke(data);
|
||||
}
|
||||
|
||||
private void OnJsonListDownloaded(byte[] data)
|
||||
{
|
||||
if (data == null) return;
|
||||
try
|
||||
{
|
||||
PackageManifest manifest = JsonUtility.FromJson<PackageManifest>(System.Text.Encoding.UTF8.GetString(data));
|
||||
if (manifest != null && manifest.packages != null)
|
||||
{
|
||||
allPackages = new List<PackageData>(manifest.packages);
|
||||
var catList = new HashSet<string> { "All" };
|
||||
foreach (var p in allPackages) if (!string.IsNullOrEmpty(p.category)) catList.Add(p.category);
|
||||
categories = catList.OrderBy(c => c).ToArray();
|
||||
ApplyFilters();
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
catch (Exception e) { Debug.LogError("JSON Error: " + e.Message); }
|
||||
}
|
||||
|
||||
private void ApplyFilters()
|
||||
{
|
||||
if (allPackages == null) return;
|
||||
if (_isSetupMode)
|
||||
{
|
||||
// Check against packageName instead of uniqueId
|
||||
filteredPackages = allPackages.Where(p =>
|
||||
p.versions.Any(v => _essentialPackages.Contains(v.packageName))
|
||||
).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
filteredPackages = allPackages.Where(p =>
|
||||
{
|
||||
bool catMatch = selectedCategory == "All" || p.category == selectedCategory;
|
||||
bool searchMatch = string.IsNullOrEmpty(searchString) || p.displayName.ToLower().Contains(searchString.ToLower());
|
||||
return catMatch && searchMatch;
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearCache()
|
||||
{
|
||||
string path = Application.temporaryCachePath;
|
||||
var info = new DirectoryInfo(path);
|
||||
foreach (var f in info.GetFiles("*.unitypackage")) f.Delete();
|
||||
Debug.Log("Cache cleared.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e877a2529afa4573908befa02302e0dc
|
||||
timeCreated: 1765485911
|
||||
3
Assets/ShiroginSDK/Editor/Core.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f83da24293a44111ad4261ebd6abea37
|
||||
timeCreated: 1765666221
|
||||
3
Assets/ShiroginSDK/Editor/Core/SDK.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a8fc14d0843046eab7bada6257bf087d
|
||||
timeCreated: 1765818013
|
||||
99
Assets/ShiroginSDK/Editor/Core/SDK/ShiroginConfigEditor.cs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
using System.Reflection;
|
||||
using ShiroginSDK.Editor.Bitbucket;
|
||||
using ShiroginSDK.Runtime.Core.SDK;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShiroginSDK.Editor.Core.SDK
|
||||
{
|
||||
[CustomEditor(typeof(ShiroginConfig))]
|
||||
public class ShiroginConfigEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
GUILayout.Space(20);
|
||||
|
||||
GUILayout.Label("SDK Compilation Control", EditorStyles.boldLabel);
|
||||
|
||||
// Apply Button
|
||||
GUI.backgroundColor = new Color(0.2f, 0.8f, 0.2f);
|
||||
if (GUILayout.Button("✅ Apply Changes & Compile", GUILayout.Height(40)))
|
||||
{
|
||||
bool confirm = EditorUtility.DisplayDialog("Apply SDK Defines?",
|
||||
"This will trigger a script recompilation.\n\n" +
|
||||
"Ensure you have downloaded the necessary packages (Firebase, AppLovin, etc.) " +
|
||||
"via the Asset Manager BEFORE enabling them.\n\n" +
|
||||
"If code breaks, use 'Tools > ShiroginSDK > Force Reset Symbols'.",
|
||||
"Yes, Compile", "Cancel");
|
||||
|
||||
if (confirm)
|
||||
{
|
||||
ShiroginDefinesManager.UpdateDefines();
|
||||
}
|
||||
}
|
||||
|
||||
GUI.backgroundColor = Color.white;
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
GUIStyle bigButtonStyle = new GUIStyle(GUI.skin.button);
|
||||
bigButtonStyle.fontSize = 14;
|
||||
bigButtonStyle.fontStyle = FontStyle.Bold;
|
||||
bigButtonStyle.fixedHeight = 40;
|
||||
bigButtonStyle.normal.textColor = Color.white;
|
||||
|
||||
GUI.backgroundColor = new Color(0.2f, 0.6f, 1f);
|
||||
if (GUILayout.Button("OPEN ASSET MANAGER", bigButtonStyle))
|
||||
{
|
||||
AssetRegistryEditor.ShowWindow();
|
||||
}
|
||||
|
||||
GUI.backgroundColor = Color.white;
|
||||
|
||||
GUILayout.Space(5);
|
||||
GUILayout.Label("Click above to manage SDK packages.", EditorStyles.centeredGreyMiniLabel);
|
||||
}
|
||||
|
||||
public static class ShiroginConfigInspectorOpener
|
||||
{
|
||||
[MenuItem("ShiroginSDK/Config")]
|
||||
public static void OpenConfigInNewLockedInspector()
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets("t:ShiroginConfig");
|
||||
if (guids.Length == 0)
|
||||
{
|
||||
Debug.LogError("ShiroginConfig asset not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
var path = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||||
var config = AssetDatabase.LoadAssetAtPath<Object>(path);
|
||||
|
||||
var inspectorType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.InspectorWindow");
|
||||
var before = Resources.FindObjectsOfTypeAll(inspectorType).Length;
|
||||
|
||||
Selection.activeObject = config;
|
||||
|
||||
EditorApplication.ExecuteMenuItem("Window/General/Inspector");
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
var inspectors = Resources.FindObjectsOfTypeAll(inspectorType);
|
||||
if (inspectors.Length <= before)
|
||||
return;
|
||||
|
||||
// Yeni açılan inspector = son eklenen
|
||||
var newInspector = inspectors[inspectors.Length - 1];
|
||||
|
||||
var isLockedProp = inspectorType.GetProperty(
|
||||
"isLocked",
|
||||
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
|
||||
);
|
||||
|
||||
isLockedProp?.SetValue(newInspector, true);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b4044634796944508551efb45ce358de
|
||||
timeCreated: 1765818022
|
||||
135
Assets/ShiroginSDK/Editor/Core/ShiroginDefinesManager.cs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ShiroginSDK.Runtime.Core.SDK;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShiroginSDK.Editor.Core
|
||||
{
|
||||
public static class ShiroginDefinesManager
|
||||
{
|
||||
// Define Symbols
|
||||
private const string DEFINE_SDK = "SHIROGIN_SDK";
|
||||
private const string DEFINE_IAP = "SHIROGIN_IAP";
|
||||
private const string DEFINE_AD_SERVICE = "SHIROGIN_AD_SERVICE";
|
||||
private const string DEFINE_ANALYTICS = "SHIROGIN_ANALYTICS";
|
||||
private const string DEFINE_FIREBASE_ANALYTICS = "SHIROGIN_FIREBASE_ANALYTICS";
|
||||
private const string DEFINE_FIREBASE_REMOTE_CONFIG = "SHIROGIN_FIREBASE_REMOTE_CONFIG";
|
||||
private const string DEFINE_APPSFLYER = "SHIROGIN_APPSFLYER";
|
||||
private const string DEFINE_FACEBOOK = "SHIROGIN_FACEBOOK";
|
||||
|
||||
/// <summary>
|
||||
/// Updates scripting define symbols based on ShiroginConfig settings.
|
||||
/// Call this manually from the Config Editor.
|
||||
/// </summary>
|
||||
public static void UpdateDefines()
|
||||
{
|
||||
var config = ShiroginConfig.Load();
|
||||
|
||||
if (config == null)
|
||||
{
|
||||
Debug.LogError("ShiroginConfig not found! Cannot update defines.");
|
||||
return;
|
||||
}
|
||||
|
||||
var activeDefines = new List<string>();
|
||||
|
||||
// --- Enable Flags ---
|
||||
|
||||
if (config.enableSdk)
|
||||
activeDefines.Add(DEFINE_SDK);
|
||||
|
||||
if (config.enableIAP)
|
||||
activeDefines.Add(DEFINE_IAP);
|
||||
|
||||
if (config.enableAdService)
|
||||
activeDefines.Add(DEFINE_AD_SERVICE);
|
||||
|
||||
if (config.enableAnalytics)
|
||||
activeDefines.Add(DEFINE_ANALYTICS);
|
||||
|
||||
if (config.enableFirebaseAnalytics)
|
||||
activeDefines.Add(DEFINE_FIREBASE_ANALYTICS);
|
||||
|
||||
if (config.enableFirebaseRemoteConfig)
|
||||
activeDefines.Add(DEFINE_FIREBASE_REMOTE_CONFIG);
|
||||
|
||||
if (config.enableAppsFlyerAnalytics)
|
||||
activeDefines.Add(DEFINE_APPSFLYER);
|
||||
|
||||
if (config.enableFacebook)
|
||||
activeDefines.Add(DEFINE_FACEBOOK);
|
||||
|
||||
SetDefines(activeDefines);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emergency tool to clear all SDK symbols if compilation breaks.
|
||||
/// Access via: Tools -> ShiroginSDK -> Force Reset Symbols
|
||||
/// </summary>
|
||||
[MenuItem("ShiroginSDK/🔧 Force Reset Symbols (Fix Errors)", false, 99)]
|
||||
public static void ForceReset()
|
||||
{
|
||||
SetDefines(new List<string>());
|
||||
Debug.Log("ShiroginSDK: All symbols cleared. You should be able to compile now.");
|
||||
}
|
||||
|
||||
private static void SetDefines(List<string> targetDefines)
|
||||
{
|
||||
var targetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
|
||||
|
||||
if (targetGroup == BuildTargetGroup.Unknown) return;
|
||||
|
||||
string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup);
|
||||
var allDefines = definesString.Split(';').ToList();
|
||||
|
||||
bool changed = false;
|
||||
|
||||
var managedDefines = new List<string>
|
||||
{
|
||||
DEFINE_SDK,
|
||||
DEFINE_IAP,
|
||||
DEFINE_AD_SERVICE,
|
||||
DEFINE_ANALYTICS,
|
||||
DEFINE_FIREBASE_ANALYTICS,
|
||||
DEFINE_FIREBASE_REMOTE_CONFIG,
|
||||
DEFINE_APPSFLYER,
|
||||
DEFINE_FACEBOOK
|
||||
};
|
||||
|
||||
// Add required
|
||||
foreach (var define in targetDefines)
|
||||
{
|
||||
if (!allDefines.Contains(define))
|
||||
{
|
||||
allDefines.Add(define);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove unused
|
||||
foreach (var define in managedDefines)
|
||||
{
|
||||
if (!targetDefines.Contains(define) && allDefines.Contains(define))
|
||||
{
|
||||
allDefines.Remove(define);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, string.Join(";", allDefines));
|
||||
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
UnityEditor.Compilation.CompilationPipeline.RequestScriptCompilation();
|
||||
#endif
|
||||
Debug.Log($"[ShiroginSDK] 🔄 Defines Updated: {string.Join(", ", targetDefines)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("[ShiroginSDK] No changes in defines.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6c16173692394a179aa515a4773768f4
|
||||
timeCreated: 1765666256
|
||||
8
Assets/ShiroginSDK/Editor/IAP.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 323e6e9bf4835764eb53fb63261d6d3e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Assets/ShiroginSDK/Editor/IAP/IAPNameProvider.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using System.Collections.Generic;
|
||||
using ShiroginSDK.Runtime.Core.SDK;
|
||||
using ShiroginSDK.Runtime.Shared.Constants;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShiroginSDK.Editor.IAP
|
||||
{
|
||||
public static class IAPNameProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns all productIds from the active StoreRepository in SDKConfig.
|
||||
/// </summary>
|
||||
public static IEnumerable<string> GetIAPNames()
|
||||
{
|
||||
var config = Resources.Load<ShiroginConfig>(SDKConstants.ConfigResourcePath);
|
||||
if (config == null || config.storeRepository == null) return new List<string> { "⚠ No Repository Found" };
|
||||
|
||||
var list = new List<string>();
|
||||
var allItems = config.storeRepository.GetAll(); // ✅
|
||||
|
||||
foreach (var item in allItems)
|
||||
if (item != null && !string.IsNullOrEmpty(item.productId))
|
||||
list.Add(item.productId);
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/ShiroginSDK/Editor/IAP/IAPNameProvider.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fc886bf85ac14aed80a646e4abb126e4
|
||||
timeCreated: 1759412104
|
||||
39
Assets/ShiroginSDK/Editor/IAP/IAPProductDropdownDrawer.cs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using ShiroginSDK.Runtime.Core.Editor.Attributes;
|
||||
using ShiroginSDK.Runtime.Core.SDK;
|
||||
using ShiroginSDK.Runtime.Shared.Constants;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShiroginSDK.Editor.IAP
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(IAPProductDropdownAttribute))]
|
||||
public class IAPProductDropdownDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (property.propertyType != SerializedPropertyType.String)
|
||||
{
|
||||
EditorGUI.LabelField(position, label.text, "Use with string only.");
|
||||
return;
|
||||
}
|
||||
|
||||
var config = Resources.Load<ShiroginConfig>(SDKConstants.ConfigResourcePath);
|
||||
if (config == null || config.storeRepository == null)
|
||||
{
|
||||
EditorGUI.PropertyField(position, property, label);
|
||||
return;
|
||||
}
|
||||
|
||||
var items = config.storeRepository.GetAll();
|
||||
var options = new string[items.Count];
|
||||
for (var i = 0; i < items.Count; i++) options[i] = items[i] != null ? items[i].productId : "<null>";
|
||||
|
||||
var index = Mathf.Max(0, Array.IndexOf(options, property.stringValue));
|
||||
index = EditorGUI.Popup(position, label.text, index, options);
|
||||
if (index >= 0 && index < options.Length) property.stringValue = options[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 328d5079597b43289c6892ef6d86cf8b
|
||||
timeCreated: 1759412301
|
||||
182
Assets/ShiroginSDK/Editor/IAP/StoreItemEditor.cs
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// #if UNITY_EDITOR
|
||||
// using UnityEditor;
|
||||
// using UnityEngine;
|
||||
// using UnityEngine.UIElements;
|
||||
// using ShiroginSDK.Runtime.IAP.SO;
|
||||
// using ShiroginSDK.Runtime.IAP.Enums;
|
||||
// using System.IO;
|
||||
// using System.Collections.Generic;
|
||||
//
|
||||
// namespace ShiroginSDK.Editor.IAP
|
||||
// {
|
||||
// [CustomEditor(typeof(StoreItem))]
|
||||
// public class StoreItemEditor : UnityEditor.Editor
|
||||
// {
|
||||
// private const string SaveFolder = "Assets/ShiroginSDK/Generated/StoreItemIcons";
|
||||
// private const string JsonPath = "Assets/ShiroginSDK/Generated/storeitemeditor.json";
|
||||
//
|
||||
// [System.Serializable]
|
||||
// private class IconData { public string itemPath; public string iconPath; }
|
||||
//
|
||||
// [System.Serializable]
|
||||
// private class IconDataList { public List<IconData> list = new(); }
|
||||
//
|
||||
// public override VisualElement CreateInspectorGUI()
|
||||
// {
|
||||
// var root = new VisualElement { style = { paddingTop = 6, paddingBottom = 8 } };
|
||||
// var item = (StoreItem)target;
|
||||
//
|
||||
// // Default inspector (IMGUIContainer ile izole)
|
||||
// var defaultInspector = new IMGUIContainer(() => DrawDefaultInspector());
|
||||
// root.Add(defaultInspector);
|
||||
//
|
||||
// // Separator
|
||||
// var line = new VisualElement();
|
||||
// line.style.height = 1;
|
||||
// line.style.marginTop = 8;
|
||||
// line.style.marginBottom = 8;
|
||||
// line.style.backgroundColor = new Color(0.25f, 0.25f, 0.25f, 0.6f);
|
||||
// root.Add(line);
|
||||
//
|
||||
// // Box container
|
||||
// var box = new VisualElement();
|
||||
// box.style.borderTopLeftRadius = 6;
|
||||
// box.style.borderTopRightRadius = 6;
|
||||
// box.style.borderBottomLeftRadius = 6;
|
||||
// box.style.borderBottomRightRadius = 6;
|
||||
// box.style.paddingTop = 8;
|
||||
// box.style.paddingBottom = 8;
|
||||
// box.style.paddingLeft = 10;
|
||||
// box.style.paddingRight = 10;
|
||||
// box.style.backgroundColor = new Color(0.12f, 0.12f, 0.12f, 0.6f);
|
||||
// root.Add(box);
|
||||
//
|
||||
// var header = new Label("🧩 Shirogin IAP Tools");
|
||||
// header.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
// header.style.marginBottom = 6;
|
||||
// box.Add(header);
|
||||
//
|
||||
// if (item.icon == null)
|
||||
// {
|
||||
// var help = new HelpBox("Please assign an icon sprite before applying.", HelpBoxMessageType.Warning);
|
||||
// box.Add(help);
|
||||
// }
|
||||
//
|
||||
// var button = new Button(() => GenerateAndSave(item))
|
||||
// {
|
||||
// text = "🖼 Generate & Save Icon",
|
||||
// style =
|
||||
// {
|
||||
// height = 28,
|
||||
// unityTextAlign = TextAnchor.MiddleCenter,
|
||||
// marginTop = 4
|
||||
// }
|
||||
// };
|
||||
// box.Add(button);
|
||||
//
|
||||
// return root;
|
||||
// }
|
||||
//
|
||||
// private void GenerateAndSave(StoreItem item)
|
||||
// {
|
||||
// Directory.CreateDirectory(SaveFolder);
|
||||
//
|
||||
// Texture2D baseTex = AssetPreview.GetAssetPreview(item.icon);
|
||||
// if (baseTex == null)
|
||||
// {
|
||||
// Debug.LogWarning("[ShiroginSDK] Couldn't create preview texture.");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// string category = item.category.ToString();
|
||||
// Texture2D label = Resources.Load<Texture2D>($"Shirogin/IAP_Labels/{category}") ??
|
||||
// Resources.Load<Texture2D>("Shirogin/IAP_Labels/Unknown");
|
||||
//
|
||||
// Texture2D final = new Texture2D(baseTex.width, baseTex.height, TextureFormat.RGBA32, false);
|
||||
// Graphics.CopyTexture(baseTex, final);
|
||||
// if (label != null) Overlay(final, label);
|
||||
// final.Apply();
|
||||
//
|
||||
// string savePath = $"{SaveFolder}/{item.name}_Icon.png";
|
||||
// File.WriteAllBytes(savePath, final.EncodeToPNG());
|
||||
// AssetDatabase.ImportAsset(savePath);
|
||||
// AssetDatabase.Refresh();
|
||||
//
|
||||
// Texture2D savedTex = AssetDatabase.LoadAssetAtPath<Texture2D>(savePath);
|
||||
// if (savedTex != null)
|
||||
// EditorGUIUtility.SetIconForObject(item, savedTex);
|
||||
//
|
||||
// EditorUtility.SetDirty(item);
|
||||
// AssetDatabase.SaveAssets();
|
||||
// SaveJson(AssetDatabase.GetAssetPath(item), savePath);
|
||||
// Debug.Log($"[ShiroginSDK] Icon saved → {savePath}");
|
||||
// }
|
||||
//
|
||||
// private void Overlay(Texture2D baseTex, Texture2D labelTex)
|
||||
// {
|
||||
// int w = baseTex.width;
|
||||
// int h = baseTex.height;
|
||||
// int lh = Mathf.RoundToInt(h * 0.2f);
|
||||
// Texture2D scaled = Scale(labelTex, w, lh);
|
||||
//
|
||||
// for (int y = 0; y < lh; y++)
|
||||
// {
|
||||
// for (int x = 0; x < w; x++)
|
||||
// {
|
||||
// Color a = baseTex.GetPixel(x, h - lh + y);
|
||||
// Color b = scaled.GetPixel(x, y);
|
||||
// baseTex.SetPixel(x, h - lh + y, Color.Lerp(a, b, b.a));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private Texture2D Scale(Texture2D src, int w, int h)
|
||||
// {
|
||||
// RenderTexture rt = RenderTexture.GetTemporary(w, h);
|
||||
// Graphics.Blit(src, rt);
|
||||
// RenderTexture.active = rt;
|
||||
// Texture2D result = new Texture2D(w, h, TextureFormat.RGBA32, false);
|
||||
// result.ReadPixels(new Rect(0, 0, w, h), 0, 0);
|
||||
// result.Apply();
|
||||
// RenderTexture.ReleaseTemporary(rt);
|
||||
// RenderTexture.active = null;
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// private void SaveJson(string itemPath, string iconPath)
|
||||
// {
|
||||
// IconDataList data = File.Exists(JsonPath)
|
||||
// ? JsonUtility.FromJson<IconDataList>(File.ReadAllText(JsonPath))
|
||||
// : new IconDataList();
|
||||
//
|
||||
// data.list.RemoveAll(x => x.itemPath == itemPath);
|
||||
// data.list.Add(new IconData { itemPath = itemPath, iconPath = iconPath });
|
||||
//
|
||||
// File.WriteAllText(JsonPath, JsonUtility.ToJson(data, true));
|
||||
// AssetDatabase.Refresh();
|
||||
// }
|
||||
//
|
||||
// [InitializeOnLoadMethod]
|
||||
// private static void RestoreIconsOnLoad()
|
||||
// {
|
||||
// EditorApplication.delayCall += () =>
|
||||
// {
|
||||
// if (!File.Exists(JsonPath)) return;
|
||||
// var data = JsonUtility.FromJson<IconDataList>(File.ReadAllText(JsonPath));
|
||||
// if (data == null || data.list.Count == 0) return;
|
||||
//
|
||||
// foreach (var entry in data.list)
|
||||
// {
|
||||
// var item = AssetDatabase.LoadAssetAtPath<StoreItem>(entry.itemPath);
|
||||
// var icon = AssetDatabase.LoadAssetAtPath<Texture2D>(entry.iconPath);
|
||||
// if (item != null && icon != null)
|
||||
// EditorGUIUtility.SetIconForObject(item, icon);
|
||||
// }
|
||||
//
|
||||
// Debug.Log($"[ShiroginSDK] Restored {data.list.Count} StoreItem icons (Unity 6 compatible).");
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
|
||||
3
Assets/ShiroginSDK/Editor/IAP/StoreItemEditor.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fbea0c77393e48038e5bbb46246e38e3
|
||||
timeCreated: 1760535014
|
||||
3
Assets/ShiroginSDK/Editor/RemoteConfig.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 83a5dfe9c55d4ea38699ffad6bf306bd
|
||||
timeCreated: 1760346182
|
||||
72
Assets/ShiroginSDK/Editor/RemoteConfig/EntryDrawer.cs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#if UNITY_EDITOR
|
||||
using ShiroginSDK.Runtime.Modules.RemoteConfig.Scripts.SO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShiroginSDK.Editor.RemoteConfig
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(RemoteConfigDefinition.Entry))]
|
||||
public class EntryDrawer : PropertyDrawer
|
||||
{
|
||||
private static readonly Color StringColor = new(0.55f, 0.9f, 0.6f);
|
||||
private static readonly Color NumberColor = new(0.55f, 0.75f, 1f);
|
||||
private static readonly Color BoolColor = new(1f, 0.85f, 0.55f);
|
||||
private static readonly Color BorderColor = new(0.35f, 0.35f, 0.35f);
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
return 3 * EditorGUIUtility.singleLineHeight + 24f;
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
var typeProp = property.FindPropertyRelative("Type");
|
||||
var valueType = (RemoteConfigDefinition.ValueType)typeProp.enumValueIndex;
|
||||
|
||||
var bgColor = valueType switch
|
||||
{
|
||||
RemoteConfigDefinition.ValueType.String => StringColor,
|
||||
RemoteConfigDefinition.ValueType.Number => NumberColor,
|
||||
RemoteConfigDefinition.ValueType.Boolean => BoolColor,
|
||||
_ => Color.gray
|
||||
};
|
||||
|
||||
var boxRect = new Rect(position.x + 4, position.y + 2, position.width - 8, position.height - 4);
|
||||
EditorGUI.DrawRect(boxRect, new Color(bgColor.r, bgColor.g, bgColor.b, 0.25f));
|
||||
Handles.color = BorderColor;
|
||||
Handles.DrawAAPolyLine(1.5f, new Vector3(boxRect.x, boxRect.yMax), new Vector3(boxRect.xMax, boxRect.yMax));
|
||||
|
||||
var y = boxRect.y + 4;
|
||||
var lh = EditorGUIUtility.singleLineHeight + 6;
|
||||
|
||||
EditorGUI.PropertyField(new Rect(boxRect.x + 6, y, boxRect.width - 12, lh - 4),
|
||||
property.FindPropertyRelative("Key"), new GUIContent("🔑 Key"));
|
||||
y += lh;
|
||||
|
||||
EditorGUI.PropertyField(new Rect(boxRect.x + 6, y, boxRect.width - 12, lh - 4),
|
||||
typeProp, new GUIContent("🎛️ Type"));
|
||||
y += lh;
|
||||
|
||||
switch (valueType)
|
||||
{
|
||||
case RemoteConfigDefinition.ValueType.String:
|
||||
EditorGUI.PropertyField(new Rect(boxRect.x + 6, y, boxRect.width - 12, lh - 4),
|
||||
property.FindPropertyRelative("StringValue"), new GUIContent("🧩 String Value"));
|
||||
break;
|
||||
case RemoteConfigDefinition.ValueType.Number:
|
||||
EditorGUI.PropertyField(new Rect(boxRect.x + 6, y, boxRect.width - 12, lh - 4),
|
||||
property.FindPropertyRelative("NumberValue"), new GUIContent("🔢 Number Value"));
|
||||
break;
|
||||
case RemoteConfigDefinition.ValueType.Boolean:
|
||||
EditorGUI.PropertyField(new Rect(boxRect.x + 6, y, boxRect.width - 12, lh - 4),
|
||||
property.FindPropertyRelative("BoolValue"), new GUIContent("✅ Boolean Value"));
|
||||
break;
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c1d17a52bda042929c7ef52153edfd98
|
||||
timeCreated: 1760348378
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using ShiroginSDK.Runtime.Core.SDK;
|
||||
using ShiroginSDK.Runtime.Modules.Data.Scripts;
|
||||
using ShiroginSDK.Runtime.Modules.RemoteConfig.Scripts.SO;
|
||||
using ShiroginSDK.Runtime.Shared.Constants;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShiroginSDK.Editor.RemoteConfig
|
||||
{
|
||||
[CustomEditor(typeof(RemoteConfigDefinition))]
|
||||
public class RemoteConfigDefinitionEditor : UnityEditor.Editor
|
||||
{
|
||||
private bool showRemotePreview;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var def = (RemoteConfigDefinition)target;
|
||||
|
||||
// Auto sync group name with SDKConfig
|
||||
var sdkConfig = Resources.Load<ShiroginConfig>(SDKConstants.ConfigResourcePath);
|
||||
if (sdkConfig != null && def.GroupName != sdkConfig.selectedRemoteGroup)
|
||||
{
|
||||
def.SetGroupName(sdkConfig.selectedRemoteGroup);
|
||||
EditorUtility.SetDirty(def);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(6);
|
||||
EditorGUILayout.LabelField("Remote Config Info", EditorStyles.boldLabel);
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
EditorGUILayout.TextField("Group Name", def.GroupName);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
DrawDefaultInspector();
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
EditorGUILayout.LabelField("Remote Config Tools", EditorStyles.boldLabel);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("✅ Validate Keys"))
|
||||
{
|
||||
if (def.ValidateKeys(out var err))
|
||||
EditorUtility.DisplayDialog("Validation", "All keys valid ✅", "OK");
|
||||
else
|
||||
EditorUtility.DisplayDialog("Validation Failed", err, "OK");
|
||||
}
|
||||
|
||||
if (GUILayout.Button("🔤 Sort by Key"))
|
||||
{
|
||||
Undo.RecordObject(def, "Sort Remote Config Entries");
|
||||
def.Entries = def.Entries.OrderBy(e => e.Key).ToList();
|
||||
EditorUtility.SetDirty(def);
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button("📋 Copy JSON to Clipboard"))
|
||||
{
|
||||
if (!def.ValidateKeys(out var err))
|
||||
{
|
||||
EditorUtility.DisplayDialog("Error", err, "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
var json = def.GenerateJson();
|
||||
EditorGUIUtility.systemCopyBuffer = json;
|
||||
Debug.Log($"[RemoteConfig] JSON copied to clipboard ({json.Length} chars)");
|
||||
EditorUtility.DisplayDialog("Success", "JSON copied to clipboard ✅", "OK");
|
||||
}
|
||||
|
||||
// 🔸 Import button
|
||||
if (GUILayout.Button("⬆️ Import from RemoteConfigData")) ImportFromRemoteConfigData(def);
|
||||
|
||||
// 🌐 Remote Data Preview (Cached)
|
||||
EditorGUILayout.Space(12);
|
||||
showRemotePreview = EditorGUILayout.Foldout(showRemotePreview, "🌐 Remote Data Preview (Cached)", true);
|
||||
|
||||
if (showRemotePreview)
|
||||
{
|
||||
if (GUILayout.Button("🔄 Refresh from Cache"))
|
||||
{
|
||||
def.RefreshFromCache();
|
||||
Debug.Log("[RemoteConfigDefinition] 🔄 Refreshed from cached RemoteConfigData.");
|
||||
}
|
||||
|
||||
if (def.RemoteEntries == null || def.RemoteEntries.Count == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("No cached remote data found.", MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.Space(4);
|
||||
EditorGUILayout.LabelField("Cached Entries:", EditorStyles.boldLabel);
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
|
||||
foreach (var entry in def.RemoteEntries)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
EditorGUILayout.LabelField(entry.Key, GUILayout.Width(160));
|
||||
|
||||
switch (entry.Type)
|
||||
{
|
||||
case RemoteConfigDefinition.ValueType.Boolean:
|
||||
EditorGUILayout.Toggle(entry.BoolValue);
|
||||
break;
|
||||
case RemoteConfigDefinition.ValueType.Number:
|
||||
EditorGUILayout.LabelField(entry.NumberValue.ToString(CultureInfo.InvariantCulture));
|
||||
break;
|
||||
default:
|
||||
EditorGUILayout.LabelField(entry.StringValue);
|
||||
break;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUI.changed)
|
||||
EditorUtility.SetDirty(def);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports instance fields from RemoteConfigData as RemoteConfigDefinition entries.
|
||||
/// Works with BaseData-based RemoteConfigData (non-static).
|
||||
/// </summary>
|
||||
private void ImportFromRemoteConfigData(RemoteConfigDefinition def)
|
||||
{
|
||||
// Onay penceresi
|
||||
var proceed = EditorUtility.DisplayDialog(
|
||||
"Confirm Import",
|
||||
"Are you sure you want to import all fields from RemoteConfigData?\n\nThis will overwrite current entries.",
|
||||
"Yes, Import",
|
||||
"Cancel"
|
||||
);
|
||||
if (!proceed)
|
||||
{
|
||||
Debug.Log("[RemoteConfigDefinitionEditor] 🚫 Import canceled by user.");
|
||||
return;
|
||||
}
|
||||
|
||||
Undo.RecordObject(def, "Import from RemoteConfigData");
|
||||
def.Entries.Clear();
|
||||
|
||||
var remoteDataType = typeof(RemoteConfigData);
|
||||
|
||||
// Public INSTANCE fields (BaseData yapısıyla uyumlu)
|
||||
var fields = remoteDataType.GetFields(BindingFlags.Public |
|
||||
BindingFlags.Instance);
|
||||
if (fields == null || fields.Length == 0)
|
||||
{
|
||||
Debug.LogWarning(
|
||||
"[RemoteConfigDefinitionEditor] ⚠️ RemoteConfigData içinde public instance field bulunamadı.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Geçici örnek yarat (BaseData default değerlerini okumak için)
|
||||
var instance = Activator.CreateInstance(remoteDataType);
|
||||
var ci = CultureInfo.InvariantCulture;
|
||||
|
||||
foreach (var f in fields)
|
||||
{
|
||||
if (f.IsLiteral || f.IsInitOnly) continue; // const/readonly atla
|
||||
|
||||
var entry = new RemoteConfigDefinition.Entry();
|
||||
entry.Key = ToSnakeCasePreserveUnderscores(f.Name); // 🔸 snake_case + '_' korunur
|
||||
|
||||
var val = f.GetValue(instance);
|
||||
|
||||
if (val == null)
|
||||
{
|
||||
entry.Type = RemoteConfigDefinition.ValueType.String;
|
||||
entry.StringValue = string.Empty;
|
||||
}
|
||||
else if (val is bool b)
|
||||
{
|
||||
entry.Type = RemoteConfigDefinition.ValueType.Boolean;
|
||||
entry.BoolValue = b;
|
||||
}
|
||||
else if (val is int i)
|
||||
{
|
||||
entry.Type = RemoteConfigDefinition.ValueType.Number;
|
||||
entry.NumberValue = i;
|
||||
}
|
||||
else if (val is float fl)
|
||||
{
|
||||
entry.Type = RemoteConfigDefinition.ValueType.Number;
|
||||
entry.NumberValue = fl;
|
||||
}
|
||||
else if (val is Array arr)
|
||||
{
|
||||
// Dizileri "1,1.4,2" şeklinde string'e çevir
|
||||
var values = arr.Cast<object>().Select(x => Convert.ToString(x, ci)).ToArray();
|
||||
entry.Type = RemoteConfigDefinition.ValueType.String;
|
||||
entry.StringValue = string.Join(",", values);
|
||||
}
|
||||
else if (val is IEnumerable list && !(val is string))
|
||||
{
|
||||
// Listeleri string'e çevir
|
||||
var values = new List<string>();
|
||||
foreach (var item in list)
|
||||
values.Add(Convert.ToString(item, ci));
|
||||
|
||||
entry.Type = RemoteConfigDefinition.ValueType.String;
|
||||
entry.StringValue = string.Join(",", values);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.Type = RemoteConfigDefinition.ValueType.String;
|
||||
entry.StringValue = val.ToString();
|
||||
}
|
||||
|
||||
def.Entries.Add(entry);
|
||||
}
|
||||
|
||||
def.Entries = def.Entries.OrderBy(e => e.Key).ToList();
|
||||
EditorUtility.SetDirty(def);
|
||||
|
||||
Debug.Log($"[RemoteConfigDefinitionEditor] ✅ Imported {def.Entries.Count} entries from RemoteConfigData.");
|
||||
EditorUtility.DisplayDialog("Import Completed",
|
||||
$"Successfully imported {def.Entries.Count} entries from RemoteConfigData.", "OK");
|
||||
}
|
||||
|
||||
// Pascal/camelCase → snake_case, mevcut '_' karakterlerini KORUR
|
||||
// Örn: "TargetFps" -> "target_fps", "Enemy_HpMultiplier" -> "enemy_hp_multiplier"
|
||||
private static string ToSnakeCasePreserveUnderscores(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input)) return input;
|
||||
|
||||
// Büyük harf grupları ve geçişleri doğru bölmek için regex
|
||||
// (mevcut '_' karakterlerine dokunmuyoruz)
|
||||
var s = Regex.Replace(input, "([A-Z]+)([A-Z][a-z])", "$1_$2");
|
||||
s = Regex.Replace(s, "([a-z0-9])([A-Z])", "$1_$2");
|
||||
|
||||
// Çift alt çizgileri tek'e indir (varsa)
|
||||
while (s.Contains("__")) s = s.Replace("__", "_");
|
||||
|
||||
return s.ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a7f932636f994e74a05bd163c0d62dc8
|
||||
timeCreated: 1760346189
|
||||
8
Assets/ShiroginSDK/Editor/Resources.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 81cfc5cc491b31c47a3b391a5f090c1d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/ShiroginSDK/Editor/Resources/Shirogin.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 88388748fbd09b24eada8e3dbdc574a8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0268502886f1ef24591dbc7b41930bf1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 36 KiB |
|
|
@ -0,0 +1,156 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4529796387140d847b0a13f3623fe0c9
|
||||
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: 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: 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
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
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: 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: 4
|
||||
buildTarget: iOS
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5c9c7b49e4716a44ab88294e4a7138dc
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 6 KiB |
|
|
@ -0,0 +1,156 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 07e56e8de2b1f1e4684c80e7ddf8dd77
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
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: 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: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
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: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 0
|
||||
crunchedCompression: 1
|
||||
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
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
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: 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: 4
|
||||
buildTarget: iOS
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 6 KiB |
|
|
@ -0,0 +1,156 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0804f6ef69f8f0b4e8d1963c1865e109
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
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: 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: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
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: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 0
|
||||
crunchedCompression: 1
|
||||
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
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
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: 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: 4
|
||||
buildTarget: iOS
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
|
|
@ -0,0 +1,156 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8e40403edd8c8ae4da2bed8ed60c293f
|
||||
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: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
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: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 0
|
||||
crunchedCompression: 1
|
||||
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
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
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: 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: 4
|
||||
buildTarget: iOS
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 6 KiB |
|
|
@ -0,0 +1,156 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c8a83af7ebfad3e4ab67ae882f6f2f80
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
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: 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: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
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: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 0
|
||||
crunchedCompression: 1
|
||||
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
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
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: 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: 4
|
||||
buildTarget: iOS
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
|
|
@ -0,0 +1,156 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 32968a781eeaead4e9d1fb5363ac17ee
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
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: 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: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
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: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 100
|
||||
crunchedCompression: 1
|
||||
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
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
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: 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: 4
|
||||
buildTarget: iOS
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 6 KiB |
|
|
@ -0,0 +1,156 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4ddcf1578be1f79429b66f2a7a8108ff
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
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: 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: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
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: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 0
|
||||
crunchedCompression: 1
|
||||
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
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
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: 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: 4
|
||||
buildTarget: iOS
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
|
|
@ -0,0 +1,156 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4c21dbdfeb306694cade94ee94012095
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
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: 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: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
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: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
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: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 0
|
||||
crunchedCompression: 1
|
||||
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
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
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: 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: 4
|
||||
buildTarget: iOS
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 6 KiB |
|
|
@ -0,0 +1,156 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 15798e41d3533de4ba4816a5f6242982
|
||||
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: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
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: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 256
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 0
|
||||
crunchedCompression: 1
|
||||
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
|
||||
- serializedVersion: 4
|
||||
buildTarget: Android
|
||||
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: 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: 4
|
||||
buildTarget: iOS
|
||||
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: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
19
Assets/ShiroginSDK/Editor/ShiroginSDK.Editor.asmdef
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "ShiroginSDK.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"Unity.TextMeshPro",
|
||||
"ShiroginSDK.Runtime"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
Assets/ShiroginSDK/Editor/ShiroginSDK.Editor.asmdef.meta
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: be300420007eaf54aacf878fb13463a8
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
35
Assets/ShiroginSDK/Editor/SubHeaderDrawer.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#if UNITY_EDITOR
|
||||
using ShiroginSDK.Runtime.Core.Editor.Attributes;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ShiroginSDK.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(SubHeaderAttribute))]
|
||||
public class SubHeaderDrawer : DecoratorDrawer
|
||||
{
|
||||
public override float GetHeight()
|
||||
{
|
||||
var subHeader = (SubHeaderAttribute)attribute;
|
||||
return EditorGUIUtility.singleLineHeight + subHeader.spaceAbove;
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position)
|
||||
{
|
||||
var subHeader = (SubHeaderAttribute)attribute;
|
||||
|
||||
// Adjust vertical offset
|
||||
position.y += subHeader.spaceAbove;
|
||||
position.height = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
// Prevent null or empty label text from crashing Unity 6 UIElements backend
|
||||
var headerText = subHeader.header ?? string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(headerText))
|
||||
return;
|
||||
|
||||
// Draw the label safely
|
||||
EditorGUI.LabelField(position, headerText, EditorStyles.boldLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
3
Assets/ShiroginSDK/Editor/SubHeaderDrawer.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 38daa8b300134e2580f2eb4e6159d2ae
|
||||
timeCreated: 1759310055
|
||||
3
Assets/ShiroginSDK/Editor/Windows.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5bc4b28b77644a1091082bb220294f10
|
||||
timeCreated: 1765824754
|
||||
335
Assets/ShiroginSDK/Editor/Windows/ShiroginWelcomeWindow.cs
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using ShiroginSDK.Editor.Bitbucket;
|
||||
using ShiroginSDK.Runtime.Core.SDK; // Config için
|
||||
using ShiroginSDK.Runtime.Shared.Constants;
|
||||
|
||||
namespace ShiroginSDK.Editor.Windows
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public class ShiroginWelcomeWindow : EditorWindow
|
||||
{
|
||||
private Texture2D _logo;
|
||||
|
||||
// --- LINKS ---
|
||||
private const string DOCS_URL =
|
||||
"https://bitbucket.org/batud/shiroginsdk/src/Version_1/Assets/ShiroginSDK/README.md";
|
||||
|
||||
private const string CHANGELOG_URL =
|
||||
"https://bitbucket.org/batud/shiroginsdk/src/Version_1/Assets/ShiroginSDK/CHANGELOG.md";
|
||||
|
||||
private const string DISCORD_URL = "https://discord.gg/wgq3tc7h";
|
||||
private const string WEBSITE_URL = "https://shirogin.com";
|
||||
|
||||
// --- PREFS ---
|
||||
private const string PREF_SHOW_AT_STARTUP = "ShiroginSDK_ShowWelcome_V2";
|
||||
|
||||
static ShiroginWelcomeWindow()
|
||||
{
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
if (EditorPrefs.GetBool(PREF_SHOW_AT_STARTUP, true))
|
||||
{
|
||||
ShowWindow();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[MenuItem("ShiroginSDK/👋 Welcome", false, 0)]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
// Pencere boyutunu biraz artırdım ki sığsın
|
||||
var window = GetWindow<ShiroginWelcomeWindow>(true, "Welcome to Shirogin SDK", true);
|
||||
window.minSize = new Vector2(500, 520);
|
||||
window.maxSize = new Vector2(500, 520);
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets(
|
||||
"shirogin_logo t:Texture2D",
|
||||
new[] { "Assets/ShiroginSDK" }
|
||||
);
|
||||
|
||||
if (guids.Length > 0)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||||
_logo = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
DrawBackground();
|
||||
|
||||
GUILayout.BeginVertical();
|
||||
|
||||
// 1. LOGO & BAŞLIK
|
||||
DrawHeader();
|
||||
|
||||
GUILayout.Space(15);
|
||||
|
||||
// 2. HOŞGELDİN METNİ (Düzeltildi)
|
||||
DrawWelcomeMessage();
|
||||
|
||||
GUILayout.Space(20);
|
||||
|
||||
// 3. BUTONLAR (Setup, Manager, Config)
|
||||
DrawActions();
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
// 4. ALT BİLGİ & LİNKLER
|
||||
DrawFooter();
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void DrawBackground()
|
||||
{
|
||||
EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height), new Color(0.18f, 0.18f, 0.18f));
|
||||
}
|
||||
|
||||
private void DrawHeader()
|
||||
{
|
||||
GUILayout.Space(20);
|
||||
if (_logo != null)
|
||||
{
|
||||
var aspect = (float)_logo.width / _logo.height;
|
||||
var width = 120f;
|
||||
var height = width / aspect;
|
||||
var rect = GUILayoutUtility.GetRect(width, height);
|
||||
float xPos = (position.width - width) / 2;
|
||||
GUI.DrawTexture(new Rect(xPos, rect.y, width, height), _logo);
|
||||
}
|
||||
else
|
||||
{
|
||||
var titleStyle = new GUIStyle(EditorStyles.boldLabel)
|
||||
{
|
||||
fontSize = 28,
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
normal = { textColor = new Color(0.9f, 0.9f, 0.9f) }
|
||||
};
|
||||
GUILayout.Label("SHIROGIN SDK", titleStyle);
|
||||
}
|
||||
|
||||
var subStyle = new GUIStyle(EditorStyles.label)
|
||||
{
|
||||
fontSize = 12,
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
fontStyle = FontStyle.Italic,
|
||||
normal = { textColor = new Color(0.6f, 0.6f, 0.6f) }
|
||||
};
|
||||
// GUILayout.Label("Professional Unity Solutions", subStyle);
|
||||
}
|
||||
|
||||
private void DrawWelcomeMessage()
|
||||
{
|
||||
var style = new GUIStyle(EditorStyles.label)
|
||||
{
|
||||
wordWrap = true,
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
fontSize = 14,
|
||||
richText = true,
|
||||
normal = { textColor = new Color(0.85f, 0.85f, 0.85f) }
|
||||
};
|
||||
|
||||
// GUILayout.Label kullanarak otomatik boyutlandırma sağladık
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
// GUILayout.Label(
|
||||
// "Thank you for choosing <b>ShiroginSDK</b>.\n\n" +
|
||||
// "This toolkit provides everything you need to build scalable games,\n" +
|
||||
// "from Ads and IAP to Analytics and UI Frameworks.",
|
||||
// style, GUILayout.Width(420));
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void DrawActions()
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
// --- SETUP WIZARD ---
|
||||
if (DrawBigButton("🚀 Setup Wizard", "Install essential packages", new Color(0.2f, 0.6f, 0.3f)))
|
||||
{
|
||||
AssetRegistryEditor.ShowWindow(true);
|
||||
Close();
|
||||
}
|
||||
|
||||
GUILayout.Space(15);
|
||||
|
||||
// --- ASSET MANAGER ---
|
||||
if (DrawBigButton("📦 Asset Manager", "Manage all modules", new Color(0.2f, 0.4f, 0.8f)))
|
||||
{
|
||||
AssetRegistryEditor.ShowWindow(false);
|
||||
Close();
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(15);
|
||||
|
||||
// --- OPEN CONFIG BUTTON (YENİ) ---
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
var configBtnStyle = new GUIStyle(GUI.skin.button)
|
||||
{ fixedHeight = 35, fontSize = 12, fontStyle = FontStyle.Bold };
|
||||
GUI.backgroundColor = new Color(0.9f, 0.6f, 0.2f); // Turuncu ton
|
||||
|
||||
if (GUILayout.Button("⚙ Open SDK Config Settings", configBtnStyle, GUILayout.Width(250)))
|
||||
{
|
||||
SelectConfig();
|
||||
Close();
|
||||
}
|
||||
|
||||
GUI.backgroundColor = Color.white;
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private bool DrawBigButton(string title, string subtitle, Color color)
|
||||
{
|
||||
var btnStyle = new GUIStyle(GUI.skin.button);
|
||||
var width = 200f;
|
||||
var height = 60f;
|
||||
|
||||
var oldColor = GUI.backgroundColor;
|
||||
GUI.backgroundColor = color;
|
||||
|
||||
bool clicked = GUILayout.Button("", btnStyle, GUILayout.Width(width), GUILayout.Height(height));
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
var rect = GUILayoutUtility.GetLastRect();
|
||||
|
||||
var titleStyle = new GUIStyle(EditorStyles.boldLabel)
|
||||
{
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
fontSize = 15,
|
||||
normal = { textColor = Color.white }
|
||||
};
|
||||
|
||||
var subStyle = new GUIStyle(EditorStyles.label)
|
||||
{
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
fontSize = 10,
|
||||
normal = { textColor = new Color(1f, 1f, 1f, 0.85f) }
|
||||
};
|
||||
|
||||
// Pozisyonları biraz daha hassas ayarladım
|
||||
var titleRect = new Rect(rect.x, rect.y + 10, rect.width, 20);
|
||||
var subRect = new Rect(rect.x, rect.y + 32, rect.width, 20);
|
||||
|
||||
GUI.Label(titleRect, title, titleStyle);
|
||||
GUI.Label(subRect, subtitle, subStyle);
|
||||
}
|
||||
|
||||
GUI.backgroundColor = oldColor;
|
||||
return clicked;
|
||||
}
|
||||
|
||||
private void DrawFooter()
|
||||
{
|
||||
GUILayout.BeginVertical();
|
||||
|
||||
// Çizgi
|
||||
var lineRect = GUILayoutUtility.GetRect(position.width - 40, 1);
|
||||
lineRect.x += 20;
|
||||
lineRect.width -= 40;
|
||||
EditorGUI.DrawRect(lineRect, new Color(0.3f, 0.3f, 0.3f));
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
// Linkler
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
if (LinkButton("📚 Documentation", DOCS_URL))
|
||||
{
|
||||
}
|
||||
|
||||
GUILayout.Space(15);
|
||||
if (LinkButton("📚 Changelog", CHANGELOG_URL))
|
||||
{
|
||||
}
|
||||
|
||||
GUILayout.Space(15);
|
||||
if (LinkButton("💬 Discord", DISCORD_URL))
|
||||
{
|
||||
}
|
||||
|
||||
GUILayout.Space(15);
|
||||
if (LinkButton("🌐 Website", WEBSITE_URL))
|
||||
{
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
// Toggle
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
bool show = EditorPrefs.GetBool(PREF_SHOW_AT_STARTUP, true);
|
||||
bool newShow = GUILayout.Toggle(show, "Show this window on startup");
|
||||
if (newShow != show) EditorPrefs.SetBool(PREF_SHOW_AT_STARTUP, newShow);
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(10);
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private bool LinkButton(string label, string url)
|
||||
{
|
||||
var style = new GUIStyle(EditorStyles.label)
|
||||
{
|
||||
normal = { textColor = new Color(0.4f, 0.7f, 1f) },
|
||||
hover = { textColor = Color.white }
|
||||
};
|
||||
if (GUILayout.Button(label, style, GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
Application.OpenURL(url);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- HELPER: CONFIG BULMA VE SEÇME ---
|
||||
private void SelectConfig()
|
||||
{
|
||||
var config = Resources.Load<ShiroginConfig>(SDKConstants.ConfigResourcePath);
|
||||
if (config != null)
|
||||
{
|
||||
Selection.activeObject = config;
|
||||
EditorGUIUtility.PingObject(config);
|
||||
Debug.Log("[ShiroginSDK] Config file selected.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resources'da yoksa projede ara
|
||||
string[] guids = AssetDatabase.FindAssets("t:ShiroginConfig");
|
||||
if (guids.Length > 0)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||||
var obj = AssetDatabase.LoadAssetAtPath<ShiroginConfig>(path);
|
||||
Selection.activeObject = obj;
|
||||
EditorGUIUtility.PingObject(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayDialog("Config Not Found",
|
||||
"ShiroginConfig file could not be found.\nPlease create it via 'Create > ShiroginSDK > ShiroginConfig'.",
|
||||
"OK");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 64ce90d2a71e4357b30e125402ffe27d
|
||||
timeCreated: 1765824761
|
||||
3
Assets/ShiroginSDK/Prefabs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3e9d1725d6084809ab0bb09455a17321
|
||||
timeCreated: 1760612286
|
||||
3
Assets/ShiroginSDK/Prefabs/IAP.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 914368bd284d4719b40a88b739e5c2fb
|
||||
timeCreated: 1760612304
|
||||
8
Assets/ShiroginSDK/Prefabs/IAP/Canvas.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 963a9768220bd324c92754ac9921612d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||