Shop and In App Purchase

dev-ali
Ali Sharoz 7 hours ago
parent c128924706
commit 6076e6db36

File diff suppressed because it is too large Load Diff

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5b5f91794ab69874083e5a024dceb063
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,51 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.2.2] - 2023-01-10
- Fix icon offset influence on other inspector entries
## [1.2.1] - 2022-04-24
- Fix detection for PlayerPrefs where the key contains '_h'
- Use unicode for windows registry lookups to support none ASCII chars in projects names
## [1.2.0] - 2022-01-01
### Added
- Enhanced search field to filter player preferences by key or value
- Add sorting functionality for Pref entries (none, ascending, descending)
### Removed
- Remove Unity 2017 support
- Remove Unity 2018 support
## [1.1.2] - 2021-07-01
- Fixed ImageManger icon detection
## [1.1.1] - 2021-05-23
- Add utf8 key encryption support for windows
## [1.1.0] - 2021-05-17
- Improve key validation with more characters
- Async output reading for MAC plist process
- Performance optimizations
## [1.0.4] - 2020-09-20
- Add handling for special characters in product/company name
- Improvement of plist read call on MAC
## [1.0.3] - 2020-09-20
- Fix text color on professional skin
## [1.0.2] - 2020-08-11
- Switch package author to 'BG Tools'
- Fix UPM documentation image path
## [1.0.1] - 2020-06-01
- Resizable column width for table layout
- Multiple UX improvements
- Add manual
## [1.0.0] - 2020-05-26
This is the first release of PlayerPrefs Editor

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 53e2fe1165389a84c8c415eed555029d
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ac7740c4463611344b22ca368af84da1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fa4d09c10dec18841a67065c4ef628bf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: 418213a0ca74fec47960ee53fbae1cad
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
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
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 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: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: 34408ed3bf23927459af6b3263c3b147
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
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
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 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: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,474 @@
<!DOCTYPE html>
<html>
<head>
<title>PlayerPrefsEditor-Manual</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"></meta>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<style type="text/css">
body {
font-family: Helvetica, arial, sans-serif;
font-size: 14px;
line-height: 1.6;
padding-top: 10px;
padding-bottom: 10px;
background-color: white;
padding: 30px;
color: #333;
}
body &gt; *:first-child {
margin-top: 0 !important;
}
body &gt; *:last-child {
margin-bottom: 0 !important;
}
a {
color: #4183C4;
text-decoration: none;
}
a.absent {
color: #cc0000;
}
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0;
}
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative;
}
h2:first-child, h1:first-child, h1:first-child + h2, h3:first-child, h4:first-child, h5:first-child, h6:first-child {
margin-top: 0;
padding-top: 0;
}
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
text-decoration: none;
}
h1 tt, h1 code {
font-size: inherit;
}
h2 tt, h2 code {
font-size: inherit;
}
h3 tt, h3 code {
font-size: inherit;
}
h4 tt, h4 code {
font-size: inherit;
}
h5 tt, h5 code {
font-size: inherit;
}
h6 tt, h6 code {
font-size: inherit;
}
h1 {
font-size: 28px;
color: black;
}
h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
color: #777777;
font-size: 14px;
}
p, blockquote, ul, ol, dl, li, table, pre {
margin: 15px 0;
}
/*
hr {
border: 0 none;
color: #cccccc;
height: 4px;
padding: 0;
}
*/
body &gt; h2:first-child {
margin-top: 0;
padding-top: 0;
}
body &gt; h1:first-child {
margin-top: 0;
padding-top: 0;
}
body &gt; h1:first-child + h2 {
margin-top: 0;
padding-top: 0;
}
body &gt; h3:first-child, body &gt; h4:first-child, body &gt; h5:first-child, body &gt; h6:first-child {
margin-top: 0;
padding-top: 0;
}
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
margin-top: 0;
}
li p.first {
display: inline-block;
}
ul, ol {
padding-left: 30px;
}
ul :first-child, ol :first-child {
margin-top: 0;
}
ul :last-child, ol :last-child {
margin-bottom: 0;
}
dl {
padding: 0;
}
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}
dl dt:first-child {
padding: 0;
}
dl dt &gt; :first-child {
margin-top: 0;
}
dl dt &gt; :last-child {
margin-bottom: 0;
}
dl dd {
margin: 0 0 15px;
padding: 0 15px;
}
dl dd &gt; :first-child {
margin-top: 0;
}
dl dd &gt; :last-child {
margin-bottom: 0;
}
blockquote {
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777;
}
blockquote &gt; :first-child {
margin-top: 0;
}
blockquote &gt; :last-child {
margin-bottom: 0;
}
table {
padding: 0;
}
table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0;
}
table tr:nth-child(2n) {
background-color: #f8f8f8;
}
table tr th {
font-weight: bold;
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px;
}
table tr td {
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px;
}
table tr th :first-child, table tr td :first-child {
margin-top: 0;
}
table tr th :last-child, table tr td :last-child {
margin-bottom: 0;
}
img {
max-width: 100%;
}
span.frame {
display: block;
overflow: hidden;
}
span.frame &gt; span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto;
}
span.frame span img {
display: block;
float: left;
}
span.frame span span {
clear: both;
color: #333333;
display: block;
padding: 5px 0 0;
}
span.align-center {
display: block;
overflow: hidden;
clear: both;
}
span.align-center &gt; span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center;
}
span.align-center span img {
margin: 0 auto;
text-align: center;
}
span.align-right {
display: block;
overflow: hidden;
clear: both;
}
span.align-right &gt; span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right;
}
span.align-right span img {
margin: 0;
text-align: right;
}
span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left;
}
span.float-left span {
margin: 13px 0 0;
}
span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right;
}
span.float-right &gt; span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right;
}
code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}
pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}
.highlight pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}
pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}
pre code, pre tt {
background-color: transparent;
border: none;
}
</style>
</head>
<body style="">
<h1 id="0">PlayerPrefs Editor for Unity 3D</h1>
<p id="2">Tool extension for the Unity Editor that enables easy access to the player preferences over a simple UI. Allows to view, add, remove and modify entries on the development machine.</p>
<h2 id="4">Support</h2>
<p id="6"><a href="https://github.com/Dysman/bgTools-playerPrefsEditor">GitHub</a> | <a href="https://www.bgtools.de/post/playerprefseditor/">Website</a> | <a href="mailto:support@bgtools.de">Mail</a> | <a href="https://discord.gg/8rcPZrD">Discord</a></p>
<h2 id="8">Features</h2>
<ul id="10">
<li id="10">Add, remove and edit PlayerPrefs</li>
<li id="11">Intuitive visual editor</li>
<li id="12">Works with standard Unity PlayerPrefs</li>
<li id="13">Monitors changes from code</li>
<li id="14">Supports all editors (Windows, Linux, MacOS)</li>
<li id="15">Lightweight dockable for full integration in your workflow</li>
<li id="16">Supports both skins (Personal, Professional)</li>
</ul>
<h2 id="18">Usage</h2>
<p id="20">The PlayerPrefs Editor is located in the top menu at Tools/BG Tools/PlayerPrefs Editor. It's a standard dockable window, so place it wherever it helps to be productive.</p>
<p id="22"><img src="./Images/bgtools_ppe_manual_layout.png" width="100%" style="max-width:800px" alt="PlayerPrefs editor window layout" /></p>
<p id="24">The PlayerPrefs Editor window displays:</p>
<ul id="25">
<li id="25">(A) Filter field</li>
<li id="26">(B) Sort mode</li>
<li id="27">(C) Toggle 'System changes monitoring' behavior</li>
<li id="28">(D) Refresh data</li>
<li id="29">(E) Delete all data</li>
<li id="30">(F) Operating system and path to PlayerPrefs data</li>
<li id="31">(G) PlayerPrefs data list (Key, Type, Value)</li>
<li id="32">(H) Add/Remove a PlayerPrefs entry</li>
<li id="33">(I) Toggle visibility of system defined PlayerPrefs</li>
</ul>
<h3 id="35">Modify Entries</h3>
<p id="37">The PlayerPrefs Editor allow to add, remove and edit PlayerPrefs data.</p>
<p id="39"><strong>Add a new entry</strong></p>
<p id="41">Press the '+' button and select the type of the new PlayerPref entry. It's not possible to modify this type later. Add the key for the new entry in the upcoming dialog field. Additionally the dialog will provide feedback when it detected unintended overrides or invalid characters.</p>
<p id="43"><strong>Remove a existing entry</strong></p>
<p id="45">Select the entry from the list that you want to delete. Press the '-' button to remove this entry. Confirm the warning dialog to finish the operation.</p>
<p id="47"><strong>Modify a existing entry</strong></p>
<p id="49">To change a value of a existing entry do this directly in the value field in the PlayerPref list.</p>
<h3 id="51">Sort &amp; Filter</h3>
<p id="53"><strong>Sorting</strong></p>
<p id="55">Circle trought the sorting funtions by pressing the (B) button in the toolbar.</p>
<p id="57">Following sorting function are aviliable for the PlayerPref entries:</p>
<ul id="58">
<li id="58">None</li>
<li id="59">Ascending</li>
<li id="60">Descending</li>
</ul>
<p id="62"><strong>Filtering</strong></p>
<p id="64">Enter a text into the the search field (A) in the toolbar to filter the PlayerPrefs data list (G).</p>
<p id="66"><img src="./Images/bgtools_ppe_manual_filterModes.png" width="50%" style="max-width:350px" alt="PlayerPrefs editor searchfield modes" /></p>
<p id="68">Additionally select the mode for filtering by pressing on the magnifying glass icon in the search field. Choose between filtering the existing PlayPrefs by key or value. The current search target will be shown in the searchfield if no search string is present.</p>
<h3 id="70">Monitoring system changes</h3>
<p id="72">The plugin can monitor changes at runtime automatically and keep the view up-to-date. This detection is active by default, but it can be turned off over the (C) button in the toolbar.</p>
<h2 id="74">Samples</h2>
<p id="76">This package includes two samples for testing purposes:</p>
<p id="78"><strong>Test Value Menu</strong></p>
<blockquote id="79">
<p id="79">Adds new entries into the top menu Tools/BG Tools/PlayerPrefs Test Values. This allows easily to add text values to the PlayerPrefs of the current project.</p>
</blockquote>
<p id="81"><strong>Sample Scene</strong></p>
<blockquote id="82">
<p id="82">Simple UI that manipulates PlayerPrefs entries on runtime.</p>
</blockquote>
<h2 id="84">Technical details</h2>
<h3 id="85">Requirements</h3>
<p id="87">This version of PlayerPrefs Editor is compatible with the following versions of the Unity Editor:</p>
<blockquote id="89">
<p id="89">2019.4 and later (recommended)<br />
Windows, MacOS, Linux</p>
</blockquote>
<h3 id="92">Limitations MacOS</h3>
<p id="94">Due to technical on MacOS it take time to update the persistent file that stores the PlayerPrefs. To avoid inconsistent data the plugin will show a loading screen until the data can be fully refreshed. Sorry for the inconvenience.</p>
<p id="96">Keep in mind that it's possible to deactivate the automatic refresh in the settings.</p>
</body>
<html>

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 907d7ca800984c64d9b2116fdaf6681e
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 31c463d7ccf40cf4cab8c990a851231d
folderAsset: yes
timeCreated: 1500321077
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,224 @@
#if UNITY_EDITOR
using System;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace BgTools.Utils
{
public class ImageManager
{
// Keep this ID unique
private static readonly string ID = "[PlayerPrefsEditor] com.bgtools.playerprefseditor";
private static string imageManagerPath;
private static string GetAssetDir()
{
if (imageManagerPath != null)
{
return imageManagerPath;
}
foreach (string assetGuid in AssetDatabase.FindAssets("ImageManager"))
{
string assetPath = AssetDatabase.GUIDToAssetPath(assetGuid);
string fileName = Path.GetFileName(assetPath);
if (fileName.Equals("ImageManager.cs"))
{
// Check ID if it's the correct ImageManager
if (File.ReadLines(Path.GetFullPath(assetPath)).Any(line => line.Contains(ID)))
{
imageManagerPath = Path.GetDirectoryName(assetPath) + Path.DirectorySeparatorChar;
return imageManagerPath;
}
}
}
throw new Exception("Cannot find ImageManager.cs in the project. Are sure all the files in place?");
}
public static Texture2D GetOsIcon()
{
#if UNITY_EDITOR_WIN
return OsWinIcon;
#elif UNITY_EDITOR_OSX
return OsMacIcon;
#elif UNITY_EDITOR_LINUX
return OsLinuxIcon;
#endif
}
private static Texture2D osLinuxIcon;
public static Texture2D OsLinuxIcon
{
get
{
if (osLinuxIcon == null)
{
osLinuxIcon = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "os_linux_icon.png", typeof(Texture2D));
}
return osLinuxIcon;
}
}
private static Texture2D osWinIcon;
public static Texture2D OsWinIcon
{
get
{
if (osWinIcon == null)
{
osWinIcon = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "os_win_icon.png", typeof(Texture2D));
}
return osWinIcon;
}
}
private static Texture2D osMacIcon;
public static Texture2D OsMacIcon
{
get
{
if (osMacIcon == null)
{
osMacIcon = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "os_mac_icon.png", typeof(Texture2D));
}
return osMacIcon;
}
}
private static GUIContent[] spinWheelIcons;
public static GUIContent[] SpinWheelIcons
{
get
{
if(spinWheelIcons == null)
{
spinWheelIcons = new GUIContent[12];
for (int i = 0; i < 12; i++)
spinWheelIcons[i] = EditorGUIUtility.IconContent("WaitSpin" + i.ToString("00"));
}
return spinWheelIcons;
}
}
private static Texture2D refresh;
public static Texture2D Refresh
{
get
{
if (refresh == null)
{
refresh = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "refresh.png", typeof(Texture2D));
}
return refresh;
}
}
private static Texture2D trash;
public static Texture2D Trash
{
get
{
if (trash == null)
{
trash = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "trash.png", typeof(Texture2D));
}
return trash;
}
}
private static Texture2D exclamation;
public static Texture2D Exclamation
{
get
{
if(exclamation == null)
{
exclamation = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "exclamation.png", typeof(Texture2D));
}
return exclamation;
}
}
private static Texture2D info;
public static Texture2D Info
{
get
{
if (info == null)
{
info = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "info.png", typeof(Texture2D));
}
return info;
}
}
private static Texture2D watching;
public static Texture2D Watching
{
get
{
if(watching == null)
{
watching = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "watching.png", typeof(Texture2D));
}
return watching;
}
}
private static Texture2D notWatching;
public static Texture2D NotWatching
{
get
{
if (notWatching == null)
{
notWatching = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "not_watching.png", typeof(Texture2D));
}
return notWatching;
}
}
private static Texture2D sortDisabled;
public static Texture2D SortDisabled
{
get
{
if (sortDisabled == null)
{
sortDisabled = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "sort.png", typeof(Texture2D));
}
return sortDisabled;
}
}
private static Texture2D sortAsscending;
public static Texture2D SortAsscending
{
get
{
if (sortAsscending == null)
{
sortAsscending = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "sort_asc.png", typeof(Texture2D));
}
return sortAsscending;
}
}
private static Texture2D sortDescending;
public static Texture2D SortDescending
{
get
{
if (sortDescending == null)
{
sortDescending = (Texture2D)AssetDatabase.LoadAssetAtPath(GetAssetDir() + "sort_desc.png", typeof(Texture2D));
}
return sortDescending;
}
}
}
}
#endif

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ee68545419352384a950cc488e731084
timeCreated: 1500324006
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,14 @@
{
"name": "Unity.PlayerPrefsEditor.EditorResources",
"references": [],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: bf6f54031c06d954889037da1389c752
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

@ -0,0 +1,99 @@
fileFormatVersion: 2
guid: 058af12bb195cdc43a0f974953fc4afd
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 9
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
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

@ -0,0 +1,99 @@
fileFormatVersion: 2
guid: babe6cc749d43c2469c6cb12a7a9d344
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 9
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
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

@ -0,0 +1,86 @@
fileFormatVersion: 2
guid: 01600487ba432264983788be42b0b029
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
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
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 1
mipBias: -1
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 B

@ -0,0 +1,100 @@
fileFormatVersion: 2
guid: c78f517c9f87bdf4e814d0d96e740793
timeCreated: 1500327620
licenseType: Store
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

@ -0,0 +1,100 @@
fileFormatVersion: 2
guid: c94af9de33f2f524ca4141c5ea383090
timeCreated: 1500322442
licenseType: Store
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

@ -0,0 +1,100 @@
fileFormatVersion: 2
guid: d40b23b11d3b85145af46d2c1316e057
timeCreated: 1500327620
licenseType: Store
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

@ -0,0 +1,100 @@
fileFormatVersion: 2
guid: 7d9ae81a8b3252449820b277748395bc
timeCreated: 1500927179
licenseType: Store
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,122 @@
fileFormatVersion: 2
guid: 5d3ebd901d622c14a9653af004d172a0
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
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
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -0,0 +1,108 @@
fileFormatVersion: 2
guid: 3e86075fa207f0041b6111dbfaa3d66e
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
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
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -0,0 +1,108 @@
fileFormatVersion: 2
guid: 73059e24567e2e647bb1d8280f28bf43
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
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
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

@ -0,0 +1,106 @@
fileFormatVersion: 2
guid: cc312847c3bca82428ff672fea7385c7
timeCreated: 1502315347
licenseType: Store
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
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
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 1
mipBias: -1
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

@ -0,0 +1,86 @@
fileFormatVersion: 2
guid: ed8c91adb8fc54f41aaff0986b083281
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
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
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 1
mipBias: -1
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 7afdecdeaea3efc42b92ba335397568c
folderAsset: yes
timeCreated: 1496263422
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 2c61139fc58134242bb4b9e6d9fabdc0
folderAsset: yes
timeCreated: 1502815237
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,139 @@
using BgTools.Extensions;
using BgTools.Utils;
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace BgTools.Dialogs
{
public class TextFieldDialog : EditorWindow
{
[NonSerialized]
private string resultString = string.Empty;
[NonSerialized]
private Action<string> callback;
[NonSerialized]
private string description;
[NonSerialized]
private List<TextValidator> validatorList = new List<TextValidator>();
[NonSerialized]
private TextValidator errorValidator = null;
public static void OpenDialog(string title, string description, List<TextValidator> validatorList, Action<string> callback, EditorWindow targetWin = null)
{
TextFieldDialog window = ScriptableObject.CreateInstance<TextFieldDialog>();
window.name = "TextFieldDialog '" + title + "'";
window.titleContent = new GUIContent (title);
window.description = description;
window.callback = callback;
window.validatorList = validatorList;
window.position = new Rect(0, 0, 350, 140);
window.ShowUtility();
window.CenterOnWindow(targetWin);
window.Focus();
EditorWindow.FocusWindowIfItsOpen<TextFieldDialog>();
}
void OnGUI()
{
errorValidator = null;
Color defaultColor = GUI.contentColor;
GUILayout.Space(20);
EditorGUILayout.LabelField(description);
GUILayout.Space(20);
GUI.SetNextControlName(name+"_textInput");
resultString = EditorGUILayout.TextField(resultString, GUILayout.ExpandWidth(true));
// GUILayout.Space(20);
GUILayout.FlexibleSpace();
foreach(TextValidator val in validatorList)
{
if (!val.Validate(resultString))
{
errorValidator = val;
break;
}
}
bool lockOkButton = !(errorValidator != null && errorValidator.m_errorType == TextValidator.ErrorType.Error);
GUILayout.BeginHorizontal();
if(errorValidator != null)
{
switch (errorValidator.m_errorType)
{
case TextValidator.ErrorType.Info:
GUI.contentColor = Styles.Colors.Blue;
GUILayout.Box(new GUIContent(ImageManager.Info, errorValidator.m_failureMsg), Styles.icon);
break;
case TextValidator.ErrorType.Warning:
GUI.contentColor = Styles.Colors.Yellow;
GUILayout.Box(new GUIContent(ImageManager.Exclamation, errorValidator.m_failureMsg), Styles.icon);
break;
case TextValidator.ErrorType.Error:
GUI.contentColor = Styles.Colors.Red;
GUILayout.Box(new GUIContent(ImageManager.Exclamation, errorValidator.m_failureMsg), Styles.icon);
break;
}
GUI.contentColor = defaultColor;
}
GUILayout.FlexibleSpace();
if (GUILayout.Button("Cancel", GUILayout.Width(75.0f)))
this.Close();
GUI.enabled = lockOkButton;
if (GUILayout.Button("OK", GUILayout.Width(75.0f)))
{
callback(resultString);
Close();
}
GUI.enabled = true;
GUILayout.EndHorizontal();
GUILayout.Space(20);
// set focus only if element exist
try
{
EditorGUI.FocusTextInControl(name+"_textInput");
}
catch (MissingReferenceException)
{ }
if (Event.current != null && Event.current.isKey)
{
switch (Event.current.keyCode)
{
case KeyCode.Return:
if (lockOkButton)
{
callback(resultString);
Close();
}
break;
case KeyCode.Escape:
Close();
break;
}
}
}
}
}

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 380be3677d2e95144863ee00c051c1f2
timeCreated: 1500849296
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,64 @@
using System;
using System.Text.RegularExpressions;
namespace BgTools.Dialogs
{
public class TextValidator
{
public enum ErrorType
{
Invalid = -1,
Info = 0,
Warning = 1,
Error = 2
}
[NonSerialized]
public ErrorType m_errorType = ErrorType.Invalid;
[NonSerialized]
private string m_regEx = string.Empty;
[NonSerialized]
private Func<string, bool> m_validationFunction;
[NonSerialized]
public string m_failureMsg = string.Empty;
/// <summary>
/// Validator for TextFieldDialog based on regex.
/// </summary>
/// <param name="errorType">Categorie of the error.</param>
/// <param name="failureMsg">Message that described the reason why the validation fail.</param>
/// <param name="regEx">String with regular expression. It need to describe the valid state.</param>
public TextValidator(ErrorType errorType, string failureMsg, string regEx)
{
m_errorType = errorType;
m_failureMsg = failureMsg;
m_regEx = regEx;
}
/// <summary>
/// Validator for TextFieldDialog based on regex.
/// </summary>
/// <param name="errorType">Categorie of the error.</param>
/// <param name="failureMsg">Message that described the reason why the validation fail.</param>
/// <param name="validationFunction">Function that validate the input. Get the current input as string and need to return a bool. Nedd to return 'false' if the validation fails.</param>
public TextValidator(ErrorType errorType, string failureMsg, Func<string, bool> validationFunction)
{
m_errorType = errorType;
m_failureMsg = failureMsg;
m_validationFunction = validationFunction;
}
public bool Validate(string srcString)
{
if (m_regEx != string.Empty)
return Regex.IsMatch(srcString, m_regEx);
else if (m_validationFunction != null)
return m_validationFunction(srcString);
return false;
}
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4202eaaf18e2e43438f2f3632b252393
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 5c7bb3ee5362c0a40a707ade01e79972
folderAsset: yes
timeCreated: 1502876479
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,90 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace BgTools.Extensions
{
public static class Extensions
{
private static Type[] GetAllDerivedTypes(this AppDomain aAppDomain, Type aType)
{
var result = new List<Type>();
var assemblies = aAppDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
var types = assembly.GetTypes();
foreach (Type type in types)
{
if (type.IsSubclassOf(aType))
result.Add(type);
}
}
return result.ToArray();
}
public static Rect GetEditorMainWindowPos(EditorWindow relatedWin = null)
{
var containerWinType = AppDomain.CurrentDomain.GetAllDerivedTypes(typeof(ScriptableObject)).Where(t => t.Name == "ContainerWindow").FirstOrDefault();
if (containerWinType == null)
throw new MissingMemberException("Can't find internal type ContainerWindow. Maybe something has changed inside Unity");
var showModeField = containerWinType.GetField("m_ShowMode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var positionProperty = containerWinType.GetProperty("position", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
if (showModeField == null || positionProperty == null)
throw new MissingFieldException("Can't find internal fields 'm_ShowMode' or 'position'. Maybe something has changed inside Unity");
var windows = Resources.FindObjectsOfTypeAll(containerWinType);
foreach (var win in windows)
{
var showmode = (int)showModeField.GetValue(win);
// Given window
//if (relatedWin != null && relatedWin.GetInstanceID() == win.GetInstanceID())
//{
// var pos = (Rect)positionProperty.GetValue(win, null);
// return pos;
//}
// Main window
if (showmode == 4)
{
var pos = (Rect)positionProperty.GetValue(win, null);
return pos;
}
}
throw new NotSupportedException("Can't find internal main window. Maybe something has changed inside Unity");
}
/// <summary>
/// Center the EditorWindow in front of the MainUnityWindow (support multi screens).
/// Kept the currend window sizes.
/// </summary>
public static void CenterOnMainWindow(this EditorWindow window)
{
CenterOnWindow(window, null);
}
/// <summary>
/// Center the EditorWindow in front of the given EditorWindow (support multi screens).
/// Kept the currend window sizes.
/// </summary>
/// <param name="relatedWin">Referance window for the positioning.</param>
public static void CenterOnWindow(this EditorWindow window, EditorWindow relatedWin)
{
var main = GetEditorMainWindowPos(relatedWin);
var pos = window.position;
float w = (main.width - pos.width) * 0.5f;
float h = (main.height - pos.height) * 0.5f;
pos.x = main.x + w;
pos.y = main.y + h;
window.position = pos;
}
}
}

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 274db1862ad1a1b4c80a2ed6558e05ec
timeCreated: 1502876542
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: e93ef5c4e798b034bb024596113459cb
folderAsset: yes
timeCreated: 1505565882
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,36 @@
namespace BgTools.PlayerPrefsEditor
{
[System.Serializable]
public class PreferenceEntry
{
public enum PrefTypes
{
String = 0,
Int = 1,
Float = 2
}
public PrefTypes m_typeSelection;
public string m_key;
// Need diffrend ones for auto type selection of serilizedProerty
public string m_strValue;
public int m_intValue;
public float m_floatValue;
public string ValueAsString()
{
switch(m_typeSelection)
{
case PrefTypes.String:
return m_strValue;
case PrefTypes.Int:
return m_intValue.ToString();
case PrefTypes.Float:
return m_floatValue.ToString();
default:
return string.Empty;
}
}
}
}

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2ae9239fbddf12b4099b3cacc5301271
timeCreated: 1496684286
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,29 @@
using System.Collections.Generic;
using UnityEngine;
namespace BgTools.PlayerPrefsEditor
{
[System.Serializable]
public class PreferenceEntryHolder : ScriptableObject
{
public List<PreferenceEntry> userDefList;
public List<PreferenceEntry> unityDefList;
private void OnEnable()
{
hideFlags = HideFlags.DontSave;
if (userDefList == null)
userDefList = new List<PreferenceEntry>();
if (unityDefList == null)
unityDefList = new List<PreferenceEntry>();
}
public void ClearLists()
{
if (userDefList != null)
userDefList.Clear();
if (unityDefList != null)
unityDefList.Clear();
}
}
}

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d5d94a5263d6af0478dde8fb08a3dcb7
timeCreated: 1500316993
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,272 @@
using System;
using System.Linq;
#if UNITY_EDITOR_WIN
using Microsoft.Win32;
using System.Text;
#elif UNITY_EDITOR_OSX
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
#elif UNITY_EDITOR_LINUX
using System.IO;
using System.Xml;
using System.Xml.Linq;
#endif
namespace BgTools.PlayerPrefsEditor
{
public abstract class PreferanceStorageAccessor
{
protected string prefPath;
protected string[] cachedData = new string[0];
protected abstract void FetchKeysFromSystem();
protected PreferanceStorageAccessor(string pathToPrefs)
{
prefPath = pathToPrefs;
}
public string[] GetKeys(bool reloadData = true)
{
if (reloadData || cachedData.Length == 0)
{
FetchKeysFromSystem();
}
return cachedData;
}
public Action PrefEntryChangedDelegate;
protected bool ignoreNextChange = false;
public void IgnoreNextChange()
{
ignoreNextChange = true;
}
protected virtual void OnPrefEntryChanged()
{
if (ignoreNextChange)
{
ignoreNextChange = false;
return;
}
PrefEntryChangedDelegate();
}
public Action StartLoadingDelegate;
public Action StopLoadingDelegate;
public abstract void StartMonitoring();
public abstract void StopMonitoring();
public abstract bool IsMonitoring();
}
#if UNITY_EDITOR_WIN
public class WindowsPrefStorage : PreferanceStorageAccessor
{
RegistryMonitor monitor;
public WindowsPrefStorage(string pathToPrefs) : base(pathToPrefs)
{
monitor = new RegistryMonitor(RegistryHive.CurrentUser, prefPath);
monitor.RegChanged += new EventHandler(OnRegChanged);
}
private void OnRegChanged(object sender, EventArgs e)
{
OnPrefEntryChanged();
}
protected override void FetchKeysFromSystem()
{
cachedData = new string[0];
using (RegistryKey rootKey = Registry.CurrentUser.OpenSubKey(prefPath))
{
if (rootKey != null)
{
cachedData = rootKey.GetValueNames();
rootKey.Close();
}
}
// Clean <key>_h3320113488 nameing
cachedData = cachedData.Select((key) => { return key.Substring(0, key.LastIndexOf("_h", StringComparison.Ordinal)); }).ToArray();
EncodeAnsiInPlace();
}
public override void StartMonitoring()
{
monitor.Start();
}
public override void StopMonitoring()
{
monitor.Stop();
}
public override bool IsMonitoring()
{
return monitor.IsMonitoring;
}
private void EncodeAnsiInPlace()
{
Encoding utf8 = Encoding.UTF8;
Encoding ansi = Encoding.GetEncoding(1252);
for (int i = 0; i < cachedData.Length; i++)
{
cachedData[i] = utf8.GetString(ansi.GetBytes(cachedData[i]));
}
}
}
#elif UNITY_EDITOR_LINUX
public class LinuxPrefStorage : PreferanceStorageAccessor
{
FileSystemWatcher fileWatcher;
public LinuxPrefStorage(string pathToPrefs) : base(Path.Combine(Environment.GetEnvironmentVariable("HOME"), pathToPrefs))
{
fileWatcher = new FileSystemWatcher();
fileWatcher.Path = Path.GetDirectoryName(prefPath);
fileWatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite;
fileWatcher.Filter = "prefs";
fileWatcher.Changed += OnWatchedFileChanged;
}
protected override void FetchKeysFromSystem()
{
cachedData = new string[0];
if (File.Exists(prefPath))
{
XmlReaderSettings settings = new XmlReaderSettings();
XmlReader reader = XmlReader.Create(prefPath, settings);
XDocument doc = XDocument.Load(reader);
cachedData = doc.Element("unity_prefs").Elements().Select((e) => e.Attribute("name").Value).ToArray();
}
}
public override void StartMonitoring()
{
fileWatcher.EnableRaisingEvents = true;
}
public override void StopMonitoring()
{
fileWatcher.EnableRaisingEvents = false;
}
public override bool IsMonitoring()
{
return fileWatcher.EnableRaisingEvents;
}
private void OnWatchedFileChanged(object source, FileSystemEventArgs e)
{
OnPrefEntryChanged();
}
}
#elif UNITY_EDITOR_OSX
public class MacPrefStorage : PreferanceStorageAccessor
{
private FileSystemWatcher fileWatcher;
private DirectoryInfo prefsDirInfo;
private String prefsFileNameWithoutExtension;
public MacPrefStorage(string pathToPrefs) : base(Path.Combine(Environment.GetEnvironmentVariable("HOME"), pathToPrefs))
{
prefsDirInfo = new DirectoryInfo(Path.GetDirectoryName(prefPath));
prefsFileNameWithoutExtension = Path.GetFileNameWithoutExtension(prefPath);
fileWatcher = new FileSystemWatcher();
fileWatcher.Path = Path.GetDirectoryName(prefPath);
fileWatcher.NotifyFilter = NotifyFilters.LastWrite;
fileWatcher.Filter = Path.GetFileName(prefPath);
// MAC delete the old and create a new file instead of updating
fileWatcher.Created += OnWatchedFileChanged;
}
protected override void FetchKeysFromSystem()
{
// Workaround to avoid incomplete tmp phase from MAC OS
foreach (FileInfo info in prefsDirInfo.GetFiles())
{
// Check if tmp PlayerPrefs file exist
if (info.FullName.Contains(prefsFileNameWithoutExtension) && !info.FullName.EndsWith(".plist"))
{
StartLoadingDelegate();
return;
}
}
StopLoadingDelegate();
cachedData = new string[0];
if (File.Exists(prefPath))
{
string fixedPrefsPath = prefPath.Replace("\"", "\\\"").Replace("'", "\\'").Replace("`", "\\`");
var cmdStr = string.Format(@"-p '{0}'", fixedPrefsPath);
string stdOut = String.Empty;
string errOut = String.Empty;
var process = new System.Diagnostics.Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "plutil";
process.StartInfo.Arguments = cmdStr;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.OutputDataReceived += new DataReceivedEventHandler((sender, evt) => { stdOut += evt.Data + "\n"; });
process.ErrorDataReceived += new DataReceivedEventHandler((sender, evt) => { errOut += evt.Data + "\n"; });
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
MatchCollection matches = Regex.Matches(stdOut, @"(?: "")(.*)(?:"" =>.*)");
cachedData = matches.Cast<Match>().Select((e) => e.Groups[1].Value).ToArray();
}
}
public override void StartMonitoring()
{
fileWatcher.EnableRaisingEvents = true;
}
public override void StopMonitoring()
{
fileWatcher.EnableRaisingEvents = false;
}
public override bool IsMonitoring()
{
return fileWatcher.EnableRaisingEvents;
}
private void OnWatchedFileChanged(object source, FileSystemEventArgs e)
{
OnPrefEntryChanged();
}
}
#endif
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f54241e622579a145a495df929a9330a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,700 @@
using UnityEngine;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEditorInternal;
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using BgTools.Utils;
using BgTools.Dialogs;
#if (UNITY_EDITOR_LINUX || UNITY_EDITOR_OSX)
using System.Text;
using System.Globalization;
#endif
namespace BgTools.PlayerPrefsEditor
{
public class PreferencesEditorWindow : EditorWindow
{
#region ErrorValues
private readonly int ERROR_VALUE_INT = int.MinValue;
private readonly string ERROR_VALUE_STR = "<bgTool_error_24072017>";
#endregion //ErrorValues
private enum PreferencesEntrySortOrder
{
None = 0,
Asscending = 1,
Descending = 2
}
private static string pathToPrefs = String.Empty;
private static string platformPathPrefix = @"~";
private string[] userDef;
private string[] unityDef;
private bool showSystemGroup = false;
private PreferencesEntrySortOrder sortOrder = PreferencesEntrySortOrder.None;
private SerializedObject serializedObject;
private ReorderableList userDefList;
private ReorderableList unityDefList;
private SerializedProperty[] userDefListCache = new SerializedProperty[0];
private PreferenceEntryHolder prefEntryHolder;
private Vector2 scrollPos;
private float relSpliterPos;
private bool moveSplitterPos = false;
private PreferanceStorageAccessor entryAccessor;
private MySearchField searchfield;
private string searchTxt;
private int loadingSpinnerFrame;
private bool updateView = false;
private bool monitoring = false;
private bool showLoadingIndicatorOverlay = false;
private readonly List<TextValidator> prefKeyValidatorList = new List<TextValidator>()
{
new TextValidator(TextValidator.ErrorType.Error, @"Invalid character detected. Only letters, numbers, space and ,.;:<>_|!§$%&/()=?*+~#-]+$ are allowed", @"(^$)|(^[a-zA-Z0-9 ,.;:<>_|!§$%&/()=?*+~#-]+$)"),
new TextValidator(TextValidator.ErrorType.Warning, @"The given key already exist. The existing entry would be overwritten!", (key) => { return !PlayerPrefs.HasKey(key); })
};
#if UNITY_EDITOR_LINUX
private readonly char[] invalidFilenameChars = { '"', '\\', '*', '/', ':', '<', '>', '?', '|' };
#elif UNITY_EDITOR_OSX
private readonly char[] invalidFilenameChars = { '$', '%', '&', '\\', '/', ':', '<', '>', '|', '~' };
#endif
[MenuItem("Tools/BG Tools/PlayerPrefs Editor", false, 1)]
static void ShowWindow()
{
PreferencesEditorWindow window = EditorWindow.GetWindow<PreferencesEditorWindow>(false, "Prefs Editor");
window.minSize = new Vector2(270.0f, 300.0f);
window.name = "Prefs Editor";
//window.titleContent = EditorGUIUtility.IconContent("SettingsIcon"); // Icon
window.Show();
}
private void OnEnable()
{
#if UNITY_EDITOR_WIN
pathToPrefs = @"SOFTWARE\Unity\UnityEditor\" + PlayerSettings.companyName + @"\" + PlayerSettings.productName;
platformPathPrefix = @"<CurrentUser>";
entryAccessor = new WindowsPrefStorage(pathToPrefs);
#elif UNITY_EDITOR_OSX
pathToPrefs = @"Library/Preferences/unity." + MakeValidFileName(PlayerSettings.companyName) + "." + MakeValidFileName(PlayerSettings.productName) + ".plist";
entryAccessor = new MacPrefStorage(pathToPrefs);
entryAccessor.StartLoadingDelegate = () => { showLoadingIndicatorOverlay = true; };
entryAccessor.StopLoadingDelegate = () => { showLoadingIndicatorOverlay = false; };
#elif UNITY_EDITOR_LINUX
pathToPrefs = @".config/unity3d/" + MakeValidFileName(PlayerSettings.companyName) + "/" + MakeValidFileName(PlayerSettings.productName) + "/prefs";
entryAccessor = new LinuxPrefStorage(pathToPrefs);
#endif
entryAccessor.PrefEntryChangedDelegate = () => { updateView = true; };
monitoring = EditorPrefs.GetBool("BGTools.PlayerPrefsEditor.WatchingForChanges", true);
if(monitoring)
entryAccessor.StartMonitoring();
sortOrder = (PreferencesEntrySortOrder) EditorPrefs.GetInt("BGTools.PlayerPrefsEditor.SortOrder", 0);
searchfield = new MySearchField();
searchfield.DropdownSelectionDelegate = () => { PrepareData(); };
// Fix for serialisation issue of static fields
if (userDefList == null)
{
InitReorderedList();
PrepareData();
}
}
// Handel view updates for monitored changes
// Necessary to avoid main thread access issue
private void Update()
{
if (showLoadingIndicatorOverlay)
{
loadingSpinnerFrame = (int)Mathf.Repeat(Time.realtimeSinceStartup * 10, 11.99f);
PrepareData();
Repaint();
}
if (updateView)
{
updateView = false;
PrepareData();
Repaint();
}
}
private void OnDisable()
{
entryAccessor.StopMonitoring();
}
private void InitReorderedList()
{
if (prefEntryHolder == null)
{
var tmp = Resources.FindObjectsOfTypeAll<PreferenceEntryHolder>();
if (tmp.Length > 0)
{
prefEntryHolder = tmp[0];
}
else
{
prefEntryHolder = ScriptableObject.CreateInstance<PreferenceEntryHolder>();
}
}
if (serializedObject == null)
{
serializedObject = new SerializedObject(prefEntryHolder);
}
userDefList = new ReorderableList(serializedObject, serializedObject.FindProperty("userDefList"), false, true, true, true);
unityDefList = new ReorderableList(serializedObject, serializedObject.FindProperty("unityDefList"), false, true, false, false);
relSpliterPos = EditorPrefs.GetFloat("BGTools.PlayerPrefsEditor.RelativeSpliterPosition", 100 / position.width);
userDefList.drawHeaderCallback = (Rect rect) =>
{
EditorGUI.LabelField(rect, "User defined");
};
userDefList.drawElementBackgroundCallback = OnDrawElementBackgroundCallback;
userDefList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
{
SerializedProperty element = GetUserDefListElementAtIndex(index, userDefList.serializedProperty);
SerializedProperty key = element.FindPropertyRelative("m_key");
SerializedProperty type = element.FindPropertyRelative("m_typeSelection");
SerializedProperty value;
// Load only necessary type
switch ((PreferenceEntry.PrefTypes)type.enumValueIndex)
{
case PreferenceEntry.PrefTypes.Float:
value = element.FindPropertyRelative("m_floatValue");
break;
case PreferenceEntry.PrefTypes.Int:
value = element.FindPropertyRelative("m_intValue");
break;
case PreferenceEntry.PrefTypes.String:
value = element.FindPropertyRelative("m_strValue");
break;
default:
value = element.FindPropertyRelative("This should never happen");
break;
}
float spliterPos = relSpliterPos * rect.width;
rect.y += 2;
EditorGUI.BeginChangeCheck();
string prefKeyName = key.stringValue;
EditorGUI.LabelField(new Rect(rect.x, rect.y, spliterPos - 1, EditorGUIUtility.singleLineHeight), new GUIContent(prefKeyName, prefKeyName));
GUI.enabled = false;
EditorGUI.EnumPopup(new Rect(rect.x + spliterPos + 1, rect.y, 60, EditorGUIUtility.singleLineHeight), (PreferenceEntry.PrefTypes)type.enumValueIndex);
GUI.enabled = !showLoadingIndicatorOverlay;
switch ((PreferenceEntry.PrefTypes)type.enumValueIndex)
{
case PreferenceEntry.PrefTypes.Float:
EditorGUI.DelayedFloatField(new Rect(rect.x + spliterPos + 62, rect.y, rect.width - spliterPos - 60, EditorGUIUtility.singleLineHeight), value, GUIContent.none);
break;
case PreferenceEntry.PrefTypes.Int:
EditorGUI.DelayedIntField(new Rect(rect.x + spliterPos + 62, rect.y, rect.width - spliterPos - 60, EditorGUIUtility.singleLineHeight), value, GUIContent.none);
break;
case PreferenceEntry.PrefTypes.String:
EditorGUI.DelayedTextField(new Rect(rect.x + spliterPos + 62, rect.y, rect.width - spliterPos - 60, EditorGUIUtility.singleLineHeight), value, GUIContent.none);
break;
}
if (EditorGUI.EndChangeCheck())
{
entryAccessor.IgnoreNextChange();
switch ((PreferenceEntry.PrefTypes)type.enumValueIndex)
{
case PreferenceEntry.PrefTypes.Float:
PlayerPrefs.SetFloat(key.stringValue, value.floatValue);
break;
case PreferenceEntry.PrefTypes.Int:
PlayerPrefs.SetInt(key.stringValue, value.intValue);
break;
case PreferenceEntry.PrefTypes.String:
PlayerPrefs.SetString(key.stringValue, value.stringValue);
break;
}
PlayerPrefs.Save();
}
};
userDefList.onRemoveCallback = (ReorderableList l) =>
{
userDefList.ReleaseKeyboardFocus();
unityDefList.ReleaseKeyboardFocus();
string prefKey = l.serializedProperty.GetArrayElementAtIndex(l.index).FindPropertyRelative("m_key").stringValue;
if (EditorUtility.DisplayDialog("Warning!", $"Are you sure you want to delete this entry from PlayerPrefs?\n\nEntry: {prefKey}", "Yes", "No"))
{
entryAccessor.IgnoreNextChange();
PlayerPrefs.DeleteKey(prefKey);
PlayerPrefs.Save();
ReorderableList.defaultBehaviours.DoRemoveButton(l);
PrepareData();
GUIUtility.ExitGUI();
}
};
userDefList.onAddDropdownCallback = (Rect buttonRect, ReorderableList l) =>
{
var menu = new GenericMenu();
foreach (PreferenceEntry.PrefTypes type in Enum.GetValues(typeof(PreferenceEntry.PrefTypes)))
{
menu.AddItem(new GUIContent(type.ToString()), false, () =>
{
TextFieldDialog.OpenDialog("Create new property", "Key for the new property:", prefKeyValidatorList, (key) => {
entryAccessor.IgnoreNextChange();
switch (type)
{
case PreferenceEntry.PrefTypes.Float:
PlayerPrefs.SetFloat(key, 0.0f);
break;
case PreferenceEntry.PrefTypes.Int:
PlayerPrefs.SetInt(key, 0);
break;
case PreferenceEntry.PrefTypes.String:
PlayerPrefs.SetString(key, string.Empty);
break;
}
PlayerPrefs.Save();
PrepareData();
Focus();
}, this);
});
}
menu.ShowAsContext();
};
unityDefList.drawElementBackgroundCallback = OnDrawElementBackgroundCallback;
unityDefList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
{
var element = unityDefList.serializedProperty.GetArrayElementAtIndex(index);
SerializedProperty key = element.FindPropertyRelative("m_key");
SerializedProperty type = element.FindPropertyRelative("m_typeSelection");
SerializedProperty value;
// Load only necessary type
switch ((PreferenceEntry.PrefTypes)type.enumValueIndex)
{
case PreferenceEntry.PrefTypes.Float:
value = element.FindPropertyRelative("m_floatValue");
break;
case PreferenceEntry.PrefTypes.Int:
value = element.FindPropertyRelative("m_intValue");
break;
case PreferenceEntry.PrefTypes.String:
value = element.FindPropertyRelative("m_strValue");
break;
default:
value = element.FindPropertyRelative("This should never happen");
break;
}
float spliterPos = relSpliterPos * rect.width;
rect.y += 2;
GUI.enabled = false;
string prefKeyName = key.stringValue;
EditorGUI.LabelField(new Rect(rect.x, rect.y, spliterPos - 1, EditorGUIUtility.singleLineHeight), new GUIContent(prefKeyName, prefKeyName));
EditorGUI.EnumPopup(new Rect(rect.x + spliterPos + 1, rect.y, 60, EditorGUIUtility.singleLineHeight), (PreferenceEntry.PrefTypes)type.enumValueIndex);
switch ((PreferenceEntry.PrefTypes)type.enumValueIndex)
{
case PreferenceEntry.PrefTypes.Float:
EditorGUI.DelayedFloatField(new Rect(rect.x + spliterPos + 62, rect.y, rect.width - spliterPos - 60, EditorGUIUtility.singleLineHeight), value, GUIContent.none);
break;
case PreferenceEntry.PrefTypes.Int:
EditorGUI.DelayedIntField(new Rect(rect.x + spliterPos + 62, rect.y, rect.width - spliterPos - 60, EditorGUIUtility.singleLineHeight), value, GUIContent.none);
break;
case PreferenceEntry.PrefTypes.String:
EditorGUI.DelayedTextField(new Rect(rect.x + spliterPos + 62, rect.y, rect.width - spliterPos - 60, EditorGUIUtility.singleLineHeight), value, GUIContent.none);
break;
}
GUI.enabled = !showLoadingIndicatorOverlay;
};
unityDefList.drawHeaderCallback = (Rect rect) =>
{
EditorGUI.LabelField(rect, "Unity defined");
};
}
private void OnDrawElementBackgroundCallback(Rect rect, int index, bool isActive, bool isFocused)
{
if (Event.current.type == EventType.Repaint)
{
ReorderableList.defaultBehaviours.elementBackground.Draw(rect, false, isActive, isActive, isFocused);
}
Rect spliterRect = new Rect(rect.x + relSpliterPos * rect.width, rect.y, 2, rect.height);
EditorGUIUtility.AddCursorRect(spliterRect, MouseCursor.ResizeHorizontal);
if (Event.current.type == EventType.MouseDown && spliterRect.Contains(Event.current.mousePosition))
{
moveSplitterPos = true;
}
if(moveSplitterPos)
{
if (Event.current.mousePosition.x > 100 && Event.current.mousePosition.x<rect.width - 120)
{
relSpliterPos = Event.current.mousePosition.x / rect.width;
Repaint();
}
}
if (Event.current.type == EventType.MouseUp)
{
moveSplitterPos = false;
EditorPrefs.SetFloat("BGTools.PlayerPrefsEditor.RelativeSpliterPosition", relSpliterPos);
}
}
void OnGUI()
{
// Need to catch 'Stack empty' error on linux
try
{
if (showLoadingIndicatorOverlay)
{
GUI.enabled = false;
}
Color defaultColor = GUI.contentColor;
if (!EditorGUIUtility.isProSkin)
{
GUI.contentColor = Styles.Colors.DarkGray;
}
GUILayout.BeginVertical();
GUILayout.BeginHorizontal(EditorStyles.toolbar);
EditorGUI.BeginChangeCheck();
searchTxt = searchfield.OnToolbarGUI(searchTxt);
if (EditorGUI.EndChangeCheck())
{
PrepareData(false);
}
GUILayout.FlexibleSpace();
EditorGUIUtility.SetIconSize(new Vector2(14.0f, 14.0f));
GUIContent sortOrderContent;
switch (sortOrder)
{
case PreferencesEntrySortOrder.Asscending:
sortOrderContent = new GUIContent(ImageManager.SortAsscending, "Ascending sorted");
break;
case PreferencesEntrySortOrder.Descending:
sortOrderContent = new GUIContent(ImageManager.SortDescending, "Descending sorted");
break;
case PreferencesEntrySortOrder.None:
default:
sortOrderContent = new GUIContent(ImageManager.SortDisabled, "Not sorted");
break;
}
if (GUILayout.Button(sortOrderContent, EditorStyles.toolbarButton))
{
sortOrder++;
if((int) sortOrder >= Enum.GetValues(typeof(PreferencesEntrySortOrder)).Length)
{
sortOrder = 0;
}
EditorPrefs.SetInt("BGTools.PlayerPrefsEditor.SortOrder", (int) sortOrder);
PrepareData(false);
}
GUIContent watcherContent = (entryAccessor.IsMonitoring()) ? new GUIContent(ImageManager.Watching, "Watching changes") : new GUIContent(ImageManager.NotWatching, "Not watching changes");
if (GUILayout.Button(watcherContent, EditorStyles.toolbarButton))
{
monitoring = !monitoring;
EditorPrefs.SetBool("BGTools.PlayerPrefsEditor.WatchingForChanges", monitoring);
if (monitoring)
entryAccessor.StartMonitoring();
else
entryAccessor.StopMonitoring();
Repaint();
}
if (GUILayout.Button(new GUIContent(ImageManager.Refresh, "Refresh"), EditorStyles.toolbarButton))
{
PlayerPrefs.Save();
PrepareData();
}
if (GUILayout.Button(new GUIContent(ImageManager.Trash, "Delete all"), EditorStyles.toolbarButton))
{
if (EditorUtility.DisplayDialog("Warning!", "Are you sure you want to delete ALL entries from PlayerPrefs?\n\nUse with caution! Unity defined keys are affected too.", "Yes", "No"))
{
PlayerPrefs.DeleteAll();
PrepareData();
GUIUtility.ExitGUI();
}
}
EditorGUIUtility.SetIconSize(new Vector2(0.0f, 0.0f));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Box(ImageManager.GetOsIcon(), Styles.icon);
GUILayout.TextField(platformPathPrefix + Path.DirectorySeparatorChar + pathToPrefs, GUILayout.MinWidth(200));
GUILayout.EndHorizontal();
scrollPos = GUILayout.BeginScrollView(scrollPos);
serializedObject.Update();
userDefList.DoLayoutList();
serializedObject.ApplyModifiedProperties();
GUILayout.FlexibleSpace();
showSystemGroup = EditorGUILayout.Foldout(showSystemGroup, new GUIContent("Show System"));
if (showSystemGroup)
{
unityDefList.DoLayoutList();
}
GUILayout.EndScrollView();
GUILayout.EndVertical();
GUI.enabled = true;
if (showLoadingIndicatorOverlay)
{
GUILayout.BeginArea(new Rect(position.size.x * 0.5f - 30, position.size.y * 0.5f - 25, 60, 50), GUI.skin.box);
GUILayout.FlexibleSpace();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Box(ImageManager.SpinWheelIcons[loadingSpinnerFrame], Styles.icon);
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Label("Loading");
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.FlexibleSpace();
GUILayout.EndArea();
}
GUI.contentColor = defaultColor;
}
catch (InvalidOperationException)
{ }
}
private void PrepareData(bool reloadKeys = true)
{
prefEntryHolder.ClearLists();
LoadKeys(out userDef, out unityDef, reloadKeys);
CreatePrefEntries(userDef, ref prefEntryHolder.userDefList);
CreatePrefEntries(unityDef, ref prefEntryHolder.unityDefList);
// Clear cache
userDefListCache = new SerializedProperty[prefEntryHolder.userDefList.Count];
}
private void CreatePrefEntries(string[] keySource, ref List<PreferenceEntry> listDest)
{
if (!string.IsNullOrEmpty(searchTxt) && searchfield.SearchMode == MySearchField.SearchModePreferencesEditorWindow.Key)
{
keySource = keySource.Where((keyEntry) => keyEntry.ToLower().Contains(searchTxt.ToLower())).ToArray();
}
foreach (string key in keySource)
{
var entry = new PreferenceEntry();
entry.m_key = key;
string s = PlayerPrefs.GetString(key, ERROR_VALUE_STR);
if (s != ERROR_VALUE_STR)
{
entry.m_strValue = s;
entry.m_typeSelection = PreferenceEntry.PrefTypes.String;
listDest.Add(entry);
continue;
}
float f = PlayerPrefs.GetFloat(key, float.NaN);
if (!float.IsNaN(f))
{
entry.m_floatValue = f;
entry.m_typeSelection = PreferenceEntry.PrefTypes.Float;
listDest.Add(entry);
continue;
}
int i = PlayerPrefs.GetInt(key, ERROR_VALUE_INT);
if (i != ERROR_VALUE_INT)
{
entry.m_intValue = i;
entry.m_typeSelection = PreferenceEntry.PrefTypes.Int;
listDest.Add(entry);
continue;
}
}
if (!string.IsNullOrEmpty(searchTxt) && searchfield.SearchMode == MySearchField.SearchModePreferencesEditorWindow.Value)
{
listDest = listDest.Where((preferenceEntry) => preferenceEntry.ValueAsString().ToLower().Contains(searchTxt.ToLower())).ToList<PreferenceEntry>();
}
switch(sortOrder)
{
case PreferencesEntrySortOrder.Asscending:
listDest.Sort((PreferenceEntry x, PreferenceEntry y) => { return x.m_key.CompareTo(y.m_key); });
break;
case PreferencesEntrySortOrder.Descending:
listDest.Sort((PreferenceEntry x, PreferenceEntry y) => { return y.m_key.CompareTo(x.m_key); });
break;
}
}
private void LoadKeys(out string[] userDef, out string[] unityDef, bool reloadKeys)
{
string[] keys = entryAccessor.GetKeys(reloadKeys);
//keys.ToList().ForEach( e => { Debug.Log(e); } );
// Seperate keys int unity defined and user defined
Dictionary<bool, List<string>> groups = keys
.GroupBy( (key) => key.StartsWith("unity.") || key.StartsWith("UnityGraphicsQuality") )
.ToDictionary( (g) => g.Key, (g) => g.ToList() );
unityDef = (groups.ContainsKey(true)) ? groups[true].ToArray() : new string[0];
userDef = (groups.ContainsKey(false)) ? groups[false].ToArray() : new string[0];
}
private SerializedProperty GetUserDefListElementAtIndex(int index, SerializedProperty ListProperty)
{
UnityEngine.Assertions.Assert.IsTrue(ListProperty.isArray, "Given 'ListProperts' is not type of array");
if (userDefListCache[index] == null)
{
userDefListCache[index] = ListProperty.GetArrayElementAtIndex(index);
}
return userDefListCache[index];
}
#if (UNITY_EDITOR_LINUX || UNITY_EDITOR_OSX)
private string MakeValidFileName(string unsafeFileName)
{
string normalizedFileName = unsafeFileName.Trim().Normalize(NormalizationForm.FormD);
StringBuilder stringBuilder = new StringBuilder();
// We need to use a TextElementEmumerator in order to support UTF16 characters that may take up more than one char(case 1169358)
TextElementEnumerator charEnum = StringInfo.GetTextElementEnumerator(normalizedFileName);
while (charEnum.MoveNext())
{
string c = charEnum.GetTextElement();
if (c.Length == 1 && invalidFilenameChars.Contains(c[0]))
{
stringBuilder.Append('_');
continue;
}
UnicodeCategory unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c, 0);
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
stringBuilder.Append(c);
}
return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}
#endif
}
}
public class MySearchField : SearchField
{
public enum SearchModePreferencesEditorWindow { Key, Value }
public SearchModePreferencesEditorWindow SearchMode { get; private set; }
public Action DropdownSelectionDelegate;
public new string OnGUI(
Rect rect,
string text,
GUIStyle style,
GUIStyle cancelButtonStyle,
GUIStyle emptyCancelButtonStyle)
{
style.padding.left = 17;
Rect ContextMenuRect = new Rect(rect.x, rect.y, 10, rect.height);
// Add interactive area
EditorGUIUtility.AddCursorRect(ContextMenuRect, MouseCursor.Text);
if (Event.current.type == EventType.MouseDown && ContextMenuRect.Contains(Event.current.mousePosition))
{
void OnDropdownSelection(object parameter)
{
SearchMode = (SearchModePreferencesEditorWindow) Enum.Parse(typeof(SearchModePreferencesEditorWindow), parameter.ToString());
DropdownSelectionDelegate();
}
GenericMenu menu = new GenericMenu();
foreach(SearchModePreferencesEditorWindow EnumIt in Enum.GetValues(typeof(SearchModePreferencesEditorWindow)))
{
String EnumName = Enum.GetName(typeof(SearchModePreferencesEditorWindow), EnumIt);
menu.AddItem(new GUIContent(EnumName), SearchMode == EnumIt, OnDropdownSelection, EnumName);
}
menu.DropDown(rect);
}
// Render original search field
String result = base.OnGUI(rect, text, style, cancelButtonStyle, emptyCancelButtonStyle);
// Render additional images
GUIStyle ContexMenuOverlayStyle = GUIStyle.none;
ContexMenuOverlayStyle.contentOffset = new Vector2(9, 5);
GUI.Box(new Rect(rect.x, rect.y, 5, 5), EditorGUIUtility.IconContent("d_ProfilerTimelineDigDownArrow@2x"), ContexMenuOverlayStyle);
if (!HasFocus() && String.IsNullOrEmpty(text))
{
GUI.enabled = false;
GUI.Label(new Rect(rect.x + 14, rect.y, 40, rect.height), Enum.GetName(typeof(SearchModePreferencesEditorWindow), SearchMode));
GUI.enabled = true;
}
ContexMenuOverlayStyle.contentOffset = new Vector2();
return result;
}
public new string OnToolbarGUI(string text, params GUILayoutOption[] options) => this.OnToolbarGUI(GUILayoutUtility.GetRect(29f, 200f, 18f, 18f, EditorStyles.toolbarSearchField, options), text);
public new string OnToolbarGUI(Rect rect, string text) => this.OnGUI(rect, text, EditorStyles.toolbarSearchField, EditorStyles.toolbarButton, EditorStyles.toolbarButton);
}

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 13c94fa190e7e6f4690cadc347a312aa
timeCreated: 1496263475
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,364 @@
/*
* Thanks to gr0ss for the inspiration.
*
* https://github.com/gr0ss/RegistryMonitor
*
* 11/08/2019
*/
using System;
using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace BgTools.PlayerPrefsEditor
{
public class RegistryMonitor : IDisposable
{
#region P/Invoke
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern int RegOpenKeyEx(IntPtr hKey, string subKey, uint options, int samDesired, out IntPtr phkResult);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int RegNotifyChangeKeyValue(IntPtr hKey, bool bWatchSubtree, RegChangeNotifyFilter dwNotifyFilter, IntPtr hEvent, bool fAsynchronous);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int RegCloseKey(IntPtr hKey);
private const int KEY_QUERY_VALUE = 0x0001;
private const int KEY_NOTIFY = 0x0010;
private const int STANDARD_RIGHTS_READ = 0x00020000;
private static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(unchecked((int)0x80000000));
private static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(unchecked((int)0x80000001));
private static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002));
private static readonly IntPtr HKEY_USERS = new IntPtr(unchecked((int)0x80000003));
private static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(unchecked((int)0x80000004));
private static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(unchecked((int)0x80000005));
private static readonly IntPtr HKEY_DYN_DATA = new IntPtr(unchecked((int)0x80000006));
#endregion
#region Event handling
/// <summary>
/// Occurs when the specified registry key has changed.
/// </summary>
public event EventHandler RegChanged;
/// <summary>
/// Raises the <see cref="RegChanged"/> event.
/// </summary>
/// <remarks>
/// <p>
/// <b>OnRegChanged</b> is called when the specified registry key has changed.
/// </p>
/// <note type="inheritinfo">
/// When overriding <see cref="OnRegChanged"/> in a derived class, be sure to call
/// the base class's <see cref="OnRegChanged"/> method.
/// </note>
/// </remarks>
protected virtual void OnRegChanged()
{
EventHandler handler = RegChanged;
if (handler != null)
handler(this, null);
}
/// <summary>
/// Occurs when the access to the registry fails.
/// </summary>
public event ErrorEventHandler Error;
/// <summary>
/// Raises the <see cref="Error"/> event.
/// </summary>
/// <param name="e">The <see cref="Exception"/> which occured while watching the registry.</param>
/// <remarks>
/// <p>
/// <b>OnError</b> is called when an exception occurs while watching the registry.
/// </p>
/// <note type="inheritinfo">
/// When overriding <see cref="OnError"/> in a derived class, be sure to call
/// the base class's <see cref="OnError"/> method.
/// </note>
/// </remarks>
protected virtual void OnError(Exception e)
{
ErrorEventHandler handler = Error;
if (handler != null)
handler(this, new ErrorEventArgs(e));
}
#endregion
#region Private member variables
private IntPtr _registryHive;
private string _registrySubName;
private object _threadLock = new object();
private Thread _thread;
private bool _disposed = false;
private ManualResetEvent _eventTerminate = new ManualResetEvent(false);
private RegChangeNotifyFilter _regFilter = RegChangeNotifyFilter.Key | RegChangeNotifyFilter.Attribute | RegChangeNotifyFilter.Value | RegChangeNotifyFilter.Security;
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="RegistryMonitor"/> class.
/// </summary>
/// <param name="registryKey">The registry key to monitor.</param>
public RegistryMonitor(RegistryKey registryKey)
{
InitRegistryKey(registryKey.Name);
}
/// <summary>
/// Initializes a new instance of the <see cref="RegistryMonitor"/> class.
/// </summary>
/// <param name="name">The name.</param>
public RegistryMonitor(string name)
{
if (name == null || name.Length == 0)
throw new ArgumentNullException("name");
InitRegistryKey(name);
}
/// <summary>
/// Initializes a new instance of the <see cref="RegistryMonitor"/> class.
/// </summary>
/// <param name="registryHive">The registry hive.</param>
/// <param name="subKey">The sub key.</param>
public RegistryMonitor(RegistryHive registryHive, string subKey)
{
InitRegistryKey(registryHive, subKey);
}
/// <summary>
/// Disposes this object.
/// </summary>
public void Dispose()
{
Stop();
_disposed = true;
GC.SuppressFinalize(this);
}
/// <summary>
/// Gets or sets the <see cref="RegChangeNotifyFilter">RegChangeNotifyFilter</see>.
/// </summary>
public RegChangeNotifyFilter RegChangeNotifyFilter
{
get { return _regFilter; }
set
{
lock (_threadLock)
{
if (IsMonitoring)
throw new InvalidOperationException("Monitoring thread is already running");
_regFilter = value;
}
}
}
#region Initialization
private void InitRegistryKey(RegistryHive hive, string name)
{
switch (hive)
{
case RegistryHive.ClassesRoot:
_registryHive = HKEY_CLASSES_ROOT;
break;
case RegistryHive.CurrentConfig:
_registryHive = HKEY_CURRENT_CONFIG;
break;
case RegistryHive.CurrentUser:
_registryHive = HKEY_CURRENT_USER;
break;
case RegistryHive.DynData:
_registryHive = HKEY_DYN_DATA;
break;
case RegistryHive.LocalMachine:
_registryHive = HKEY_LOCAL_MACHINE;
break;
case RegistryHive.PerformanceData:
_registryHive = HKEY_PERFORMANCE_DATA;
break;
case RegistryHive.Users:
_registryHive = HKEY_USERS;
break;
default:
throw new InvalidEnumArgumentException("hive", (int)hive, typeof(RegistryHive));
}
_registrySubName = name;
}
private void InitRegistryKey(string name)
{
string[] nameParts = name.Split('\\');
switch (nameParts[0])
{
case "HKEY_CLASSES_ROOT":
case "HKCR":
_registryHive = HKEY_CLASSES_ROOT;
break;
case "HKEY_CURRENT_USER":
case "HKCU":
_registryHive = HKEY_CURRENT_USER;
break;
case "HKEY_LOCAL_MACHINE":
case "HKLM":
_registryHive = HKEY_LOCAL_MACHINE;
break;
case "HKEY_USERS":
_registryHive = HKEY_USERS;
break;
case "HKEY_CURRENT_CONFIG":
_registryHive = HKEY_CURRENT_CONFIG;
break;
default:
_registryHive = IntPtr.Zero;
throw new ArgumentException("The registry hive '" + nameParts[0] + "' is not supported", "value");
}
_registrySubName = String.Join("\\", nameParts, 1, nameParts.Length - 1);
}
#endregion
/// <summary>
/// <b>true</b> if this <see cref="RegistryMonitor"/> object is currently monitoring;
/// otherwise, <b>false</b>.
/// </summary>
public bool IsMonitoring
{
get { return _thread != null; }
}
/// <summary>
/// Start monitoring.
/// </summary>
public void Start()
{
if (_disposed)
throw new ObjectDisposedException(null, "This instance is already disposed");
lock (_threadLock)
{
if (!IsMonitoring)
{
_eventTerminate.Reset();
_thread = new Thread(new ThreadStart(MonitorThread)) { IsBackground = true };
_thread.Start();
}
}
}
/// <summary>
/// Stops the monitoring thread.
/// </summary>
public void Stop()
{
if (_disposed)
throw new ObjectDisposedException(null, "This instance is already disposed");
lock (_threadLock)
{
Thread thread = _thread;
if (thread != null)
{
_eventTerminate.Set();
thread.Join();
}
}
}
private void MonitorThread()
{
try
{
ThreadLoop();
}
catch (Exception e)
{
OnError(e);
}
_thread = null;
}
private void ThreadLoop()
{
IntPtr registryKey;
int result = RegOpenKeyEx(_registryHive, _registrySubName, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_NOTIFY, out registryKey);
if (result != 0)
{
throw new Win32Exception(result);
}
try
{
AutoResetEvent _eventNotify = new AutoResetEvent(false);
WaitHandle[] waitHandles = new WaitHandle[] { _eventNotify, _eventTerminate };
while (!_eventTerminate.WaitOne(0, true))
{
result = RegNotifyChangeKeyValue(registryKey, true, _regFilter, _eventNotify.SafeWaitHandle.DangerousGetHandle(), true);
if (result != 0)
{
throw new Win32Exception(result);
}
if (WaitHandle.WaitAny(waitHandles) == 0)
{
OnRegChanged();
}
}
}
finally
{
if (registryKey != IntPtr.Zero)
{
RegCloseKey(registryKey);
}
}
}
}
/// <summary>
/// Filter for notifications reported by <see cref="RegistryMonitor"/>.
/// </summary>
[Flags]
public enum RegChangeNotifyFilter
{
/// <summary>Notify the caller if a subkey is added or deleted.</summary>
Key = 1,
/// <summary>Notify the caller of changes to the attributes of the key,
/// such as the security descriptor information.</summary>
Attribute = 2,
/// <summary>Notify the caller of changes to a value of the key. This can
/// include adding or deleting a value, or changing an existing value.</summary>
Value = 4,
/// <summary>Notify the caller of changes to the security descriptor
/// of the key.</summary>
Security = 8,
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9c38f17e357d98d4296b689ae716240b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,109 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace BgTools.Utils
{
public class Styles
{
#region Colors
public class Colors {
public static Color DarkGray = new Color(0.09f, 0.09f, 0.09f);
public static Color LightGray = new Color(0.65f, 0.65f, 0.65f);
public static Color Red = new Color(1.00f, 0.00f, 0.00f);
public static Color Yellow = new Color(1.00f, 1.00f, 0.00f);
public static Color Blue = new Color(0.00f, 0.63f, 0.99f);
}
#endregion // Colors
#region Texture manager
static Dictionary<long, Texture2D> mTextures = new Dictionary<long, Texture2D>();
public static Texture2D GetTexture(long pColorRGBA)
{
if (mTextures.ContainsKey(pColorRGBA) && mTextures[pColorRGBA] != null)
return mTextures[pColorRGBA];
Color32 c = GetColor(pColorRGBA);
var texture = new Texture2D(4, 4);
for (int x = 0; x < 4; x++)
for (int y = 0; y < 4; y++)
texture.SetPixel(x, y, c);
texture.Apply();
texture.Compress(true);
mTextures[pColorRGBA] = texture;
return texture;
}
private static Color32 GetColor(long pColorRGBA)
{
byte r = (byte)((pColorRGBA & 0xff000000) >> 24);
byte g = (byte)((pColorRGBA & 0xff0000) >> 16);
byte b = (byte)((pColorRGBA & 0xff00) >> 8);
byte a = (byte)((pColorRGBA & 0xff));
Color32 c = new Color32(r, g, b, a);
return c;
}
#endregion Texture manager
static GUIStyle mHSeparator;
private static GUIStyle hSeparator
{
get
{
if (mHSeparator == null)
{
mHSeparator = new GUIStyle();
mHSeparator.alignment = TextAnchor.MiddleCenter;
mHSeparator.stretchWidth = true;
mHSeparator.fixedHeight = 1;
mHSeparator.margin = new RectOffset(20, 20, 5, 5);
mHSeparator.normal.background = (EditorGUIUtility.isProSkin) ? GetTexture(0xb5b5b5ff) : GetTexture(0x000000ff);
}
return mHSeparator;
}
}
public static void HorizontalSeparator()
{
GUILayout.Label("", hSeparator);
}
static GUIStyle Icon;
public static GUIStyle icon
{
get
{
if (Icon == null)
{
Icon = new GUIStyle();
Icon.fixedWidth = 15.0f;
Icon.fixedHeight = 15.0f;
Icon.margin = new RectOffset(2, 2, 2, 2);
}
return Icon;
}
}
static GUIStyle MiniButton;
public static GUIStyle miniButton
{
get
{
if (MiniButton == null)
{
MiniButton = new GUIStyle(GUI.skin.button);
MiniButton.fixedWidth = 15.0f;
MiniButton.fixedHeight = 15.0f;
MiniButton.margin = new RectOffset(2, 2, 2, 2);
MiniButton.padding = new RectOffset(2, 2, 2, 2);
}
return MiniButton;
}
}
}
}

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: be53f59c705f7434a9d6581d0746990f
timeCreated: 1496670894
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,16 @@
{
"name": "Unity.PlayerPrefsEditor.Editor",
"references": [
"Unity.PlayerPrefsEditor.EditorResources"
],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 516df2812c38a7348b10d202b71bf483
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,71 @@
# PlayerPrefs Editor for Unity 3D
[![Minimal unity editor version](https://img.shields.io/badge/UnityEditor-2019.4%20or%20later-blue.svg)](https://unity3d.com/de/get-unity/download/archive)
[![CI](https://github.com/Dysman/bgTools-playerPrefsEditor/workflows/CI/badge.svg)](https://github.com/Dysman/bgTools-playerPrefsEditor/actions)&nbsp;&nbsp;
[![Release](https://img.shields.io/github/v/release/Dysman/bgTools-playerPrefsEditor?include_prereleases&label=Release)](https://github.com/Dysman/bgTools-playerPrefsEditor/releases)
[![GitHub package.json version (branch)](https://img.shields.io/github/package-json/v/dysman/bgTools-playerPrefsEditor/upm?label=GitURL-UPM)](https://github.com/Dysman/bgTools-playerPrefsEditor/tree/upm)
[![openupm](https://img.shields.io/npm/v/com.bgtools.playerprefseditor?label=OpenUPM&registry_uri=https://package.openupm.com)](https://openupm.com/packages/com.bgtools.playerprefseditor)
[![AssetStore](https://img.shields.io/badge/dynamic/xml?url=http://u3d.as/1RLa&label=UnityAssetStore&query=//*[contains(@class,%20%27product-version%27)]/div[2]&prefix=v)](http://u3d.as/1RLa)
[![Flattr this git repo](https://img.shields.io/badge/_-Flattr-green?logo=flattr&style=flat)](https://flattr.com/@dysman)&nbsp;
[![Buy me a coffee](https://img.shields.io/badge/-Buy%20Me%20A%20Coffee-yellow?logo=BuyMeACoffee&style=flat&logoColor=white)](https://www.buymeacoffee.com/dysman)
[<img align="right" src="https://img.shields.io/discord/431522155814191116?logo=Discord&logoColor=white&style=flat&label=Discord&labelColor=5865F2">](https://discord.gg/8rcPZrD)
Tool extension for the Unity Editor that enables easy access to the player preferences over a simple UI. Allows to view, add, remove and modify entries on the development machine.
![Preference editor window](https://www.bgranzow.de/downloads/PlayerPrefsEditorV1_2_0.png)
## Features
* Add, remove and edit PlayerPrefs
* Intuitive visual editor
* Works with standard Unity PlayerPrefs
* Monitors changes from code
* Supports all editors (Windows, Linux, MacOS)
* Lightweight dockable for full integration in your workflow
* Supports both skins (Personal, Professional)
## Requirements
Unity Version: 2019.4 (LTS) or higher
Editor Version: Windows, MacOS, Linux
## Installation
The plugin provides *manual* and *UPM* installation.
Additionally it's available on the [Unity Asset Store](http://u3d.as/1RLa).
### Manual
Place the PlayerPrefsEditor folder somewhere in your project. It's not relevant where it's located, the plugin will find all of its files by itself.
### Unity Package Manager (UPM)
**Via Git URL**
Through the Unity Plugin Manager it's possible to install the plugin direct from this git repository.
The UPM need a specific structure what will be provided into the *upm* branch.
Use following direct URL for the configuration:
```
https://github.com/Dysman/bgTools-playerPrefsEditor.git#upm
```
See official Unity documentation for more informations: [UI](https://docs.unity3d.com/Manual/upm-ui-giturl.html) or [manifest.json](https://docs.unity3d.com/Manual/upm-git.html)
**Via OpenUPM**
The package is available on the [openupm registry](https://openupm.com). It's recommended to install it via [openupm-cli](https://github.com/openupm/openupm-cli).
```
openupm add com.bgtools.playerprefseditor
```
## Usage
The entry to open the _PlayerPrefs Editor_ is located in the top menu at Tools/BG Tools/PlayerPrefs Editor. It's a standard dockable window, so place it wherever it helps to be productive.
A more detailed manual can be fund in following locations:
* GitHub (Manual)- [Manual page](Packages/PlayerPrefsEditor/Documentation~/PlayerPrefsEditor.md)
* GitHub (UPM) - Press the _Documentation_ link on the UPM description.
* Unity Asset Store Package - [MANUAL.html](Documentation/MANUAL.html)

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3b2e0e2a0041b58458afaba08099fba4
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 70d87455559ee7d4d9abd1153e42ed4f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 16180e12a1ec47a4fb2cc753af98d39e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,53 @@
using UnityEngine;
public class PlayerPrefsController : MonoBehaviour
{
#region Add
public void AddTestStrings()
{
PlayerPrefs.SetString("Runtime_String", "boing");
PlayerPrefs.SetString("Runtime_String2", "foo");
PlayerPrefs.Save();
}
public void AddTestInt()
{
PlayerPrefs.SetInt("Runtime_Int", 1234);
PlayerPrefs.Save();
}
public void AddTestFloat()
{
PlayerPrefs.SetFloat("Runtime_Float", 3.14f);
PlayerPrefs.Save();
}
#endregion
#region Remove
public void RemoveTestStrings()
{
PlayerPrefs.DeleteKey("Runtime_String");
PlayerPrefs.DeleteKey("Runtime_String2");
PlayerPrefs.Save();
}
public void RemoveTestInt()
{
PlayerPrefs.DeleteKey("Runtime_Int");
PlayerPrefs.Save();
}
public void RemoveTestFloat()
{
PlayerPrefs.DeleteKey("Runtime_Float");
PlayerPrefs.Save();
}
public void DeleteAll()
{
PlayerPrefs.DeleteAll();
PlayerPrefs.Save();
}
#endregion
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4004328c339a7cb4fb509e2e5f789688
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fba661fc32606eb498ae23fd271867b4
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,12 @@
{
"name": "Unity.PlayerPrefsEditor.Samples.SampleScene",
"references": [],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7bb1abbf070c8e248939f8fd7910665f
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1 @@
{"androidStore":"GooglePlay"}

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 56a828302d3ac444da6adb4f2f638797
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,384 @@
using System.Collections;
using UnityEngine;
using TMPro;
using System;
using UnityEngine.Purchasing;
using System.Collections.Generic;
using static UnityEngine.Networking.UnityWebRequest;
using UnityEngine.Purchasing.Extension;
using UnityEngine.UI;
[Serializable]
public class ConsumableItem
{
public string Name;
public string Id;
public string desc;
public float price;
}
[Serializable]
public class NonConsumableItem
{
public string Name;
public string Id;
public string desc;
public float price;
}
[Serializable]
public class SubscriptionItem
{
public string Name;
public string Id;
public string desc;
public float price;
public int timeDuration;// in Days
}
public class ShopManager : MonoBehaviour, IDetailedStoreListener
{
IStoreController m_StoreContoller;
public List<ConsumableItem> cItem;
public List<int> coinsRewards;
//public NonConsumableItem ncItem;
//public SubscriptionItem sItem;
public TMP_InputField inp;
public Data data;
public Payload payload;
public PayloadData payloadData;
private void Start()
{
int coins = PlayerPrefs.GetInt("Coins");
coinTxt.text = coins.ToString();
SetupBuilder();
}
#region setup and initialize
void SetupBuilder()
{
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
for (int i = 0; i < cItem.Count; i++)
{
builder.AddProduct(cItem[i].Id, ProductType.Consumable);
}
//builder.AddProduct(ncItem.Id, ProductType.NonConsumable);
//builder.AddProduct(sItem.Id, ProductType.Subscription);
UnityPurchasing.Initialize(this, builder);
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
print("Success");
m_StoreContoller = controller;
//CheckNonConsumable(ncItem.Id);
//CheckSubscription(sItem.Id);
}
#endregion
#region button clicks
public void Consumable_Btn_Pressed(int index)
{
//AddCoins(50);
m_StoreContoller.InitiatePurchase(cItem[index].Id);
}
//public void NonConsumable_Btn_Pressed()
//{
// //RemoveAds();
// m_StoreContoller.InitiatePurchase(ncItem.Id);
//}
//public void Subscription_Btn_Pressed()
//{
// //ActivateElitePass();
// m_StoreContoller.InitiatePurchase(sItem.Id);
//}
#endregion
#region main
//processing purchase
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
{
//Retrive the purchased product
var product = purchaseEvent.purchasedProduct;
print("Purchase Complete" + product.definition.id);
for (int h = 0; h < cItem.Count; h++)
{
if (product.definition.id == cItem[h].Id)//consumable item is pressed
{
string receipt = product.receipt;
data = JsonUtility.FromJson<Data>(receipt);
payload = JsonUtility.FromJson<Payload>(data.Payload);
payloadData = JsonUtility.FromJson<PayloadData>(payload.json);
int quantity = payloadData.quantity;
for (int i = 0; i < quantity; i++)
{
AddCoins(h);
}
}
}
//else if (product.definition.id == ncItem.Id)//non consumable
//{
// RemoveAds();
//}
//else if (product.definition.id == sItem.Id)//subscribed
//{
// ActivateElitePass();
//}
return PurchaseProcessingResult.Complete;
}
#endregion
void CheckNonConsumable(string id)
{
if (m_StoreContoller != null)
{
var product = m_StoreContoller.products.WithID(id);
if (product != null)
{
if (product.hasReceipt)//purchased
{
RemoveAds();
}
else
{
ShowAds();
}
}
}
}
void CheckSubscription(string id)
{
var subProduct = m_StoreContoller.products.WithID(id);
if (subProduct != null)
{
try
{
if (subProduct.hasReceipt)
{
var subManager = new SubscriptionManager(subProduct, null);
var info = subManager.getSubscriptionInfo();
/*print(info.getCancelDate());
print(info.getExpireDate());
print(info.getFreeTrialPeriod());
print(info.getIntroductoryPrice());
print(info.getProductId());
print(info.getPurchaseDate());
print(info.getRemainingTime());
print(info.getSkuDetails());
print(info.getSubscriptionPeriod());
print(info.isAutoRenewing());
print(info.isCancelled());
print(info.isExpired());
print(info.isFreeTrial());
print(info.isSubscribed());*/
if (info.isSubscribed() == UnityEngine.Purchasing.Result.True)
{
print("We are subscribed");
ActivateElitePass();
}
else
{
print("Un subscribed");
DeActivateElitePass();
}
}
else
{
print("receipt not found !!");
}
}
catch (Exception)
{
print("It only work for Google store, app store, amazon store, you are using fake store!!");
}
}
else
{
print("product not found !!");
}
}
#region error handeling
public void OnInitializeFailed(InitializationFailureReason error)
{
print("failed" + error);
}
public void OnInitializeFailed(InitializationFailureReason error, string message)
{
print("initialize failed" + error + message);
}
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
{
print("purchase failed" + failureReason);
}
public void OnPurchaseFailed(Product product, PurchaseFailureDescription failureDescription)
{
print("purchase failed" + failureDescription);
}
#endregion
#region extra
[Header("Consumable")]
public Text coinTxt;
void AddCoins(int index)
{
int toAdd = coinsRewards[index];
int coins = PlayerPrefs.GetInt("Coin");
coins += toAdd;
PlayerPrefs.SetInt("Coin", coins);
StartCoroutine(startCoinShakeEffect(coins - toAdd, coins, .5f));
}
float val;
IEnumerator startCoinShakeEffect(int oldValue, int newValue, float animTime)
{
float ct = 0;
float nt;
float tot = animTime;
coinTxt.GetComponent<Animation>().Play("textShake");
while (ct < tot)
{
ct += Time.deltaTime;
nt = ct / tot;
val = Mathf.Lerp(oldValue, newValue, nt);
coinTxt.text = ((int)(val)).ToString();
yield return null;
}
coinTxt.GetComponent<Animation>().Stop();
}
[Header("Non Consumable")]
public GameObject AdsPurchasedWindow;
public GameObject adsBanner;
void RemoveAds()
{
DisplayAds(false);
}
void ShowAds()
{
DisplayAds(true);
}
void DisplayAds(bool x)
{
if (!x)
{
AdsPurchasedWindow.SetActive(true);
adsBanner.SetActive(false);
}
else
{
AdsPurchasedWindow.SetActive(false);
adsBanner.SetActive(true);
}
}
[Header("Subscription")]
public GameObject subActivatedWindow;
public GameObject premiumBanner;
void ActivateElitePass()
{
setupElitePass(true);
}
void DeActivateElitePass()
{
setupElitePass(false);
}
void setupElitePass(bool x)
{
if (x)// active
{
subActivatedWindow.SetActive(true);
premiumBanner.SetActive(true);
}
else
{
subActivatedWindow.SetActive(false);
premiumBanner.SetActive(false);
}
}
#endregion
}
[Serializable]
public class SkuDetails
{
public string productId;
public string type;
public string title;
public string name;
public string iconUrl;
public string description;
public string price;
public long price_amount_micros;
public string price_currency_code;
public string skuDetailsToken;
}
[Serializable]
public class PayloadData
{
public string orderId;
public string packageName;
public string productId;
public long purchaseTime;
public int purchaseState;
public string purchaseToken;
public int quantity;
public bool acknowledged;
}
[Serializable]
public class Payload
{
public string json;
public string signature;
public List<SkuDetails> skuDetails;
public PayloadData payloadData;
}
[Serializable]
public class Data
{
public string Payload;
public string Store;
public string TransactionID;
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a5467920342753f45af6cb2b5de436de
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -4,6 +4,7 @@
"com.unity.ide.rider": "3.0.31",
"com.unity.ide.visualstudio": "2.0.22",
"com.unity.ide.vscode": "1.2.5",
"com.unity.purchasing": "4.12.2",
"com.unity.textmeshpro": "3.0.9",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.androidjni": "1.0.0",

@ -38,6 +38,37 @@
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.nuget.newtonsoft-json": {
"version": "3.2.1",
"depth": 2,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.purchasing": {
"version": "4.12.2",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.ugui": "1.0.0",
"com.unity.services.core": "1.12.5",
"com.unity.modules.androidjni": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.services.core": {
"version": "1.12.5",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.modules.androidjni": "1.0.0",
"com.unity.nuget.newtonsoft-json": "3.2.1",
"com.unity.modules.unitywebrequest": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.test-framework": {
"version": "1.1.33",
"depth": 1,

@ -84,6 +84,7 @@ PlayerSettings:
muteOtherAudioSources: 0
Prepare IOS For Recording: 0
Force IOS Speakers When Recording: 0
audioSpatialExperience: 0
deferSystemGesturesMode: 0
hideHomeButton: 0
submitAnalytics: 1
@ -137,6 +138,8 @@ PlayerSettings:
vulkanEnableLateAcquireNextImage: 0
vulkanEnableCommandBufferRecycling: 1
loadStoreDebugModeEnabled: 0
visionOSBundleVersion: 1.0
tvOSBundleVersion: 1.0
bundleVersion: 1.4
preloadedAssets: []
metroInputSource: 0
@ -159,7 +162,7 @@ PlayerSettings:
androidSupportedAspectRatio: 1
androidMaxAspectRatio: 2.1
applicationIdentifier:
Android: com.RizzeStudios.PiPuzzle
Android: com.rizze.pipuzzle
iPhone: com.rizze.pipuzzle
buildNumber:
Standalone: 0
@ -232,6 +235,7 @@ PlayerSettings:
iOSMetalForceHardShadows: 0
metalEditorSupport: 1
metalAPIValidation: 1
metalCompileShaderBinary: 0
iOSRenderExtraFrameOnPause: 1
iosCopyPluginsCodeInsteadOfSymlink: 0
appleDeveloperTeamID:
@ -863,6 +867,7 @@ PlayerSettings:
metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628,
a: 1}
metroSplashScreenUseBackgroundColor: 0
syncCapabilities: 0
platformCapabilities: {}
metroTargetDeviceFamilies: {}
metroFTAName:
@ -897,7 +902,13 @@ PlayerSettings:
XboxOneOverrideIdentityName:
XboxOneOverrideIdentityPublisher:
vrEditorSettings: {}
cloudServicesEnabled: {}
cloudServicesEnabled:
Build: 0
Game Performance: 0
Legacy Analytics: 0
Purchasing: 0
UDP: 0
Unity Ads: 0
luminIcon:
m_Name:
m_ModelFolderPath:

Loading…
Cancel
Save