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:
|
||||||