Introduce no GC string formatter to optimize score string formatting.
This commit is contained in:
@@ -4,6 +4,7 @@ using Cryville.Common.Pdt;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Text.Formatting;
|
||||||
|
|
||||||
namespace Cryville.Crtr {
|
namespace Cryville.Crtr {
|
||||||
public class Judge {
|
public class Judge {
|
||||||
@@ -217,7 +218,7 @@ namespace Cryville.Crtr {
|
|||||||
scoreDefs.Add(key, s.Value);
|
scoreDefs.Add(key, s.Value);
|
||||||
scores.Add(key, s.Value.init);
|
scores.Add(key, s.Value.init);
|
||||||
scoreStringCache.Add(scoreStringKeys[key], null);
|
scoreStringCache.Add(scoreStringKeys[key], null);
|
||||||
scoreStringSrcs.Add(scoreStringKeys[key], new ScoreStringSrc(scoreStringPool, () => GetScoreString(strkey)));
|
scoreStringSrcs.Add(scoreStringKeys[key], new ScoreStringSrc(scoreStringPool, () => scores[key], scoreDefs[key].format));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void InvalidateScore(int key) {
|
void InvalidateScore(int key) {
|
||||||
@@ -249,30 +250,32 @@ namespace Cryville.Crtr {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
class ScoreStringSrc : PropSrc {
|
class ScoreStringSrc : PropSrc {
|
||||||
readonly Func<string> _cb;
|
readonly Func<float> _cb;
|
||||||
|
readonly string _format;
|
||||||
readonly ArrayPool<byte> _pool;
|
readonly ArrayPool<byte> _pool;
|
||||||
byte[] _buf;
|
readonly StringBuffer _buf = new StringBuffer();
|
||||||
public ScoreStringSrc(ArrayPool<byte> pool, Func<string> cb)
|
public ScoreStringSrc(ArrayPool<byte> pool, Func<float> cb, string format)
|
||||||
: base(PdtInternalType.String) {
|
: base(PdtInternalType.String) {
|
||||||
_pool = pool;
|
_pool = pool;
|
||||||
_cb = cb;
|
_cb = cb;
|
||||||
|
_format = string.Format("{{0:{0}}}", format);
|
||||||
}
|
}
|
||||||
public override void Invalidate() {
|
public override void Invalidate() {
|
||||||
base.Invalidate();
|
if (buf != null) {
|
||||||
if (_buf != null) {
|
_pool.Return(buf);
|
||||||
_pool.Return(_buf);
|
base.Invalidate();
|
||||||
_buf = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected override unsafe void InternalGet() {
|
protected override unsafe void InternalGet() {
|
||||||
var src = _cb();
|
var src = _cb();
|
||||||
int strlen = src.Length;
|
_buf.Clear();
|
||||||
|
_buf.AppendFormat(_format, src);
|
||||||
|
int strlen = _buf.Count;
|
||||||
buf = _pool.Rent(sizeof(int) + strlen * sizeof(char));
|
buf = _pool.Rent(sizeof(int) + strlen * sizeof(char));
|
||||||
fixed (byte* _ptr = buf) {
|
fixed (byte* _ptr = buf) {
|
||||||
char* ptr = (char*)(_ptr + sizeof(int));
|
|
||||||
*(int*)_ptr = strlen;
|
*(int*)_ptr = strlen;
|
||||||
int i = 0;
|
char* ptr = (char*)(_ptr + sizeof(int));
|
||||||
foreach (var c in src) ptr[i++] = c;
|
_buf.CopyTo(ptr, 0, strlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,8 @@
|
|||||||
"rootNamespace": "",
|
"rootNamespace": "",
|
||||||
"references": [
|
"references": [
|
||||||
"GUID:d8ea0e0da3ad53a45b65c912ffcacab0",
|
"GUID:d8ea0e0da3ad53a45b65c912ffcacab0",
|
||||||
"GUID:5686e5ee69d0e084c843d61c240d7fdb"
|
"GUID:5686e5ee69d0e084c843d61c240d7fdb",
|
||||||
|
"GUID:2922aa74af3b2854e81b8a8b286d8206"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
8
Assets/Plugins/StringFormatter.meta
Normal file
8
Assets/Plugins/StringFormatter.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0c0e7d20046652343bdbe3ed52cb0340
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
333
Assets/Plugins/StringFormatter/CustomNumeric.cs
Normal file
333
Assets/Plugins/StringFormatter/CustomNumeric.cs
Normal file
@@ -0,0 +1,333 @@
|
|||||||
|
// Copyright (c) 2023 Cryville
|
||||||
|
//
|
||||||
|
// This file contains an implementation of the stub for custom format string
|
||||||
|
// originally written by Michael Popoloski. Below is the original license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015-2017 Michael Popoloski
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
namespace System.Text.Formatting {
|
||||||
|
// this file contains the custom numeric formatting routines split out from the Numeric.cs file
|
||||||
|
unsafe partial class Numeric {
|
||||||
|
static void NumberToCustomFormatString(StringBuffer formatter, ref Number number, StringView specifier, CachedCulture culture) {
|
||||||
|
// Special: Handle special values
|
||||||
|
switch (number.Scale) {
|
||||||
|
case ScaleInf: formatter.Append(number.Sign == 0 ? culture.PositiveInfinity : culture.NegativeInfinity); return;
|
||||||
|
case ScaleNaN: formatter.Append(culture.NaN); return;
|
||||||
|
}
|
||||||
|
// Iteration 1: Split by semicolon
|
||||||
|
int specifierPositiveEnd = IndexOfSectionSeparator(specifier);
|
||||||
|
int specifierNegativeStart = 0, specifierNegativeEnd, specifierZeroStart = 0;
|
||||||
|
if (specifierPositiveEnd == -1) {
|
||||||
|
specifierPositiveEnd = specifierNegativeEnd = specifier.Length;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
specifierNegativeStart = specifierPositiveEnd + 1;
|
||||||
|
specifierNegativeEnd = IndexOfSectionSeparator(specifier, specifierNegativeStart);
|
||||||
|
if (specifierNegativeEnd == -1) {
|
||||||
|
specifierNegativeEnd = specifier.Length;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
specifierZeroStart = specifierNegativeEnd + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Special: Handle zero
|
||||||
|
if (IsZero(ref number)) {
|
||||||
|
FormatCustomFormatString(formatter, ref number, null, specifier, specifierZeroStart, specifier.Length, culture);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Iteration 2: Divide and round number
|
||||||
|
int originalScale = number.Scale;
|
||||||
|
if (number.Sign == 0) ApplyDivisionAndPrecision(ref number, specifier, 0, specifierPositiveEnd);
|
||||||
|
else ApplyDivisionAndPrecision(ref number, specifier, specifierNegativeStart, specifierNegativeEnd);
|
||||||
|
// Iteration 3: Count; Iteration 4: Format
|
||||||
|
if (IsZero(ref number)) FormatCustomFormatString(formatter, ref number, null, specifier, specifierZeroStart, specifier.Length, culture);
|
||||||
|
else if (number.Sign == 0) FormatCustomFormatString(formatter, ref number, originalScale, specifier, 0, specifierPositiveEnd, culture);
|
||||||
|
else {
|
||||||
|
if (specifierNegativeStart == 0) formatter.Append(culture.NegativeSign);
|
||||||
|
FormatCustomFormatString(formatter, ref number, originalScale, specifier, specifierNegativeStart, specifierNegativeEnd, culture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static int IndexOfSectionSeparator(StringView specifier) {
|
||||||
|
return IndexOfSectionSeparator(specifier, 0);
|
||||||
|
}
|
||||||
|
static int IndexOfSectionSeparator(StringView specifier, int index) {
|
||||||
|
if (index < 0 || index > specifier.Length) throw new ArgumentOutOfRangeException("index");
|
||||||
|
char* ptr = specifier.Data;
|
||||||
|
for (; index < specifier.Length; index++) {
|
||||||
|
switch (ptr[index]) {
|
||||||
|
case ';': return index;
|
||||||
|
case '\\':
|
||||||
|
index++;
|
||||||
|
if (index >= specifier.Length) throw new FormatException();
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
SkipLiteral(specifier, ref index, '\'');
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
SkipLiteral(specifier, ref index, '"');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
static bool IsZero(ref Number number) {
|
||||||
|
char* ptr = number.Digits;
|
||||||
|
while (*ptr != '\0') if (*ptr++ != '0') return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
static void ApplyDivisionAndPrecision(ref Number number, StringView specifier, int index, int end) {
|
||||||
|
int deltaScale = 0, scalingSpecifiers = 0;
|
||||||
|
int integralDigits = 0, decimalDigits = 0;
|
||||||
|
bool decimalFlag = false, exponentialFlag = false;
|
||||||
|
char* ptr = specifier.Data;
|
||||||
|
for (; index < end; index++) {
|
||||||
|
switch (ptr[index]) {
|
||||||
|
case '\\':
|
||||||
|
if (++index >= end) throw new FormatException();
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
SkipLiteral(specifier, ref index, '\'');
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
SkipLiteral(specifier, ref index, '"');
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
case '#':
|
||||||
|
if (decimalFlag) decimalDigits++;
|
||||||
|
else integralDigits++;
|
||||||
|
scalingSpecifiers = 0;
|
||||||
|
break;
|
||||||
|
case '.': decimalFlag = true; deltaScale -= scalingSpecifiers * 3; break;
|
||||||
|
case ',': scalingSpecifiers++; break;
|
||||||
|
case '%': deltaScale += 2; break;
|
||||||
|
case '‰': deltaScale += 3; break;
|
||||||
|
case 'E':
|
||||||
|
case 'e':
|
||||||
|
if (++index >= end) goto exit;
|
||||||
|
char tc0 = ptr[index];
|
||||||
|
if (tc0 == '+' || tc0 == '-') {
|
||||||
|
if (++index >= end) goto exit;
|
||||||
|
}
|
||||||
|
if (ptr[index] != '0') break;
|
||||||
|
exponentialFlag = true;
|
||||||
|
for (index++; index < end && ptr[index] == '0'; index++) ;
|
||||||
|
index--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
if (exponentialFlag) {
|
||||||
|
number.Scale = integralDigits;
|
||||||
|
RoundNumber(ref number, integralDigits + decimalDigits);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
number.Scale += deltaScale;
|
||||||
|
RoundNumber(ref number, number.Scale + decimalDigits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void FormatCustomFormatString(StringBuffer formatter, ref Number number, int? originalScale, StringView specifier, int index, int end, CachedCulture culture) {
|
||||||
|
int start = index;
|
||||||
|
int integralDigits = 0, integralZeros = 0,
|
||||||
|
decimalDigits = 0, decimalZeros = 0;
|
||||||
|
bool integralHasZeroFlag = false;
|
||||||
|
int exponentialZeros = 0;
|
||||||
|
bool decimalFlag = false;
|
||||||
|
bool commaFlag = false, groupFlag = false;
|
||||||
|
char* ptr = specifier.Data;
|
||||||
|
for (; index < end; index++) {
|
||||||
|
switch (ptr[index]) {
|
||||||
|
case '\\':
|
||||||
|
if (++index >= end) throw new FormatException();
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
SkipLiteral(specifier, ref index, '\'');
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
SkipLiteral(specifier, ref index, '"');
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
if (decimalFlag) {
|
||||||
|
if (decimalZeros < decimalDigits)
|
||||||
|
decimalZeros = decimalDigits;
|
||||||
|
decimalDigits++;
|
||||||
|
decimalZeros++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
integralDigits++;
|
||||||
|
integralZeros++;
|
||||||
|
integralHasZeroFlag = true;
|
||||||
|
if (commaFlag) groupFlag = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
if (decimalFlag) {
|
||||||
|
decimalDigits++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
integralDigits++;
|
||||||
|
if (integralHasZeroFlag) integralZeros++;
|
||||||
|
if (commaFlag) groupFlag = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '.': decimalFlag = true; commaFlag = false; break;
|
||||||
|
case ',': commaFlag = true; break;
|
||||||
|
case 'E':
|
||||||
|
case 'e':
|
||||||
|
if (++index >= end) goto exit;
|
||||||
|
char tc0 = ptr[index];
|
||||||
|
if (tc0 == '+' || tc0 == '-') {
|
||||||
|
if (++index >= end) goto exit;
|
||||||
|
}
|
||||||
|
if (ptr[index] != '0') break;
|
||||||
|
for (; index < end && ptr[index] == '0'; index++) exponentialZeros++;
|
||||||
|
index--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
int currentDigitIndex = 0;
|
||||||
|
int groupIndex = 0, remainingDigitsInGroup = Math.Max(number.Scale, decimalZeros);
|
||||||
|
if (groupFlag) while (true) {
|
||||||
|
int groupSize = culture.NumberData.GroupSizes.ElementAtOrLast(groupIndex);
|
||||||
|
if (remainingDigitsInGroup <= groupSize) break;
|
||||||
|
remainingDigitsInGroup -= groupSize;
|
||||||
|
groupIndex++;
|
||||||
|
}
|
||||||
|
if (number.Scale > integralDigits) while (currentDigitIndex < number.Scale - integralDigits)
|
||||||
|
formatter.AppendIntegralDigit(ref number, ref currentDigitIndex, culture, groupFlag, ref groupIndex, ref remainingDigitsInGroup);
|
||||||
|
decimalFlag = false;
|
||||||
|
for (index = start; index < end; index++) {
|
||||||
|
switch (ptr[index]) {
|
||||||
|
case '\\':
|
||||||
|
if (++index >= end) throw new FormatException();
|
||||||
|
formatter.Append(ptr[index]);
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
formatter.AppendLiteral(specifier, ref index, '\'');
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
formatter.AppendLiteral(specifier, ref index, '"');
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
case '#':
|
||||||
|
if (decimalFlag) {
|
||||||
|
if (currentDigitIndex < number.Precision) {
|
||||||
|
char digit = number.Digits[currentDigitIndex++];
|
||||||
|
if (digit == '\0') digit = '0';
|
||||||
|
formatter.Append(digit);
|
||||||
|
}
|
||||||
|
else if (decimalZeros > 0)
|
||||||
|
formatter.Append('0');
|
||||||
|
--decimalDigits;
|
||||||
|
--decimalZeros;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (integralDigits <= number.Scale)
|
||||||
|
formatter.AppendIntegralDigit(ref number, ref currentDigitIndex, culture, groupFlag, ref groupIndex, ref remainingDigitsInGroup);
|
||||||
|
else if (integralDigits <= integralZeros)
|
||||||
|
formatter.AppendIntegralDigit('0', culture, groupFlag, ref groupIndex, ref remainingDigitsInGroup);
|
||||||
|
--integralDigits;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '.': formatter.Append(culture.NumberData.DecimalSeparator); decimalFlag = true; break;
|
||||||
|
case ',': break;
|
||||||
|
case '%': formatter.Append(culture.PercentSymbol); break;
|
||||||
|
case '‰': formatter.Append(culture.PerMilleSymbol); break;
|
||||||
|
case 'E':
|
||||||
|
case 'e':
|
||||||
|
char exponentialSymbol = ptr[index];
|
||||||
|
if (++index >= end) {
|
||||||
|
index--;
|
||||||
|
goto default;
|
||||||
|
}
|
||||||
|
char tc0 = ptr[index];
|
||||||
|
bool hasPlusFlag = false;
|
||||||
|
if (tc0 == '+' || tc0 == '-') {
|
||||||
|
if (++index >= end) {
|
||||||
|
index -= 2;
|
||||||
|
goto default;
|
||||||
|
}
|
||||||
|
if (tc0 == '+') hasPlusFlag = true;
|
||||||
|
}
|
||||||
|
if (ptr[index] != '0') {
|
||||||
|
index -= 2;
|
||||||
|
goto default;
|
||||||
|
}
|
||||||
|
for (index++; index < end && ptr[index] == '0'; index++) ;
|
||||||
|
index--;
|
||||||
|
|
||||||
|
int exp = originalScale == null ? 0 : originalScale.Value - number.Scale;
|
||||||
|
formatter.Append(exponentialSymbol);
|
||||||
|
if (exp < 0) {
|
||||||
|
formatter.Append(culture.NegativeSign);
|
||||||
|
exp = -exp;
|
||||||
|
}
|
||||||
|
else if (hasPlusFlag) {
|
||||||
|
formatter.Append(culture.PositiveSign);
|
||||||
|
}
|
||||||
|
Int32ToDecStr(formatter, exp, exponentialZeros, "");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
formatter.Append(ptr[index]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void AppendIntegralDigit(this StringBuffer self, ref Number number, ref int index, CachedCulture culture, bool groupFlag, ref int groupIndex, ref int remainingDigitsInGroup) {
|
||||||
|
char digit;
|
||||||
|
if (index >= number.Precision) digit = '0';
|
||||||
|
else digit = number.Digits[index];
|
||||||
|
if (digit == '\0') digit = '0';
|
||||||
|
self.AppendIntegralDigit(digit, culture, groupFlag, ref groupIndex, ref remainingDigitsInGroup);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
static void AppendIntegralDigit(this StringBuffer self, char digit, CachedCulture culture, bool groupFlag, ref int groupIndex, ref int remainingDigitsInGroup) {
|
||||||
|
self.Append(digit);
|
||||||
|
if (!groupFlag) return;
|
||||||
|
if (--remainingDigitsInGroup == 0) {
|
||||||
|
if (--groupIndex >= 0) {
|
||||||
|
remainingDigitsInGroup = culture.NumberData.GroupSizes.ElementAtOrLast(groupIndex);
|
||||||
|
self.Append(culture.NumberData.GroupSeparator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static T ElementAtOrLast<T>(this T[] arr, int index) {
|
||||||
|
if (index >= arr.Length) index = arr.Length - 1;
|
||||||
|
return arr[index];
|
||||||
|
}
|
||||||
|
static void SkipLiteral(StringView specifier, ref int index, char delimiter) {
|
||||||
|
while (++index < specifier.Length) {
|
||||||
|
if (specifier.Data[index] == delimiter) return;
|
||||||
|
}
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
static void AppendLiteral(this StringBuffer self, StringView specifier, ref int index, char delimiter) {
|
||||||
|
int start = index + 1;
|
||||||
|
while (++index < specifier.Length) {
|
||||||
|
if (specifier.Data[index] == delimiter) {
|
||||||
|
self.Append(specifier.Data + start, index - start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new FormatException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Assets/Plugins/StringFormatter/CustomNumeric.cs.meta
Normal file
11
Assets/Plugins/StringFormatter/CustomNumeric.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 85c9d5fa7edeb9d4d8737903efc95abd
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
14
Assets/Plugins/StringFormatter/StringFormatter.asmdef
Normal file
14
Assets/Plugins/StringFormatter/StringFormatter.asmdef
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "StringFormatter",
|
||||||
|
"rootNamespace": "",
|
||||||
|
"references": [],
|
||||||
|
"includePlatforms": [],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": true,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": true
|
||||||
|
}
|
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2922aa74af3b2854e81b8a8b286d8206
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
2462
Assets/Plugins/StringFormatter/StringFormatter.cs
Normal file
2462
Assets/Plugins/StringFormatter/StringFormatter.cs
Normal file
File diff suppressed because it is too large
Load Diff
11
Assets/Plugins/StringFormatter/StringFormatter.cs.meta
Normal file
11
Assets/Plugins/StringFormatter/StringFormatter.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: be273397b1d98a24cb864cb3e05643cd
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
Reference in New Issue
Block a user