demo
@@ -109,6 +109,7 @@ AGENTS.md
|
||||
Assets/Screenshots/
|
||||
output/
|
||||
tmp/
|
||||
Artifacts/
|
||||
Packages/
|
||||
Assets/unity-mcp/
|
||||
Assets/unity-mcp.meta
|
||||
@@ -121,4 +122,19 @@ KNOWN_PITFALLS.md
|
||||
Assets/~UnityDirMonSyncFile~84ae11425aac2204fbff8739574b1de6~
|
||||
.idea/
|
||||
GeneratedServers/
|
||||
!GeneratedServers/
|
||||
GeneratedServers/*
|
||||
!GeneratedServers/ReplacedPerson.Core/
|
||||
GeneratedServers/ReplacedPerson.Core/*
|
||||
!GeneratedServers/ReplacedPerson.Core/ReplacedPerson.Core.csproj
|
||||
!GeneratedServers/ReplacedPerson.ServerHost/
|
||||
GeneratedServers/ReplacedPerson.ServerHost/*
|
||||
!GeneratedServers/ReplacedPerson.ServerHost/ReplacedPerson.ServerHost.csproj
|
||||
!GeneratedServers/ReplacedPerson.ServerHost/Program.cs
|
||||
!GeneratedServers/ReplacedPerson.ServerHost/run-server.ps1
|
||||
!GeneratedServers/ReplacedPerson.ServerHost/README.md
|
||||
!GeneratedServers/ExampleGreedMod.Rules/
|
||||
GeneratedServers/ExampleGreedMod.Rules/*
|
||||
!GeneratedServers/ExampleGreedMod.Rules/ExampleGreedMod.Rules.csproj
|
||||
!GeneratedServers/ExampleGreedMod.Rules/pack-mod.ps1
|
||||
GeneratedModSdk/
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"mcp": {
|
||||
"servers": {
|
||||
"funplay-unity": {
|
||||
"type": "http",
|
||||
"url": "http://127.0.0.1:20195/mcp",
|
||||
"timeoutMs": 60000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ad6f74af7a0f854da0f9048dd81adfb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f70a9c8e61d85e441aa0b6b9913225d0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d964bdaad60b51a4e907a36afd24394f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 602d19931142c764ea5782f9dd0ccd2c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 8.2 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 007fd50a189dcdb429f59d7f079c94a7
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c05ce0fa44f7afd469978f151d4c62c8
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80d669f920616bc4f9dd1303ad50121f
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 634 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5f1908c966a51745b49cb415049745e
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 621 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 706a0c3bc5d551e429c8b496520e21d4
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 590 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e89719c4b22a6a4691729532aeb3050
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 627 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de93951858707514fbfa07fe0bb2371a
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 633 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6af7ddfbc8063a3438d79055d8ac52b7
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 623 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c61c05c482f05a34e9de768086a2487e
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 660 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87c34b2fd134be94cb9f123a9a29d3b1
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 556 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff4a0b0f38cc1ae45aec94b3de0f5d98
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bdae700573c0b914183ef4bfa3105761
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1dbe085ce7e9c694b8082803d828032a
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 642 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce3a95c26eabd1f45b0f7fca6c356b5b
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13367afdf20e47f40b184469b5e36efd
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4ea3d79e2ad0e243baca4b62e43287c
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- Noto Sans SC
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09959c845ab86524f803da99d8fcad6a
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5efe820f5d0ee3648bd837bfe2d5fac1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,166 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace ReplacedPerson.Core
|
||||
{
|
||||
public sealed class ReplacedContentCatalog
|
||||
{
|
||||
public Dictionary<string, ReplacedCardDefinition> Cards { get; } = new(StringComparer.Ordinal);
|
||||
public Dictionary<string, ReplacedEndCardDefinition> EndCards { get; } = new(StringComparer.Ordinal);
|
||||
public Dictionary<string, ReplacedEnemyDefinition> Enemies { get; } = new(StringComparer.Ordinal);
|
||||
public Dictionary<string, IReplacedPersonEffectResolver> EffectResolvers { get; } = new(StringComparer.Ordinal);
|
||||
|
||||
public ReplacedContentCatalog Clone()
|
||||
{
|
||||
var clone = new ReplacedContentCatalog();
|
||||
foreach (var pair in Cards)
|
||||
clone.Cards.Add(pair.Key, Clone(pair.Value));
|
||||
foreach (var pair in EndCards)
|
||||
clone.EndCards.Add(pair.Key, Clone(pair.Value));
|
||||
foreach (var pair in Enemies)
|
||||
clone.Enemies.Add(pair.Key, Clone(pair.Value));
|
||||
foreach (var pair in EffectResolvers)
|
||||
clone.EffectResolvers.Add(pair.Key, pair.Value);
|
||||
return clone;
|
||||
}
|
||||
|
||||
public string ComputeHash()
|
||||
{
|
||||
var text = new StringBuilder();
|
||||
foreach (var card in Cards.Values.OrderBy(value => value.Id, StringComparer.Ordinal))
|
||||
text.Append("C|").Append(card.Id).Append('|').Append(card.Name).Append('|').Append((int)card.EffectType)
|
||||
.Append('|').Append(card.Cost).Append('|').Append(card.BaseValue).Append('|').Append(card.Factor)
|
||||
.Append('|').Append(card.SpecialEffectId).Append('\n');
|
||||
foreach (var card in EndCards.Values.OrderBy(value => value.Id, StringComparer.Ordinal))
|
||||
text.Append("E|").Append(card.Id).Append('|').Append(card.Name).Append('|').Append(card.Cost).Append('|')
|
||||
.Append(string.Join(",", card.SlotBase)).Append('|').Append(string.Join(",", card.SlotFactor)).Append('\n');
|
||||
foreach (var enemy in Enemies.Values.OrderBy(value => value.Id, StringComparer.Ordinal))
|
||||
text.Append("N|").Append(enemy.Id).Append('|').Append(enemy.Name).Append('|').Append(enemy.MaxHealth).Append('|')
|
||||
.Append(string.Join(",", enemy.NormalDeck)).Append('|').Append(string.Join(",", enemy.EndDeck)).Append('\n');
|
||||
foreach (var effect in EffectResolvers.OrderBy(value => value.Key, StringComparer.Ordinal))
|
||||
text.Append("R|").Append(effect.Key).Append('|').Append(effect.Value.GetType().FullName).Append('\n');
|
||||
using var sha = SHA256.Create();
|
||||
var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(text.ToString()));
|
||||
var hash = new StringBuilder(bytes.Length * 2);
|
||||
foreach (var value in bytes) hash.Append(value.ToString("x2"));
|
||||
return hash.ToString();
|
||||
}
|
||||
|
||||
private static ReplacedCardDefinition Clone(ReplacedCardDefinition value) => new()
|
||||
{
|
||||
Id = value.Id, Name = value.Name, Description = value.Description, EffectType = value.EffectType,
|
||||
Cost = value.Cost, BaseValue = value.BaseValue, Factor = value.Factor, SpecialEffectId = value.SpecialEffectId
|
||||
};
|
||||
|
||||
private static ReplacedEndCardDefinition Clone(ReplacedEndCardDefinition value) => new()
|
||||
{
|
||||
Id = value.Id, Name = value.Name, Description = value.Description, Cost = value.Cost,
|
||||
SlotBase = (int[])value.SlotBase.Clone(), SlotFactor = (int[])value.SlotFactor.Clone()
|
||||
};
|
||||
|
||||
private static ReplacedEnemyDefinition Clone(ReplacedEnemyDefinition value) => new()
|
||||
{
|
||||
Id = value.Id, Name = value.Name, MaxHealth = value.MaxHealth,
|
||||
NormalDeck = new List<string>(value.NormalDeck), EndDeck = new List<string>(value.EndDeck),
|
||||
RewardIds = new List<string>(value.RewardIds)
|
||||
};
|
||||
}
|
||||
|
||||
public static class ReplacedBuiltInContent
|
||||
{
|
||||
public static ReplacedContentCatalog Create()
|
||||
{
|
||||
var result = new ReplacedContentCatalog();
|
||||
AddCard(result, "attack.kill", "杀", ReplacedEffectType.Attack, 2, 2, 2, "直截了当的低费进攻。");
|
||||
AddCard(result, "attack.elbow", "肘击", ReplacedEffectType.Attack, 3, 3, 2, "稳定进攻,适合试探对位。");
|
||||
AddCard(result, "attack.break", "破局", ReplacedEffectType.Attack, 4, 3, 3, "高波动进攻。");
|
||||
AddCard(result, "attack.iron", "铁山靠", ReplacedEffectType.Attack, 5, 5, 2, "高始数压制。");
|
||||
AddCard(result, "attack.burst", "寸劲", ReplacedEffectType.Attack, 6, 4, 3, "高上限连击。");
|
||||
AddCard(result, "attack.palm", "黄经极世掌", ReplacedEffectType.Attack, 7, 5, 3, "终盘重击。");
|
||||
AddCard(result, "dodge.flash", "闪", ReplacedEffectType.Dodge, 2, 4, 2, "闪避成功后获得额外抽牌。");
|
||||
AddCard(result, "dodge.phase", "虚化", ReplacedEffectType.Dodge, 3, 5, 3, "与反击合成可获得防御。");
|
||||
AddCard(result, "counter.stance", "架势", ReplacedEffectType.Counter, 1, 2, 2, "低费反击,用来试探攻击并为高费反制保留 COST。");
|
||||
AddCard(result, "counter.blood", "以血蒙眼", ReplacedEffectType.Counter, 3, 5, 2, "反制进攻并返还伤害。");
|
||||
AddCard(result, "counter.instant", "一瞬千击", ReplacedEffectType.Counter, 5, 7, 3, "高费反击。");
|
||||
AddCard(result, "greed.snob", "势利眼", ReplacedEffectType.Dodge, 3, 2, 2, "贪婪的闪避牌。", "greed.draw");
|
||||
AddCard(result, "greed.turn-profit", "扭亏为盈", ReplacedEffectType.Counter, 4, 3, 3, "反击成功时恢复 COST。", "greed.refund");
|
||||
AddCard(result, "greed.wage-cut", "降薪", ReplacedEffectType.Attack, 4, 2, 2, "命中后削减对方 COST。", "greed.wage-cut");
|
||||
|
||||
AddEnd(result, "end.inherit", "继承", 0, new[] { 0, 0, 0 }, new[] { 0, 0, 0 }, "将左侧普通牌效果继承到三个槽位。");
|
||||
AddEnd(result, "end.ledger", "账本", 1, new[] { 1, 0, 1 }, new[] { 0, 1, 0 }, "稳定首尾槽。");
|
||||
AddEnd(result, "end.severance", "断契", 1, new[] { 0, 2, 0 }, new[] { 1, 0, 1 }, "强化中槽始数与边槽因数。");
|
||||
AddEnd(result, "end.black", "黑色遗嘱", 2, new[] { 1, 1, 1 }, new[] { 1, 0, 1 }, "全面强化,适合孤注一掷。");
|
||||
|
||||
var playerDeck = CreateStarterDeck();
|
||||
result.Enemies.Add("greed.tutorial", new ReplacedEnemyDefinition
|
||||
{
|
||||
Id = "greed.tutorial", Name = "贪婪·影子", MaxHealth = 20,
|
||||
NormalDeck = new List<string> { "attack.kill", "attack.kill", "attack.elbow", "attack.elbow", "dodge.flash", "dodge.flash", "counter.blood", "counter.blood", "greed.snob", "greed.snob", "greed.turn-profit", "greed.wage-cut" },
|
||||
EndDeck = new List<string>(playerDeck.EndCards), RewardIds = new List<string> { "ornament.gold-eye" }
|
||||
});
|
||||
result.Enemies.Add("greed.full", new ReplacedEnemyDefinition
|
||||
{
|
||||
Id = "greed.full", Name = "贪婪·葛朗台", MaxHealth = 30,
|
||||
NormalDeck = new List<string> { "attack.break", "attack.break", "attack.iron", "attack.iron", "dodge.phase", "dodge.phase", "greed.snob", "greed.snob", "greed.turn-profit", "greed.turn-profit", "greed.wage-cut", "greed.wage-cut" },
|
||||
EndDeck = new List<string>(playerDeck.EndCards), RewardIds = new List<string> { "ornament.gold-eye", "ornament.gold-chain", "ornament.worn-suit", "greed.snob", "greed.turn-profit", "greed.wage-cut" }
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ReplacedDeck CreateStarterDeck() => new()
|
||||
{
|
||||
NormalCards = new List<string>
|
||||
{
|
||||
"counter.stance", "counter.stance", "counter.blood", "counter.blood", "counter.instant", "counter.instant",
|
||||
"dodge.flash", "dodge.flash", "attack.kill", "attack.kill", "attack.elbow", "attack.elbow"
|
||||
},
|
||||
EndCards = new List<string> { "end.inherit", "end.ledger", "end.severance", "end.black" }
|
||||
};
|
||||
|
||||
private static void AddCard(ReplacedContentCatalog target, string id, string name, ReplacedEffectType type,
|
||||
int cost, int baseValue, int factor, string description, string special = "")
|
||||
{
|
||||
target.Cards.Add(id, new ReplacedCardDefinition
|
||||
{
|
||||
Id = id, Name = name, EffectType = type, Cost = cost, BaseValue = baseValue,
|
||||
Factor = factor, Description = description, SpecialEffectId = special
|
||||
});
|
||||
}
|
||||
|
||||
private static void AddEnd(ReplacedContentCatalog target, string id, string name, int cost,
|
||||
int[] slotBase, int[] slotFactor, string description)
|
||||
{
|
||||
target.EndCards.Add(id, new ReplacedEndCardDefinition
|
||||
{
|
||||
Id = id, Name = name, Cost = cost, SlotBase = slotBase, SlotFactor = slotFactor, Description = description
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static class ReplacedDeckValidator
|
||||
{
|
||||
public static IReadOnlyList<string> Validate(ReplacedDeck deck, ReplacedContentCatalog catalog)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
if (deck == null) return new[] { "deck.null" };
|
||||
if (deck.NormalCards.Count != 12) errors.Add("deck.normal.count");
|
||||
if (deck.EndCards.Count != 4) errors.Add("deck.end.count");
|
||||
foreach (var group in deck.NormalCards.GroupBy(value => value, StringComparer.Ordinal))
|
||||
{
|
||||
if (!catalog.Cards.ContainsKey(group.Key)) errors.Add("deck.normal.unknown:" + group.Key);
|
||||
if (group.Count() > 2) errors.Add("deck.normal.duplicate:" + group.Key);
|
||||
}
|
||||
foreach (var group in deck.EndCards.GroupBy(value => value, StringComparer.Ordinal))
|
||||
{
|
||||
if (!catalog.EndCards.ContainsKey(group.Key)) errors.Add("deck.end.unknown:" + group.Key);
|
||||
if (group.Count() > 1) errors.Add("deck.end.duplicate:" + group.Key);
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa02820e6d30cc849adac4b52dcd52f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,220 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ReplacedPerson.Core
|
||||
{
|
||||
public enum ReplacedEffectType
|
||||
{
|
||||
Attack = 0,
|
||||
Dodge = 1,
|
||||
Counter = 2
|
||||
}
|
||||
|
||||
public enum ReplacedMatchPhase
|
||||
{
|
||||
AwaitingLead = 0,
|
||||
AwaitingResponse = 1,
|
||||
Resolving = 2,
|
||||
Completed = 3
|
||||
}
|
||||
|
||||
public enum ReplacedWinner
|
||||
{
|
||||
None = -1,
|
||||
PlayerOne = 0,
|
||||
PlayerTwo = 1,
|
||||
Draw = 2
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedCardDefinition
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public ReplacedEffectType EffectType { get; set; }
|
||||
public int Cost { get; set; }
|
||||
public int BaseValue { get; set; }
|
||||
public int Factor { get; set; }
|
||||
public string SpecialEffectId { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedEndCardDefinition
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public int Cost { get; set; }
|
||||
public int[] SlotBase { get; set; } = new int[3];
|
||||
public int[] SlotFactor { get; set; } = new int[3];
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedEnemyDefinition
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public int MaxHealth { get; set; } = 30;
|
||||
public List<string> NormalDeck { get; set; } = new();
|
||||
public List<string> EndDeck { get; set; } = new();
|
||||
public List<string> RewardIds { get; set; } = new();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedDeck
|
||||
{
|
||||
public List<string> NormalCards { get; set; } = new();
|
||||
public List<string> EndCards { get; set; } = new();
|
||||
|
||||
public ReplacedDeck Clone() => new()
|
||||
{
|
||||
NormalCards = new List<string>(NormalCards),
|
||||
EndCards = new List<string>(EndCards)
|
||||
};
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedTurnSubmission
|
||||
{
|
||||
public bool Pass { get; set; }
|
||||
public bool DiscardEndOnPass { get; set; }
|
||||
public List<string> NormalCardIds { get; set; } = new();
|
||||
public List<string> EndCardIds { get; set; } = new();
|
||||
public int RerollSlot { get; set; } = -1;
|
||||
|
||||
public ReplacedTurnSubmission Clone() => new()
|
||||
{
|
||||
Pass = Pass,
|
||||
DiscardEndOnPass = DiscardEndOnPass,
|
||||
NormalCardIds = new List<string>(NormalCardIds),
|
||||
EndCardIds = new List<string>(EndCardIds),
|
||||
RerollSlot = RerollSlot
|
||||
};
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedMatchCommand
|
||||
{
|
||||
public long Sequence { get; set; }
|
||||
public string IdempotencyToken { get; set; } = string.Empty;
|
||||
public int PlayerIndex { get; set; }
|
||||
public ReplacedTurnSubmission Submission { get; set; } = new();
|
||||
|
||||
public ReplacedMatchCommand Clone() => new()
|
||||
{
|
||||
Sequence = Sequence,
|
||||
IdempotencyToken = IdempotencyToken,
|
||||
PlayerIndex = PlayerIndex,
|
||||
Submission = Submission.Clone()
|
||||
};
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedPlayerState
|
||||
{
|
||||
public string PlayerId { get; set; } = string.Empty;
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
public int Health { get; set; } = 30;
|
||||
public int MaxHealth { get; set; } = 30;
|
||||
public int Cost { get; set; } = 10;
|
||||
public int Defense { get; set; }
|
||||
public int BonusNormalDraw { get; set; }
|
||||
public bool GuaranteedDodge { get; set; }
|
||||
public bool SkipNextEndDraw { get; set; }
|
||||
public int SpentThisRound { get; set; }
|
||||
public int EffectiveEffectsThisRound { get; set; }
|
||||
public int DamageThisRound { get; set; }
|
||||
public List<string> NormalDrawPile { get; set; } = new();
|
||||
public List<string> NormalDiscard { get; set; } = new();
|
||||
public List<string> NormalHand { get; set; } = new();
|
||||
public List<string> EndDrawPile { get; set; } = new();
|
||||
public List<string> EndDiscard { get; set; } = new();
|
||||
public List<string> EndHand { get; set; } = new();
|
||||
|
||||
public ReplacedPlayerState Clone() => new()
|
||||
{
|
||||
PlayerId = PlayerId,
|
||||
DisplayName = DisplayName,
|
||||
Health = Health,
|
||||
MaxHealth = MaxHealth,
|
||||
Cost = Cost,
|
||||
Defense = Defense,
|
||||
BonusNormalDraw = BonusNormalDraw,
|
||||
GuaranteedDodge = GuaranteedDodge,
|
||||
SkipNextEndDraw = SkipNextEndDraw,
|
||||
SpentThisRound = SpentThisRound,
|
||||
EffectiveEffectsThisRound = EffectiveEffectsThisRound,
|
||||
DamageThisRound = DamageThisRound,
|
||||
NormalDrawPile = new List<string>(NormalDrawPile),
|
||||
NormalDiscard = new List<string>(NormalDiscard),
|
||||
NormalHand = new List<string>(NormalHand),
|
||||
EndDrawPile = new List<string>(EndDrawPile),
|
||||
EndDiscard = new List<string>(EndDiscard),
|
||||
EndHand = new List<string>(EndHand)
|
||||
};
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedSlotResolution
|
||||
{
|
||||
public int SlotIndex { get; set; }
|
||||
public ReplacedEffectType PlayerOneType { get; set; }
|
||||
public ReplacedEffectType PlayerTwoType { get; set; }
|
||||
public int PlayerOneRoll { get; set; }
|
||||
public int PlayerTwoRoll { get; set; }
|
||||
public int PlayerOneValue { get; set; }
|
||||
public int PlayerTwoValue { get; set; }
|
||||
public int DamageToPlayerOne { get; set; }
|
||||
public int DamageToPlayerTwo { get; set; }
|
||||
public bool PlayerOneRerolled { get; set; }
|
||||
public bool PlayerTwoRerolled { get; set; }
|
||||
public string Summary { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedMatchState
|
||||
{
|
||||
public int Round { get; set; }
|
||||
public int LeadPlayer { get; set; }
|
||||
public int InitiativeRoll { get; set; }
|
||||
public ReplacedMatchPhase Phase { get; set; }
|
||||
public ReplacedWinner Winner { get; set; } = ReplacedWinner.None;
|
||||
public bool IsLastStand { get; set; }
|
||||
public bool LastStandUsed { get; set; }
|
||||
public ReplacedPlayerState[] Players { get; set; } = Array.Empty<ReplacedPlayerState>();
|
||||
public ReplacedTurnSubmission?[] Submissions { get; set; } = new ReplacedTurnSubmission?[2];
|
||||
public List<ReplacedSlotResolution> LastResolution { get; set; } = new();
|
||||
public List<string> Log { get; set; } = new();
|
||||
public long[] LastAcceptedSequence { get; set; } = new long[2];
|
||||
public string ContentHash { get; set; } = string.Empty;
|
||||
|
||||
public ReplacedMatchState Clone() => new()
|
||||
{
|
||||
Round = Round,
|
||||
LeadPlayer = LeadPlayer,
|
||||
InitiativeRoll = InitiativeRoll,
|
||||
Phase = Phase,
|
||||
Winner = Winner,
|
||||
IsLastStand = IsLastStand,
|
||||
LastStandUsed = LastStandUsed,
|
||||
Players = new[] { Players[0].Clone(), Players[1].Clone() },
|
||||
Submissions = new ReplacedTurnSubmission?[] { Submissions[0]?.Clone(), Submissions[1]?.Clone() },
|
||||
LastResolution = new List<ReplacedSlotResolution>(LastResolution),
|
||||
Log = new List<string>(Log),
|
||||
LastAcceptedSequence = (long[])LastAcceptedSequence.Clone(),
|
||||
ContentHash = ContentHash
|
||||
};
|
||||
}
|
||||
|
||||
public sealed class ReplacedCommandResult
|
||||
{
|
||||
public bool Accepted { get; set; }
|
||||
public bool Duplicate { get; set; }
|
||||
public string ErrorCode { get; set; } = string.Empty;
|
||||
public string Message { get; set; } = string.Empty;
|
||||
public string StateHash { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7a20d95a3133394cb808caef94ec04c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,610 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ReplacedPerson.Core
|
||||
{
|
||||
public sealed class ReplacedMatchEngine
|
||||
{
|
||||
private sealed class PreparedSlot
|
||||
{
|
||||
public ReplacedEffectType Type;
|
||||
public int BaseValue;
|
||||
public int Factor;
|
||||
public bool DrawAndRecover;
|
||||
public bool BonusDamage;
|
||||
public bool Reflect;
|
||||
public bool AddDefense;
|
||||
public bool GuaranteedDodge;
|
||||
public readonly List<string> SpecialEffects = new();
|
||||
}
|
||||
|
||||
private readonly HashSet<string> _acceptedTokens = new(StringComparer.Ordinal);
|
||||
private readonly List<ReplacedMatchCommand> _replay = new();
|
||||
|
||||
public ReplacedContentCatalog Content { get; }
|
||||
public ReplacedMatchState State { get; }
|
||||
public Pcg32 Random { get; }
|
||||
public IReadOnlyList<ReplacedMatchCommand> Replay => _replay;
|
||||
|
||||
public ReplacedMatchEngine(ReplacedContentCatalog content, ReplacedDeck playerOneDeck,
|
||||
ReplacedDeck playerTwoDeck, ulong seed, string playerOneName = "玩家", string playerTwoName = "贪婪")
|
||||
{
|
||||
Content = (content ?? throw new ArgumentNullException(nameof(content))).Clone();
|
||||
ValidateDeck(playerOneDeck, nameof(playerOneDeck));
|
||||
ValidateDeck(playerTwoDeck, nameof(playerTwoDeck));
|
||||
Random = new Pcg32(seed);
|
||||
State = new ReplacedMatchState
|
||||
{
|
||||
Round = 0,
|
||||
Players = new[]
|
||||
{
|
||||
CreatePlayer("p1", playerOneName, playerOneDeck),
|
||||
CreatePlayer("p2", playerTwoName, playerTwoDeck)
|
||||
},
|
||||
ContentHash = Content.ComputeHash()
|
||||
};
|
||||
Random.Shuffle(State.Players[0].NormalDrawPile);
|
||||
Random.Shuffle(State.Players[0].EndDrawPile);
|
||||
Random.Shuffle(State.Players[1].NormalDrawPile);
|
||||
Random.Shuffle(State.Players[1].EndDrawPile);
|
||||
BeginRound(initial: true);
|
||||
}
|
||||
|
||||
public ReplacedCommandResult Apply(ReplacedMatchCommand command)
|
||||
{
|
||||
if (command == null)
|
||||
return Reject("command.null", "指令不能为空。");
|
||||
if (State.Phase == ReplacedMatchPhase.Completed)
|
||||
return Reject("match.completed", "对局已经结束。");
|
||||
if (command.PlayerIndex is < 0 or > 1)
|
||||
return Reject("player.invalid", "玩家索引无效。");
|
||||
if (string.IsNullOrWhiteSpace(command.IdempotencyToken))
|
||||
return Reject("token.empty", "幂等令牌不能为空。");
|
||||
if (_acceptedTokens.Contains(command.IdempotencyToken))
|
||||
return new ReplacedCommandResult { Accepted = true, Duplicate = true, Message = "duplicate", StateHash = ComputeStateHash() };
|
||||
if (command.Sequence <= State.LastAcceptedSequence[command.PlayerIndex])
|
||||
return Reject("sequence.stale", "指令序号必须严格递增。");
|
||||
|
||||
var expectedPlayer = State.Phase == ReplacedMatchPhase.AwaitingLead
|
||||
? State.LeadPlayer
|
||||
: 1 - State.LeadPlayer;
|
||||
if (command.PlayerIndex != expectedPlayer)
|
||||
return Reject("turn.not-yours", "尚未轮到该玩家提交。");
|
||||
|
||||
var validation = ValidateSubmission(command.PlayerIndex, command.Submission);
|
||||
if (validation != null)
|
||||
return Reject(validation.Value.code, validation.Value.message);
|
||||
|
||||
LockSubmission(command.PlayerIndex, command.Submission);
|
||||
State.LastAcceptedSequence[command.PlayerIndex] = command.Sequence;
|
||||
_acceptedTokens.Add(command.IdempotencyToken);
|
||||
_replay.Add(command.Clone());
|
||||
State.Log.Add($"R{State.Round} {State.Players[command.PlayerIndex].DisplayName} 锁定出牌");
|
||||
|
||||
if (State.Phase == ReplacedMatchPhase.AwaitingLead)
|
||||
{
|
||||
State.Phase = ReplacedMatchPhase.AwaitingResponse;
|
||||
}
|
||||
else
|
||||
{
|
||||
State.Phase = ReplacedMatchPhase.Resolving;
|
||||
ResolveRound();
|
||||
}
|
||||
|
||||
return new ReplacedCommandResult
|
||||
{
|
||||
Accepted = true,
|
||||
Message = "accepted",
|
||||
StateHash = ComputeStateHash()
|
||||
};
|
||||
}
|
||||
|
||||
public string ComputeStateHash() => ReplacedStateHasher.Compute(State, Random);
|
||||
|
||||
private void BeginRound(bool initial)
|
||||
{
|
||||
State.Round++;
|
||||
State.Submissions = new ReplacedTurnSubmission?[2];
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
var player = State.Players[i];
|
||||
player.Defense = 0;
|
||||
player.SpentThisRound = 0;
|
||||
player.EffectiveEffectsThisRound = 0;
|
||||
player.DamageThisRound = 0;
|
||||
if (State.IsLastStand)
|
||||
{
|
||||
DiscardHands(player);
|
||||
DrawNormal(player, 4);
|
||||
DrawEnd(player, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawNormal(player, initial ? 4 : 2 + player.BonusNormalDraw);
|
||||
player.BonusNormalDraw = 0;
|
||||
if (initial || !player.SkipNextEndDraw)
|
||||
DrawEnd(player, 1);
|
||||
player.SkipNextEndDraw = false;
|
||||
}
|
||||
}
|
||||
|
||||
State.InitiativeRoll = Random.RollD6();
|
||||
State.LeadPlayer = State.InitiativeRoll % 2 == 1 ? 0 : 1;
|
||||
State.Phase = ReplacedMatchPhase.AwaitingLead;
|
||||
State.Log.Add($"R{State.Round} 先手骰={State.InitiativeRoll},{State.Players[State.LeadPlayer].DisplayName}先手");
|
||||
}
|
||||
|
||||
private (string code, string message)? ValidateSubmission(int playerIndex, ReplacedTurnSubmission? submission)
|
||||
{
|
||||
if (submission == null)
|
||||
return ("submission.null", "提交内容不能为空。");
|
||||
if (submission.RerollSlot is < -1 or > 2)
|
||||
return ("reroll.invalid", "重掷槽必须为 -1 到 2。");
|
||||
|
||||
var player = State.Players[playerIndex];
|
||||
if (submission.Pass)
|
||||
{
|
||||
if (submission.NormalCardIds.Count != 0 || submission.EndCardIds.Count != 0)
|
||||
return ("pass.with-cards", "跳过时不能同时提交卡牌。");
|
||||
return null;
|
||||
}
|
||||
|
||||
var requiredNormal = State.IsLastStand ? 4 : 1;
|
||||
var requiredEnd = State.IsLastStand ? 2 : 1;
|
||||
if (submission.NormalCardIds.Count < requiredNormal || submission.NormalCardIds.Count > 4)
|
||||
return ("normal.count", State.IsLastStand ? "孤注一掷必须提交 4 张普通牌。" : "必须提交 1 到 4 张普通牌。");
|
||||
if (submission.EndCardIds.Count != requiredEnd)
|
||||
return ("end.count", State.IsLastStand ? "孤注一掷必须提交主、副两张结束牌。" : "必须提交 1 张结束牌。");
|
||||
if (!ContainsAll(player.NormalHand, submission.NormalCardIds))
|
||||
return ("normal.not-in-hand", "普通牌不在手牌中。");
|
||||
if (!ContainsAll(player.EndHand, submission.EndCardIds))
|
||||
return ("end.not-in-hand", "结束牌不在手牌中。");
|
||||
|
||||
var cost = 0;
|
||||
foreach (var id in submission.NormalCardIds)
|
||||
{
|
||||
if (!Content.Cards.TryGetValue(id, out var card))
|
||||
return ("normal.unknown", "未知普通牌:" + id);
|
||||
cost += card.Cost;
|
||||
}
|
||||
foreach (var id in submission.EndCardIds)
|
||||
{
|
||||
if (!Content.EndCards.TryGetValue(id, out var card))
|
||||
return ("end.unknown", "未知结束牌:" + id);
|
||||
cost += card.Cost;
|
||||
}
|
||||
if (cost > player.Cost)
|
||||
return ("cost.insufficient", $"COST 不足:需要 {cost},当前 {player.Cost}。");
|
||||
return null;
|
||||
}
|
||||
|
||||
private void LockSubmission(int playerIndex, ReplacedTurnSubmission submission)
|
||||
{
|
||||
var player = State.Players[playerIndex];
|
||||
var copy = submission.Clone();
|
||||
State.Submissions[playerIndex] = copy;
|
||||
if (copy.Pass)
|
||||
{
|
||||
player.SkipNextEndDraw = true;
|
||||
if (copy.DiscardEndOnPass)
|
||||
{
|
||||
player.EndDiscard.AddRange(player.EndHand);
|
||||
player.EndHand.Clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var spent = 0;
|
||||
foreach (var id in copy.NormalCardIds)
|
||||
{
|
||||
player.NormalHand.Remove(id);
|
||||
spent += Content.Cards[id].Cost;
|
||||
}
|
||||
foreach (var id in copy.EndCardIds)
|
||||
{
|
||||
player.EndHand.Remove(id);
|
||||
spent += Content.EndCards[id].Cost;
|
||||
}
|
||||
player.Cost -= spent;
|
||||
player.SpentThisRound = spent;
|
||||
}
|
||||
|
||||
private void ResolveRound()
|
||||
{
|
||||
State.LastResolution.Clear();
|
||||
var prepared = new[]
|
||||
{
|
||||
PrepareSlots(State.Submissions[0]),
|
||||
PrepareSlots(State.Submissions[1])
|
||||
};
|
||||
|
||||
for (var slotIndex = 0; slotIndex < 3; slotIndex++)
|
||||
ResolveSlot(slotIndex, prepared[0][slotIndex], prepared[1][slotIndex]);
|
||||
|
||||
ApplyRoundRecoveryAndDiscard();
|
||||
if (State.IsLastStand)
|
||||
{
|
||||
CompleteLastStand();
|
||||
return;
|
||||
}
|
||||
|
||||
var oneDead = State.Players[0].Health <= 0;
|
||||
var twoDead = State.Players[1].Health <= 0;
|
||||
if (oneDead && twoDead && !State.LastStandUsed)
|
||||
{
|
||||
State.LastStandUsed = true;
|
||||
State.IsLastStand = true;
|
||||
State.Players[0].Health = 1;
|
||||
State.Players[1].Health = 1;
|
||||
State.Log.Add("双方同时归零,进入孤注一掷");
|
||||
BeginRound(initial: false);
|
||||
return;
|
||||
}
|
||||
if (oneDead || twoDead)
|
||||
{
|
||||
Complete(oneDead ? ReplacedWinner.PlayerTwo : ReplacedWinner.PlayerOne);
|
||||
return;
|
||||
}
|
||||
BeginRound(initial: false);
|
||||
}
|
||||
|
||||
private PreparedSlot?[] PrepareSlots(ReplacedTurnSubmission? submission)
|
||||
{
|
||||
var result = new PreparedSlot?[3];
|
||||
if (submission == null || submission.Pass)
|
||||
return result;
|
||||
var primaryEnd = Content.EndCards[submission.EndCardIds[0]];
|
||||
for (var i = 0; i < submission.NormalCardIds.Count; i++)
|
||||
{
|
||||
var card = Content.Cards[submission.NormalCardIds[i]];
|
||||
var slot = Math.Min(i, 2);
|
||||
var next = new PreparedSlot
|
||||
{
|
||||
Type = card.EffectType,
|
||||
BaseValue = card.BaseValue,
|
||||
Factor = card.Factor
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(card.SpecialEffectId))
|
||||
next.SpecialEffects.Add(card.SpecialEffectId);
|
||||
result[slot] = result[slot] == null ? next : Fuse(result[slot]!, next);
|
||||
}
|
||||
|
||||
for (var i = 0; i < result.Length; i++)
|
||||
{
|
||||
if (result[i] == null)
|
||||
continue;
|
||||
result[i]!.BaseValue += primaryEnd.SlotBase[i];
|
||||
result[i]!.Factor += primaryEnd.SlotFactor[i];
|
||||
}
|
||||
|
||||
if (State.IsLastStand && submission.EndCardIds.Count > 1 && result[0] != null)
|
||||
{
|
||||
var secondary = Content.EndCards[submission.EndCardIds[1]];
|
||||
result[0]!.BaseValue += secondary.SlotBase[0];
|
||||
result[0]!.Factor += secondary.SlotFactor[0];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static PreparedSlot Fuse(PreparedSlot left, PreparedSlot right)
|
||||
{
|
||||
var result = new PreparedSlot
|
||||
{
|
||||
Type = left.Type == ReplacedEffectType.Attack || right.Type == ReplacedEffectType.Attack
|
||||
? ReplacedEffectType.Attack
|
||||
: left.Type == ReplacedEffectType.Counter || right.Type == ReplacedEffectType.Counter
|
||||
? ReplacedEffectType.Counter
|
||||
: ReplacedEffectType.Dodge,
|
||||
BaseValue = left.BaseValue + right.BaseValue,
|
||||
Factor = left.Factor + right.Factor,
|
||||
DrawAndRecover = left.DrawAndRecover || right.DrawAndRecover,
|
||||
BonusDamage = left.BonusDamage || right.BonusDamage,
|
||||
Reflect = left.Reflect || right.Reflect,
|
||||
AddDefense = left.AddDefense || right.AddDefense,
|
||||
GuaranteedDodge = left.GuaranteedDodge || right.GuaranteedDodge
|
||||
};
|
||||
result.SpecialEffects.AddRange(left.SpecialEffects);
|
||||
result.SpecialEffects.AddRange(right.SpecialEffects);
|
||||
|
||||
var a = left.Type;
|
||||
var b = right.Type;
|
||||
if (a == ReplacedEffectType.Attack && b == ReplacedEffectType.Attack)
|
||||
{
|
||||
result.BaseValue = (int)Math.Round(result.BaseValue * 1.5, MidpointRounding.AwayFromZero);
|
||||
result.Factor = (int)Math.Round(result.Factor * 1.5, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
else if (IsPair(a, b, ReplacedEffectType.Attack, ReplacedEffectType.Dodge)) result.DrawAndRecover = true;
|
||||
else if (IsPair(a, b, ReplacedEffectType.Attack, ReplacedEffectType.Counter)) result.BonusDamage = true;
|
||||
else if (a == ReplacedEffectType.Counter && b == ReplacedEffectType.Counter) result.Reflect = true;
|
||||
else if (IsPair(a, b, ReplacedEffectType.Dodge, ReplacedEffectType.Counter)) result.AddDefense = true;
|
||||
else if (a == ReplacedEffectType.Dodge && b == ReplacedEffectType.Dodge) result.GuaranteedDodge = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void ResolveSlot(int slotIndex, PreparedSlot? one, PreparedSlot? two)
|
||||
{
|
||||
if (one == null && two == null)
|
||||
return;
|
||||
var submissionOne = State.Submissions[0]!;
|
||||
var submissionTwo = State.Submissions[1]!;
|
||||
var oneRerolled = false;
|
||||
var twoRerolled = false;
|
||||
var oneRoll = one == null ? 0 : RollWithMarkedReroll(submissionOne, slotIndex, out oneRerolled);
|
||||
var twoRoll = two == null ? 0 : RollWithMarkedReroll(submissionTwo, slotIndex, out twoRerolled);
|
||||
var oneValue = one == null ? 0 : one.BaseValue + one.Factor * oneRoll;
|
||||
var twoValue = two == null ? 0 : two.BaseValue + two.Factor * twoRoll;
|
||||
var tieGuard = 0;
|
||||
while (one != null && two != null && oneValue == twoValue && tieGuard++ < 32)
|
||||
{
|
||||
oneRoll = Random.RollD6();
|
||||
twoRoll = Random.RollD6();
|
||||
oneValue = one.BaseValue + one.Factor * oneRoll;
|
||||
twoValue = two.BaseValue + two.Factor * twoRoll;
|
||||
}
|
||||
|
||||
var resolution = new ReplacedSlotResolution
|
||||
{
|
||||
SlotIndex = slotIndex,
|
||||
PlayerOneType = one?.Type ?? ReplacedEffectType.Dodge,
|
||||
PlayerTwoType = two?.Type ?? ReplacedEffectType.Dodge,
|
||||
PlayerOneRoll = oneRoll,
|
||||
PlayerTwoRoll = twoRoll,
|
||||
PlayerOneValue = oneValue,
|
||||
PlayerTwoValue = twoValue,
|
||||
PlayerOneRerolled = oneRerolled,
|
||||
PlayerTwoRerolled = twoRerolled
|
||||
};
|
||||
|
||||
if (one == null)
|
||||
ApplyUnopposed(1, two!, twoValue, resolution);
|
||||
else if (two == null)
|
||||
ApplyUnopposed(0, one, oneValue, resolution);
|
||||
else if (oneValue == twoValue)
|
||||
resolution.Summary = "连续平点,槽位无效";
|
||||
else
|
||||
ApplyOpposed(oneValue > twoValue ? 0 : 1, one, two, oneValue, twoValue, resolution);
|
||||
|
||||
State.LastResolution.Add(resolution);
|
||||
State.Log.Add($"槽{slotIndex + 1}: {resolution.Summary}");
|
||||
}
|
||||
|
||||
private void ApplyUnopposed(int owner, PreparedSlot slot, int value, ReplacedSlotResolution resolution)
|
||||
{
|
||||
if (slot.Type == ReplacedEffectType.Attack)
|
||||
{
|
||||
var damage = Math.Min(8, value);
|
||||
DealDamage(owner, 1 - owner, damage, resolution);
|
||||
ApplySuccess(owner, slot, resolution);
|
||||
resolution.Summary = $"{State.Players[owner].DisplayName} 无对位进攻 {damage}";
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplySuccess(owner, slot, resolution);
|
||||
resolution.Summary = $"{State.Players[owner].DisplayName} 无对位效果发动";
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyOpposed(int winner, PreparedSlot one, PreparedSlot two, int oneValue, int twoValue,
|
||||
ReplacedSlotResolution resolution)
|
||||
{
|
||||
var loser = 1 - winner;
|
||||
var winSlot = winner == 0 ? one : two;
|
||||
var loseSlot = winner == 0 ? two : one;
|
||||
var difference = Math.Abs(oneValue - twoValue);
|
||||
|
||||
if (winSlot.Type == ReplacedEffectType.Attack)
|
||||
{
|
||||
if (loseSlot.Type == ReplacedEffectType.Dodge && State.Players[loser].GuaranteedDodge)
|
||||
{
|
||||
State.Players[loser].GuaranteedDodge = false;
|
||||
resolution.Summary = $"{State.Players[loser].DisplayName} 消耗必定闪避";
|
||||
return;
|
||||
}
|
||||
var damage = Math.Min(8, difference);
|
||||
DealDamage(winner, loser, damage, resolution);
|
||||
ApplySuccess(winner, winSlot, resolution);
|
||||
resolution.Summary = $"{State.Players[winner].DisplayName} 进攻胜出 {damage}";
|
||||
return;
|
||||
}
|
||||
|
||||
if (winSlot.Type == ReplacedEffectType.Counter && loseSlot.Type == ReplacedEffectType.Attack)
|
||||
{
|
||||
var damage = Math.Min(6, difference);
|
||||
DealDamage(winner, loser, damage, resolution);
|
||||
ApplySuccess(winner, winSlot, resolution);
|
||||
resolution.Summary = $"{State.Players[winner].DisplayName} 反击 {damage}";
|
||||
return;
|
||||
}
|
||||
|
||||
if (winSlot.Type == ReplacedEffectType.Dodge && loseSlot.Type == ReplacedEffectType.Attack)
|
||||
{
|
||||
State.Players[winner].BonusNormalDraw++;
|
||||
ApplySuccess(winner, winSlot, resolution);
|
||||
resolution.Summary = $"{State.Players[winner].DisplayName} 闪避并获得额外抽牌";
|
||||
return;
|
||||
}
|
||||
|
||||
ApplySuccess(winner, winSlot, resolution);
|
||||
resolution.Summary = $"{State.Players[winner].DisplayName} 对位胜出";
|
||||
}
|
||||
|
||||
private void ApplySuccess(int owner, PreparedSlot slot, ReplacedSlotResolution resolution)
|
||||
{
|
||||
var player = State.Players[owner];
|
||||
player.EffectiveEffectsThisRound++;
|
||||
if (slot.DrawAndRecover)
|
||||
{
|
||||
DrawNormal(player, 1);
|
||||
player.Cost = Math.Min(10, player.Cost + 1);
|
||||
}
|
||||
if (slot.BonusDamage)
|
||||
DealDamage(owner, 1 - owner, 3, resolution);
|
||||
if (slot.AddDefense)
|
||||
player.Defense += 2;
|
||||
if (slot.GuaranteedDodge)
|
||||
player.GuaranteedDodge = true;
|
||||
if (slot.Reflect && player.DamageThisRound > 0)
|
||||
DealDamage(owner, 1 - owner, Math.Min(5, (int)Math.Ceiling(player.DamageThisRound * 0.5)), resolution);
|
||||
|
||||
foreach (var special in slot.SpecialEffects)
|
||||
{
|
||||
switch (special)
|
||||
{
|
||||
case "greed.draw": DrawNormal(player, 1); break;
|
||||
case "greed.refund": player.Cost = Math.Min(10, player.Cost + 1); break;
|
||||
case "greed.wage-cut": State.Players[1 - owner].Cost = Math.Max(0, State.Players[1 - owner].Cost - 2); break;
|
||||
default:
|
||||
if (Content.EffectResolvers.TryGetValue(special, out var resolver))
|
||||
{
|
||||
var effectResult = resolver.Resolve(new ReplacedEffectContext
|
||||
{
|
||||
EffectId = special,
|
||||
OwnerIndex = owner,
|
||||
State = State,
|
||||
Value = 0
|
||||
});
|
||||
player.Cost = Math.Min(10, Math.Max(0, player.Cost + effectResult.CostDelta));
|
||||
DrawNormal(player, Math.Max(0, effectResult.DrawDelta));
|
||||
if (effectResult.BonusDamage > 0) DealDamage(owner, 1 - owner, effectResult.BonusDamage, resolution);
|
||||
if (!string.IsNullOrWhiteSpace(effectResult.Log)) State.Log.Add(effectResult.Log);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DealDamage(int source, int target, int amount, ReplacedSlotResolution resolution)
|
||||
{
|
||||
if (amount <= 0) return;
|
||||
var targetState = State.Players[target];
|
||||
var afterDefense = Math.Max(0, amount - targetState.Defense);
|
||||
if (State.IsLastStand)
|
||||
{
|
||||
State.Players[source].DamageThisRound += afterDefense;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetState.Health -= afterDefense;
|
||||
State.Players[source].DamageThisRound += afterDefense;
|
||||
}
|
||||
if (target == 0) resolution.DamageToPlayerOne += afterDefense;
|
||||
else resolution.DamageToPlayerTwo += afterDefense;
|
||||
}
|
||||
|
||||
private int RollWithMarkedReroll(ReplacedTurnSubmission submission, int slotIndex, out bool rerolled)
|
||||
{
|
||||
var roll = Random.RollD6();
|
||||
rerolled = submission.RerollSlot == slotIndex && roll <= 2;
|
||||
return rerolled ? Random.RollD6() : roll;
|
||||
}
|
||||
|
||||
private void ApplyRoundRecoveryAndDiscard()
|
||||
{
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
var player = State.Players[i];
|
||||
player.Cost = Math.Min(10, player.Cost + 1 + player.SpentThisRound / 2);
|
||||
var submission = State.Submissions[i];
|
||||
if (submission == null || submission.Pass) continue;
|
||||
player.NormalDiscard.AddRange(submission.NormalCardIds);
|
||||
player.EndDiscard.AddRange(submission.EndCardIds);
|
||||
}
|
||||
}
|
||||
|
||||
private void CompleteLastStand()
|
||||
{
|
||||
var first = State.Players[0];
|
||||
var second = State.Players[1];
|
||||
if (first.DamageThisRound != second.DamageThisRound)
|
||||
Complete(first.DamageThisRound > second.DamageThisRound ? ReplacedWinner.PlayerOne : ReplacedWinner.PlayerTwo);
|
||||
else if (first.EffectiveEffectsThisRound != second.EffectiveEffectsThisRound)
|
||||
Complete(first.EffectiveEffectsThisRound > second.EffectiveEffectsThisRound ? ReplacedWinner.PlayerOne : ReplacedWinner.PlayerTwo);
|
||||
else
|
||||
Complete(Random.RollD6() % 2 == 1 ? ReplacedWinner.PlayerOne : ReplacedWinner.PlayerTwo);
|
||||
}
|
||||
|
||||
private void Complete(ReplacedWinner winner)
|
||||
{
|
||||
State.Winner = winner;
|
||||
State.Phase = ReplacedMatchPhase.Completed;
|
||||
State.Log.Add("对局结束:" + winner);
|
||||
}
|
||||
|
||||
private void DrawNormal(ReplacedPlayerState player, int count)
|
||||
{
|
||||
for (var i = 0; i < count && player.NormalHand.Count < 9; i++)
|
||||
{
|
||||
RecycleIfNeeded(player.NormalDrawPile, player.NormalDiscard);
|
||||
if (player.NormalDrawPile.Count == 0) return;
|
||||
var last = player.NormalDrawPile.Count - 1;
|
||||
player.NormalHand.Add(player.NormalDrawPile[last]);
|
||||
player.NormalDrawPile.RemoveAt(last);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEnd(ReplacedPlayerState player, int count)
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
RecycleIfNeeded(player.EndDrawPile, player.EndDiscard);
|
||||
if (player.EndDrawPile.Count == 0) return;
|
||||
var last = player.EndDrawPile.Count - 1;
|
||||
player.EndHand.Add(player.EndDrawPile[last]);
|
||||
player.EndDrawPile.RemoveAt(last);
|
||||
}
|
||||
}
|
||||
|
||||
private void RecycleIfNeeded(List<string> draw, List<string> discard)
|
||||
{
|
||||
if (draw.Count > 0 || discard.Count == 0) return;
|
||||
draw.AddRange(discard);
|
||||
discard.Clear();
|
||||
Random.Shuffle(draw);
|
||||
}
|
||||
|
||||
private static bool ContainsAll(List<string> hand, List<string> requested)
|
||||
{
|
||||
var available = new List<string>(hand);
|
||||
foreach (var id in requested)
|
||||
if (!available.Remove(id)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsPair(ReplacedEffectType a, ReplacedEffectType b, ReplacedEffectType x, ReplacedEffectType y) =>
|
||||
(a == x && b == y) || (a == y && b == x);
|
||||
|
||||
private static ReplacedPlayerState CreatePlayer(string id, string name, ReplacedDeck deck) => new()
|
||||
{
|
||||
PlayerId = id,
|
||||
DisplayName = name,
|
||||
NormalDrawPile = new List<string>(deck.NormalCards),
|
||||
EndDrawPile = new List<string>(deck.EndCards)
|
||||
};
|
||||
|
||||
private void ValidateDeck(ReplacedDeck deck, string parameter)
|
||||
{
|
||||
var errors = ReplacedDeckValidator.Validate(deck, Content);
|
||||
if (errors.Count > 0)
|
||||
throw new ArgumentException(string.Join(", ", errors), parameter);
|
||||
}
|
||||
|
||||
private static void DiscardHands(ReplacedPlayerState player)
|
||||
{
|
||||
player.NormalDiscard.AddRange(player.NormalHand);
|
||||
player.NormalHand.Clear();
|
||||
player.EndDiscard.AddRange(player.EndHand);
|
||||
player.EndHand.Clear();
|
||||
}
|
||||
|
||||
private ReplacedCommandResult Reject(string code, string message) => new()
|
||||
{
|
||||
Accepted = false,
|
||||
ErrorCode = code,
|
||||
Message = message,
|
||||
StateHash = ComputeStateHash()
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47d95b984ad7b2546856f977713e4853
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,169 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace ReplacedPerson.Core
|
||||
{
|
||||
public interface IReplacedPersonMod
|
||||
{
|
||||
string Id { get; }
|
||||
string Version { get; }
|
||||
void Register(IReplacedPersonRegistry registry);
|
||||
}
|
||||
|
||||
public interface IReplacedPersonRegistry
|
||||
{
|
||||
void RegisterCard(ReplacedCardDefinition definition);
|
||||
void RegisterEndCard(ReplacedEndCardDefinition definition);
|
||||
void RegisterEnemy(ReplacedEnemyDefinition definition);
|
||||
void RegisterReward(string id, string displayName);
|
||||
void RegisterStory(string id, string title, string body);
|
||||
void RegisterEffectResolver(string effectId, IReplacedPersonEffectResolver resolver);
|
||||
void RegisterCommand(string path, Func<IReadOnlyList<string>, string> handler);
|
||||
}
|
||||
|
||||
public interface IReplacedPersonEffectResolver
|
||||
{
|
||||
ReplacedEffectResult Resolve(ReplacedEffectContext context);
|
||||
}
|
||||
|
||||
public sealed class ReplacedEffectContext
|
||||
{
|
||||
public string EffectId { get; set; } = string.Empty;
|
||||
public int OwnerIndex { get; set; }
|
||||
public int OpponentIndex => 1 - OwnerIndex;
|
||||
public int Value { get; set; }
|
||||
public ReplacedMatchState State { get; set; } = null!;
|
||||
}
|
||||
|
||||
public sealed class ReplacedEffectResult
|
||||
{
|
||||
public int BonusDamage { get; set; }
|
||||
public int CostDelta { get; set; }
|
||||
public int DrawDelta { get; set; }
|
||||
public string Log { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedPersonModFile
|
||||
{
|
||||
public string Path { get; set; } = string.Empty;
|
||||
public string Sha256 { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedPersonModManifest
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Version { get; set; } = string.Empty;
|
||||
public List<ReplacedPersonModFile> Files { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class ReplacedModCompatibilityResult
|
||||
{
|
||||
public bool Compatible => Differences.Count == 0;
|
||||
public List<string> Differences { get; } = new();
|
||||
}
|
||||
|
||||
public static class ReplacedModCompatibility
|
||||
{
|
||||
public static ReplacedModCompatibilityResult Compare(IEnumerable<ReplacedPersonModManifest> authority,
|
||||
IEnumerable<ReplacedPersonModManifest> client)
|
||||
{
|
||||
var result = new ReplacedModCompatibilityResult();
|
||||
var expected = authority.ToDictionary(value => value.Id, StringComparer.Ordinal);
|
||||
var actual = client.ToDictionary(value => value.Id, StringComparer.Ordinal);
|
||||
foreach (var id in expected.Keys.Union(actual.Keys, StringComparer.Ordinal).OrderBy(value => value, StringComparer.Ordinal))
|
||||
{
|
||||
if (!expected.TryGetValue(id, out var expectedMod)) { result.Differences.Add("unexpected-mod:" + id); continue; }
|
||||
if (!actual.TryGetValue(id, out var actualMod)) { result.Differences.Add("missing-mod:" + id); continue; }
|
||||
if (!string.Equals(expectedMod.Version, actualMod.Version, StringComparison.Ordinal))
|
||||
result.Differences.Add($"version:{id}:{expectedMod.Version}!={actualMod.Version}");
|
||||
CompareFiles(id, expectedMod.Files, actualMod.Files, result.Differences);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string ComputeManifestSetHash(IEnumerable<ReplacedPersonModManifest> manifests)
|
||||
{
|
||||
var text = new StringBuilder();
|
||||
foreach (var manifest in manifests.OrderBy(value => value.Id, StringComparer.Ordinal))
|
||||
{
|
||||
text.Append(manifest.Id).Append('|').Append(manifest.Version).Append('\n');
|
||||
foreach (var file in manifest.Files.OrderBy(value => value.Path, StringComparer.Ordinal))
|
||||
text.Append(file.Path).Append('|').Append(file.Sha256.ToLowerInvariant()).Append('\n');
|
||||
}
|
||||
using var sha = SHA256.Create();
|
||||
var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(text.ToString()));
|
||||
return string.Concat(bytes.Select(value => value.ToString("x2")));
|
||||
}
|
||||
|
||||
private static void CompareFiles(string modId, IEnumerable<ReplacedPersonModFile> expected,
|
||||
IEnumerable<ReplacedPersonModFile> actual, ICollection<string> differences)
|
||||
{
|
||||
var expectedFiles = expected.ToDictionary(value => value.Path, StringComparer.Ordinal);
|
||||
var actualFiles = actual.ToDictionary(value => value.Path, StringComparer.Ordinal);
|
||||
foreach (var path in expectedFiles.Keys.Union(actualFiles.Keys, StringComparer.Ordinal).OrderBy(value => value, StringComparer.Ordinal))
|
||||
{
|
||||
if (!expectedFiles.TryGetValue(path, out var expectedFile)) { differences.Add($"unexpected-file:{modId}:{path}"); continue; }
|
||||
if (!actualFiles.TryGetValue(path, out var actualFile)) { differences.Add($"missing-file:{modId}:{path}"); continue; }
|
||||
if (!string.Equals(expectedFile.Sha256, actualFile.Sha256, StringComparison.OrdinalIgnoreCase))
|
||||
differences.Add($"hash:{modId}:{path}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ReplacedPersonRegistry : IReplacedPersonRegistry
|
||||
{
|
||||
private readonly ReplacedContentCatalog _catalog;
|
||||
private readonly Dictionary<string, string> _rewards = new(StringComparer.Ordinal);
|
||||
private readonly Dictionary<string, (string title, string body)> _stories = new(StringComparer.Ordinal);
|
||||
private readonly Dictionary<string, IReplacedPersonEffectResolver> _effects = new(StringComparer.Ordinal);
|
||||
private readonly Dictionary<string, Func<IReadOnlyList<string>, string>> _commands = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public ReplacedPersonRegistry(ReplacedContentCatalog baseCatalog) => _catalog = baseCatalog.Clone();
|
||||
public ReplacedContentCatalog CreateSnapshot() => _catalog.Clone();
|
||||
public IReadOnlyDictionary<string, IReplacedPersonEffectResolver> Effects => _effects;
|
||||
public IReadOnlyDictionary<string, Func<IReadOnlyList<string>, string>> Commands => _commands;
|
||||
|
||||
public void RegisterCard(ReplacedCardDefinition definition) => AddUnique(_catalog.Cards, definition.Id, definition);
|
||||
public void RegisterEndCard(ReplacedEndCardDefinition definition) => AddUnique(_catalog.EndCards, definition.Id, definition);
|
||||
public void RegisterEnemy(ReplacedEnemyDefinition definition) => AddUnique(_catalog.Enemies, definition.Id, definition);
|
||||
public void RegisterReward(string id, string displayName) => AddUnique(_rewards, id, displayName);
|
||||
public void RegisterStory(string id, string title, string body) => AddUnique(_stories, id, (title, body));
|
||||
public void RegisterEffectResolver(string effectId, IReplacedPersonEffectResolver resolver)
|
||||
{
|
||||
AddUnique(_effects, effectId, resolver);
|
||||
AddUnique(_catalog.EffectResolvers, effectId, resolver);
|
||||
}
|
||||
public void RegisterCommand(string path, Func<IReadOnlyList<string>, string> handler) => AddUnique(_commands, path, handler);
|
||||
|
||||
private static void AddUnique<T>(IDictionary<string, T> target, string id, T value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id)) throw new ArgumentException("Registry id must not be empty.", nameof(id));
|
||||
var key = id.Trim();
|
||||
if (target.ContainsKey(key)) throw new InvalidOperationException("Duplicate registry id: " + id);
|
||||
target.Add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ReplacedHotReloadCatalog
|
||||
{
|
||||
public ReplacedContentCatalog Current { get; private set; }
|
||||
public ReplacedContentCatalog? Pending { get; private set; }
|
||||
public string CurrentHash => Current.ComputeHash();
|
||||
public string PendingHash => Pending?.ComputeHash() ?? string.Empty;
|
||||
|
||||
public ReplacedHotReloadCatalog(ReplacedContentCatalog initial) => Current = initial.Clone();
|
||||
public void Stage(ReplacedContentCatalog next) => Pending = next.Clone();
|
||||
public ReplacedContentCatalog SnapshotForNewMatch()
|
||||
{
|
||||
if (Pending != null) { Current = Pending; Pending = null; }
|
||||
return Current.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf4213a9a53d2c74a917cdd129f062ed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,272 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ReplacedPerson.Core
|
||||
{
|
||||
public enum ReplacedNetworkMessageKind
|
||||
{
|
||||
Join = 0,
|
||||
Create = 1,
|
||||
Ready = 2,
|
||||
Deck = 3,
|
||||
MatchCommand = 4,
|
||||
MatchSnapshot = 5,
|
||||
MatchEvent = 6,
|
||||
Reconnect = 7,
|
||||
Error = 8
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedNetworkEnvelope
|
||||
{
|
||||
public ReplacedNetworkMessageKind Kind { get; set; }
|
||||
public long Sequence { get; set; }
|
||||
public string IdempotencyToken { get; set; } = string.Empty;
|
||||
public string RoomId { get; set; } = string.Empty;
|
||||
public string PlayerId { get; set; } = string.Empty;
|
||||
public string Payload { get; set; } = string.Empty;
|
||||
public string StateHash { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedJoinRequest
|
||||
{
|
||||
public string RoomId { get; set; } = string.Empty;
|
||||
public string PlayerId { get; set; } = string.Empty;
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
public List<ReplacedPersonModManifest> Mods { get; set; } = new();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedRoomSnapshot
|
||||
{
|
||||
public string RoomId { get; set; } = string.Empty;
|
||||
public string ContentHash { get; set; } = string.Empty;
|
||||
public List<string> Players { get; set; } = new();
|
||||
public List<string> ReadyPlayers { get; set; } = new();
|
||||
public bool MatchStarted { get; set; }
|
||||
public string MatchStateHash { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedReadyRequest
|
||||
{
|
||||
public bool Ready { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedMatchSnapshotPayload
|
||||
{
|
||||
public ReplacedRoomSnapshot Room { get; set; } = new();
|
||||
public ReplacedMatchState? Match { get; set; }
|
||||
public int LocalPlayerIndex { get; set; } = -1;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class ReplacedNetworkResultPayload
|
||||
{
|
||||
public bool Accepted { get; set; }
|
||||
public bool Duplicate { get; set; }
|
||||
public string Code { get; set; } = string.Empty;
|
||||
public string Detail { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public sealed class ReplacedRoomSeat
|
||||
{
|
||||
public string PlayerId { get; set; } = string.Empty;
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
public ReplacedDeck? Deck { get; set; }
|
||||
public bool Ready { get; set; }
|
||||
public bool Connected { get; set; } = true;
|
||||
public DateTime ReservedUntilUtc { get; set; }
|
||||
public int ConsecutiveTimeouts { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ReplacedRoomAuthority
|
||||
{
|
||||
private readonly ReplacedContentCatalog _content;
|
||||
private readonly List<ReplacedPersonModManifest> _mods;
|
||||
private readonly ReplacedRoomSeat?[] _seats = new ReplacedRoomSeat?[2];
|
||||
private readonly ulong _seed;
|
||||
|
||||
public string RoomId { get; }
|
||||
public ReplacedMatchEngine? Match { get; private set; }
|
||||
public IReadOnlyList<ReplacedRoomSeat?> Seats => _seats;
|
||||
|
||||
public ReplacedRoomAuthority(string roomId, ReplacedContentCatalog content,
|
||||
IEnumerable<ReplacedPersonModManifest> mods, ulong seed)
|
||||
{
|
||||
RoomId = roomId;
|
||||
_content = content.Clone();
|
||||
_mods = new List<ReplacedPersonModManifest>(mods);
|
||||
_seed = seed;
|
||||
}
|
||||
|
||||
public ReplacedModCompatibilityResult TryJoin(ReplacedJoinRequest request, DateTime nowUtc)
|
||||
{
|
||||
var compatibility = ReplacedModCompatibility.Compare(_mods, request.Mods);
|
||||
if (!compatibility.Compatible) return compatibility;
|
||||
for (var i = 0; i < _seats.Length; i++)
|
||||
{
|
||||
if (_seats[i]?.PlayerId == request.PlayerId)
|
||||
{
|
||||
_seats[i]!.Connected = true;
|
||||
_seats[i]!.ReservedUntilUtc = nowUtc.AddSeconds(30);
|
||||
return compatibility;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < _seats.Length; i++)
|
||||
{
|
||||
if (_seats[i] == null || (!_seats[i]!.Connected && _seats[i]!.ReservedUntilUtc <= nowUtc))
|
||||
{
|
||||
_seats[i] = new ReplacedRoomSeat
|
||||
{
|
||||
PlayerId = request.PlayerId,
|
||||
DisplayName = request.DisplayName,
|
||||
Connected = true,
|
||||
ReservedUntilUtc = nowUtc.AddSeconds(30)
|
||||
};
|
||||
return compatibility;
|
||||
}
|
||||
}
|
||||
compatibility.Differences.Add("room.full");
|
||||
return compatibility;
|
||||
}
|
||||
|
||||
public string SetDeck(string playerId, ReplacedDeck deck)
|
||||
{
|
||||
var seat = FindSeat(playerId);
|
||||
var errors = ReplacedDeckValidator.Validate(deck, _content);
|
||||
if (errors.Count > 0) return string.Join(",", errors);
|
||||
seat.Deck = deck.Clone();
|
||||
seat.Ready = false;
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string SetReady(string playerId, bool ready)
|
||||
{
|
||||
var seat = FindSeat(playerId);
|
||||
if (ready && seat.Deck == null) return "deck.missing";
|
||||
seat.Ready = ready;
|
||||
if (Match == null && _seats[0]?.Ready == true && _seats[1]?.Ready == true)
|
||||
Match = new ReplacedMatchEngine(_content, _seats[0]!.Deck!, _seats[1]!.Deck!, _seed,
|
||||
_seats[0]!.DisplayName, _seats[1]!.DisplayName);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string SetDeckAndReady(string playerId, ReplacedDeck deck)
|
||||
{
|
||||
var error = SetDeck(playerId, deck);
|
||||
return string.IsNullOrEmpty(error) ? SetReady(playerId, true) : error;
|
||||
}
|
||||
|
||||
public ReplacedCommandResult Apply(string playerId, ReplacedMatchCommand command)
|
||||
{
|
||||
if (Match == null) return new ReplacedCommandResult { ErrorCode = "match.not-started", Message = "match.not-started" };
|
||||
var index = _seats[0]?.PlayerId == playerId ? 0 : _seats[1]?.PlayerId == playerId ? 1 : -1;
|
||||
if (index < 0) return new ReplacedCommandResult { ErrorCode = "player.not-seated", Message = "player.not-seated" };
|
||||
command.PlayerIndex = index;
|
||||
return Match.Apply(command);
|
||||
}
|
||||
|
||||
public void Disconnect(string playerId, DateTime nowUtc)
|
||||
{
|
||||
var seat = FindSeat(playerId);
|
||||
seat.Connected = false;
|
||||
seat.ReservedUntilUtc = nowUtc.AddSeconds(30);
|
||||
}
|
||||
|
||||
public void RecordTurnTimeout(string playerId)
|
||||
{
|
||||
var seat = FindSeat(playerId);
|
||||
seat.ConsecutiveTimeouts++;
|
||||
if (seat.ConsecutiveTimeouts >= 2 && Match != null && Match.State.Phase != ReplacedMatchPhase.Completed)
|
||||
{
|
||||
Match.State.Winner = ReferenceEquals(seat, _seats[0]) ? ReplacedWinner.PlayerTwo : ReplacedWinner.PlayerOne;
|
||||
Match.State.Phase = ReplacedMatchPhase.Completed;
|
||||
Match.State.Log.Add("连续两个回合超时判负");
|
||||
}
|
||||
}
|
||||
|
||||
public bool Kick(string playerId)
|
||||
{
|
||||
for (var i = 0; i < _seats.Length; i++)
|
||||
{
|
||||
if (_seats[i]?.PlayerId != playerId) continue;
|
||||
_seats[i] = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetPlayerIndex(string playerId)
|
||||
{
|
||||
if (_seats[0]?.PlayerId == playerId) return 0;
|
||||
if (_seats[1]?.PlayerId == playerId) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public ReplacedMatchState? PlayerMatchSnapshot(string playerId)
|
||||
{
|
||||
if (Match == null) return null;
|
||||
var playerIndex = GetPlayerIndex(playerId);
|
||||
if (playerIndex < 0) return null;
|
||||
var snapshot = Match.State.Clone();
|
||||
var opponent = snapshot.Players[1 - playerIndex];
|
||||
opponent.NormalHand = HiddenCards(opponent.NormalHand.Count);
|
||||
opponent.EndHand = HiddenCards(opponent.EndHand.Count);
|
||||
opponent.NormalDrawPile = HiddenCards(opponent.NormalDrawPile.Count);
|
||||
opponent.EndDrawPile = HiddenCards(opponent.EndDrawPile.Count);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
public ReplacedRoomSnapshot Snapshot()
|
||||
{
|
||||
var result = new ReplacedRoomSnapshot
|
||||
{
|
||||
RoomId = RoomId,
|
||||
ContentHash = _content.ComputeHash(),
|
||||
MatchStarted = Match != null,
|
||||
MatchStateHash = Match?.ComputeStateHash() ?? string.Empty
|
||||
};
|
||||
foreach (var seat in _seats)
|
||||
{
|
||||
if (seat == null) continue;
|
||||
result.Players.Add(seat.PlayerId);
|
||||
if (seat.Ready) result.ReadyPlayers.Add(seat.PlayerId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private ReplacedRoomSeat FindSeat(string playerId)
|
||||
{
|
||||
foreach (var seat in _seats)
|
||||
if (seat?.PlayerId == playerId) return seat;
|
||||
throw new InvalidOperationException("Player is not seated: " + playerId);
|
||||
}
|
||||
|
||||
private static List<string> HiddenCards(int count)
|
||||
{
|
||||
var result = new List<string>(count);
|
||||
for (var i = 0; i < count; i++) result.Add(string.Empty);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ReplacedReplayRunner
|
||||
{
|
||||
public static ReplacedMatchEngine Replay(ReplacedContentCatalog content, ReplacedDeck first, ReplacedDeck second,
|
||||
ulong seed, IEnumerable<ReplacedMatchCommand> commands)
|
||||
{
|
||||
var engine = new ReplacedMatchEngine(content, first, second, seed);
|
||||
foreach (var command in commands)
|
||||
{
|
||||
var result = engine.Apply(command.Clone());
|
||||
if (!result.Accepted) throw new InvalidOperationException(result.ErrorCode + ":" + result.Message);
|
||||
}
|
||||
return engine;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ac7eae5b8f766a40ab60ce8ea0fb184
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ReplacedPerson.Core
|
||||
{
|
||||
/// <summary>PCG-XSH-RR 32; state is explicit so replays are portable across Unity and .NET.</summary>
|
||||
public sealed class Pcg32
|
||||
{
|
||||
public ulong State { get; private set; }
|
||||
public ulong Increment { get; private set; }
|
||||
|
||||
public Pcg32(ulong seed, ulong stream = 54UL)
|
||||
{
|
||||
State = 0UL;
|
||||
Increment = (stream << 1) | 1UL;
|
||||
NextUInt();
|
||||
State += seed;
|
||||
NextUInt();
|
||||
}
|
||||
|
||||
private Pcg32(ulong state, ulong increment, bool _) { State = state; Increment = increment; }
|
||||
|
||||
public Pcg32 Clone() => new(State, Increment, true);
|
||||
|
||||
public uint NextUInt()
|
||||
{
|
||||
var oldState = State;
|
||||
State = unchecked(oldState * 6364136223846793005UL + Increment);
|
||||
var xorShifted = (uint)(((oldState >> 18) ^ oldState) >> 27);
|
||||
var rotation = (int)(oldState >> 59);
|
||||
return (xorShifted >> rotation) | (xorShifted << ((-rotation) & 31));
|
||||
}
|
||||
|
||||
public int NextInt(int exclusiveMax)
|
||||
{
|
||||
if (exclusiveMax <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(exclusiveMax));
|
||||
|
||||
var bound = (uint)exclusiveMax;
|
||||
var threshold = unchecked((uint)(-bound)) % bound;
|
||||
while (true)
|
||||
{
|
||||
var value = NextUInt();
|
||||
if (value >= threshold)
|
||||
return (int)(value % bound);
|
||||
}
|
||||
}
|
||||
|
||||
public int RollD6() => NextInt(6) + 1;
|
||||
|
||||
public void Shuffle<T>(IList<T> values)
|
||||
{
|
||||
if (values == null)
|
||||
throw new ArgumentNullException(nameof(values));
|
||||
for (var i = values.Count - 1; i > 0; i--)
|
||||
{
|
||||
var j = NextInt(i + 1);
|
||||
(values[i], values[j]) = (values[j], values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9886d17170c61941a970081ad8e742a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,81 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ReplacedPerson.Core
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class ReplacedPersonSaveData
|
||||
{
|
||||
public const int CurrentVersion = 3;
|
||||
public int Version { get; set; } = CurrentVersion;
|
||||
public int ChapterProgress { get; set; }
|
||||
public List<string> CollectedCards { get; set; } = new();
|
||||
public List<string> Ornaments { get; set; } = new();
|
||||
public List<string> EquippedOrnaments { get; set; } = new();
|
||||
public ReplacedDeck ActiveDeck { get; set; } = ReplacedBuiltInContent.CreateStarterDeck();
|
||||
public List<ReplacedMatchCommand> RecentReplay { get; set; } = new();
|
||||
}
|
||||
|
||||
public static class ReplacedPersonSaveMigration
|
||||
{
|
||||
public static ReplacedPersonSaveData Migrate(ReplacedPersonSaveData source)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||
if (source.Version > ReplacedPersonSaveData.CurrentVersion)
|
||||
throw new InvalidOperationException("Save data comes from a newer version.");
|
||||
source.CollectedCards ??= new List<string>();
|
||||
source.Ornaments ??= new List<string>();
|
||||
source.EquippedOrnaments ??= new List<string>();
|
||||
source.ActiveDeck ??= ReplacedBuiltInContent.CreateStarterDeck();
|
||||
source.RecentReplay ??= new List<ReplacedMatchCommand>();
|
||||
if (source.Version < 2)
|
||||
{
|
||||
if (source.ChapterProgress > 0 && !source.Ornaments.Contains("ornament.gold-eye"))
|
||||
source.Ornaments.Add("ornament.gold-eye");
|
||||
source.Version = 2;
|
||||
}
|
||||
if (source.Version < 3)
|
||||
{
|
||||
var starter = ReplacedBuiltInContent.CreateStarterDeck();
|
||||
if (IsLegacyStarter(source.ActiveDeck)) source.ActiveDeck = starter;
|
||||
EnsureOwnedCopies(source.CollectedCards, starter.NormalCards);
|
||||
source.Version = 3;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
public static ReplacedPersonSaveData CreateNew()
|
||||
{
|
||||
var deck = ReplacedBuiltInContent.CreateStarterDeck();
|
||||
return new ReplacedPersonSaveData
|
||||
{
|
||||
ActiveDeck = deck,
|
||||
CollectedCards = new List<string>(deck.NormalCards)
|
||||
};
|
||||
}
|
||||
|
||||
private static bool IsLegacyStarter(ReplacedDeck deck)
|
||||
{
|
||||
var legacy = new[]
|
||||
{
|
||||
"attack.kill", "attack.kill", "attack.elbow", "attack.elbow", "attack.break", "attack.break",
|
||||
"dodge.flash", "dodge.flash", "dodge.phase", "dodge.phase", "counter.blood", "counter.blood"
|
||||
};
|
||||
return deck.NormalCards.OrderBy(value => value, StringComparer.Ordinal)
|
||||
.SequenceEqual(legacy.OrderBy(value => value, StringComparer.Ordinal)) &&
|
||||
deck.EndCards.SequenceEqual(new[] { "end.inherit", "end.ledger", "end.severance", "end.black" });
|
||||
}
|
||||
|
||||
private static void EnsureOwnedCopies(List<string> collection, IEnumerable<string> starterCards)
|
||||
{
|
||||
foreach (var group in starterCards.GroupBy(value => value, StringComparer.Ordinal))
|
||||
{
|
||||
var missing = group.Count() - collection.Count(value => value == group.Key);
|
||||
for (var i = 0; i < missing; i++) collection.Add(group.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e65918b8d9a6065499ad8cd7f6247e40
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,84 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ReplacedPerson.Core
|
||||
{
|
||||
public sealed class ReplacedAi
|
||||
{
|
||||
private readonly ReplacedContentCatalog _content;
|
||||
|
||||
public ReplacedAi(ReplacedContentCatalog content) => _content = content ?? throw new ArgumentNullException(nameof(content));
|
||||
|
||||
/// <summary>Uses only own hand plus the already-public lead submission.</summary>
|
||||
public ReplacedTurnSubmission Choose(ReplacedMatchState visibleState, int playerIndex)
|
||||
{
|
||||
var self = visibleState.Players[playerIndex];
|
||||
var targetCount = visibleState.IsLastStand ? 4 : Math.Min(3, self.NormalHand.Count);
|
||||
var publicOpponent = visibleState.Submissions[1 - playerIndex];
|
||||
var opponentTypes = publicOpponent == null
|
||||
? Array.Empty<ReplacedEffectType>()
|
||||
: publicOpponent.NormalCardIds.Where(_content.Cards.ContainsKey).Select(id => _content.Cards[id].EffectType).ToArray();
|
||||
|
||||
var scored = new List<(string id, double score)>();
|
||||
foreach (var id in self.NormalHand.Distinct(StringComparer.Ordinal))
|
||||
{
|
||||
var card = _content.Cards[id];
|
||||
var expected = card.BaseValue + card.Factor * 3.5;
|
||||
var efficiency = expected / Math.Max(1, card.Cost);
|
||||
var survival = self.Health <= 10 && card.EffectType != ReplacedEffectType.Attack ? 4.0 : 0.0;
|
||||
var counterScore = opponentTypes.Sum(type => MatchupScore(card.EffectType, type));
|
||||
scored.Add((id, expected + efficiency * 2.0 + survival + counterScore));
|
||||
}
|
||||
|
||||
var selected = new List<string>();
|
||||
var remainingCost = self.Cost;
|
||||
foreach (var candidate in scored.OrderByDescending(value => value.score).ThenBy(value => value.id, StringComparer.Ordinal))
|
||||
{
|
||||
var available = self.NormalHand.Count(id => id == candidate.id);
|
||||
for (var copy = 0; copy < available && selected.Count < targetCount; copy++)
|
||||
{
|
||||
var cost = _content.Cards[candidate.id].Cost;
|
||||
if (cost > remainingCost) continue;
|
||||
selected.Add(candidate.id);
|
||||
remainingCost -= cost;
|
||||
}
|
||||
}
|
||||
|
||||
var endCount = visibleState.IsLastStand ? 2 : 1;
|
||||
var ends = self.EndHand.Where(id => _content.EndCards[id].Cost <= remainingCost)
|
||||
.OrderByDescending(id => _content.EndCards[id].SlotBase.Sum() + _content.EndCards[id].SlotFactor.Sum() * 3.5)
|
||||
.ThenBy(id => id, StringComparer.Ordinal).Take(endCount).ToList();
|
||||
if (selected.Count < (visibleState.IsLastStand ? 4 : 1) || ends.Count < endCount)
|
||||
return new ReplacedTurnSubmission { Pass = true, DiscardEndOnPass = false };
|
||||
|
||||
return new ReplacedTurnSubmission
|
||||
{
|
||||
NormalCardIds = selected,
|
||||
EndCardIds = ends,
|
||||
RerollSlot = ChooseRerollSlot(selected)
|
||||
};
|
||||
}
|
||||
|
||||
private int ChooseRerollSlot(IReadOnlyList<string> selected)
|
||||
{
|
||||
if (selected.Count == 0) return -1;
|
||||
var weakest = double.MaxValue;
|
||||
var result = -1;
|
||||
for (var i = 0; i < Math.Min(3, selected.Count); i++)
|
||||
{
|
||||
var card = _content.Cards[selected[i]];
|
||||
var expected = card.BaseValue + card.Factor * 3.5;
|
||||
if (expected < weakest) { weakest = expected; result = i; }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static double MatchupScore(ReplacedEffectType own, ReplacedEffectType opponent) =>
|
||||
own == ReplacedEffectType.Counter && opponent == ReplacedEffectType.Attack ? 4.0 :
|
||||
own == ReplacedEffectType.Dodge && opponent == ReplacedEffectType.Attack ? 3.0 :
|
||||
own == ReplacedEffectType.Attack && opponent == ReplacedEffectType.Dodge ? 2.0 : 0.0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54aee14b2a69366498d14e2f9294bcdb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "ReplacedPerson.Core",
|
||||
"rootNamespace": "ReplacedPerson.Core",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": true
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d11e372f3354d047977650288e4ea13
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,69 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace ReplacedPerson.Core
|
||||
{
|
||||
public static class ReplacedStateHasher
|
||||
{
|
||||
public static string Compute(ReplacedMatchState state, Pcg32 random)
|
||||
{
|
||||
var text = new StringBuilder(2048);
|
||||
text.Append(state.Round).Append('|').Append(state.LeadPlayer).Append('|').Append(state.InitiativeRoll)
|
||||
.Append('|').Append((int)state.Phase).Append('|').Append((int)state.Winner).Append('|')
|
||||
.Append(state.IsLastStand ? 1 : 0).Append('|').Append(state.LastStandUsed ? 1 : 0).Append('|')
|
||||
.Append(state.ContentHash).Append('|').Append(random.State).Append('|').Append(random.Increment).Append('\n');
|
||||
for (var index = 0; index < state.Players.Length; index++)
|
||||
{
|
||||
var player = state.Players[index];
|
||||
text.Append(index).Append('|').Append(player.PlayerId).Append('|').Append(player.Health).Append('|')
|
||||
.Append(player.Cost).Append('|').Append(player.Defense).Append('|').Append(player.BonusNormalDraw)
|
||||
.Append('|').Append(player.GuaranteedDodge ? 1 : 0).Append('|').Append(player.SkipNextEndDraw ? 1 : 0)
|
||||
.Append('|').Append(player.SpentThisRound).Append('|').Append(player.EffectiveEffectsThisRound)
|
||||
.Append('|').Append(player.DamageThisRound).Append('\n');
|
||||
AppendList(text, player.NormalDrawPile);
|
||||
AppendList(text, player.NormalDiscard);
|
||||
AppendList(text, player.NormalHand);
|
||||
AppendList(text, player.EndDrawPile);
|
||||
AppendList(text, player.EndDiscard);
|
||||
AppendList(text, player.EndHand);
|
||||
}
|
||||
for (var i = 0; i < state.LastAcceptedSequence.Length; i++)
|
||||
text.Append("S|").Append(i).Append('|').Append(state.LastAcceptedSequence[i]).Append('\n');
|
||||
for (var i = 0; i < state.Submissions.Length; i++)
|
||||
{
|
||||
var submission = state.Submissions[i];
|
||||
text.Append("C|").Append(i).Append('|');
|
||||
if (submission == null)
|
||||
{
|
||||
text.Append("null\n");
|
||||
continue;
|
||||
}
|
||||
text.Append(submission.Pass ? 1 : 0).Append('|').Append(submission.DiscardEndOnPass ? 1 : 0)
|
||||
.Append('|').Append(submission.RerollSlot).Append('|');
|
||||
AppendList(text, submission.NormalCardIds);
|
||||
AppendList(text, submission.EndCardIds);
|
||||
}
|
||||
foreach (var resolution in state.LastResolution)
|
||||
{
|
||||
text.Append("R|").Append(resolution.SlotIndex).Append('|').Append((int)resolution.PlayerOneType).Append('|')
|
||||
.Append((int)resolution.PlayerTwoType).Append('|').Append(resolution.PlayerOneRoll).Append('|')
|
||||
.Append(resolution.PlayerTwoRoll).Append('|').Append(resolution.PlayerOneValue).Append('|')
|
||||
.Append(resolution.PlayerTwoValue).Append('|').Append(resolution.PlayerOneRerolled ? 1 : 0).Append('|')
|
||||
.Append(resolution.PlayerTwoRerolled ? 1 : 0).Append('|').Append(resolution.DamageToPlayerOne).Append('|')
|
||||
.Append(resolution.DamageToPlayerTwo).Append('|').Append(resolution.Summary).Append('\n');
|
||||
}
|
||||
|
||||
using var sha = SHA256.Create();
|
||||
var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(text.ToString()));
|
||||
var result = new StringBuilder(bytes.Length * 2);
|
||||
foreach (var value in bytes) result.Append(value.ToString("x2"));
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
private static void AppendList(StringBuilder target, System.Collections.Generic.IEnumerable<string> values) =>
|
||||
target.Append('[').Append(string.Join(",", values)).Append("]\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c301f3f68d939564db3971ef7199dd01
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8478e2702461e554cb1391f199c19b7c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
# 美术与字体来源
|
||||
|
||||
## 论坛原始资产
|
||||
|
||||
`Art/ForumOriginal/` 中的纸张、卡面、牌序示意和结算图来自原策划页面:[Game14 - 被替代之人](https://forum.crash.work/d/22-game14-bei-ti-dai-zhi-ren)。这些文件用于复现该策划的 Demo 视觉,后续发行前应由项目方再次确认原作者授权范围。
|
||||
|
||||
示例 Mod 的 `icon.png` 由同目录反击卡面裁取复用,因此遵循相同授权边界。
|
||||
|
||||
## 字体
|
||||
|
||||
中文界面使用 Noto Sans SC Variable:
|
||||
|
||||
- 项目文件:`Art/NotoSansSC-Variable.ttf`
|
||||
- 许可证:`Art/OFL-NotoSansSC.txt`
|
||||
- 上游:[Google Fonts - Noto Sans SC](https://fonts.google.com/noto/specimen/Noto+Sans+SC)
|
||||
|
||||
字体采用 SIL Open Font License 1.1。Unity 生成的 `NotoSansSC SDF.asset` 是动态 TMP 字体资产。
|
||||
|
||||
## 音效
|
||||
|
||||
战斗与界面音效取自本机提供的 `C:\Users\im\Downloads\Soundpack`,Demo 内副本位于
|
||||
`Resources/ReplacedPersonAudio/`。当前使用了 `UI`、`Card and Board`、`Environment`、
|
||||
`Combat and Gore` 与 `Musical Effects` 分类中的按钮、纸牌、锁、骰子、打击和结算短音效。
|
||||
|
||||
该本地素材包未附带可识别的许可证文件;当前仅用于 Demo 验证。正式分发前需要由项目方补充来源与授权证明,或替换为许可证明确的音效。
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30d059b0300835a4d95851bd9615f14f
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
# Mod 开发
|
||||
|
||||
## 公共接口
|
||||
|
||||
纯规则层位于 `ReplacedPerson.Core`,可在 Unity 和 .NET 8 独服中使用:
|
||||
|
||||
- `IReplacedPersonMod`
|
||||
- `IReplacedPersonRegistry`
|
||||
- `IReplacedPersonEffectResolver`
|
||||
- `ReplacedPersonModManifest`
|
||||
|
||||
可注册卡牌、结束牌、敌人、奖励、剧情、规则效果和命令。联网规则不得依赖 Unity 类型。Unity 适配层通过 ShrinkModFramework 生命周期把规则实现注册到 `replaced-person.mods`;`AutoApplyHarmonyPatches` 应保持关闭。
|
||||
|
||||
## 审计训练 Mod
|
||||
|
||||
示例位于 `Assets/Demos/ReplacedPerson/Mods/ExampleGreedMod/`,包含:
|
||||
|
||||
- 普通牌“审计”:反击类型,触发正式效果解析器后恢复 1 COST。
|
||||
- 训练敌人“训练用审计员”。
|
||||
- 奖励、短剧情和 `example audit` 命令。
|
||||
- 纯规则程序集和可选 Unity 适配程序集。
|
||||
- 内容 JSON、PNG 图标和严格文件哈希清单。
|
||||
|
||||
构建并打包:
|
||||
|
||||
```powershell
|
||||
./GeneratedServers/ExampleGreedMod.Rules/pack-mod.ps1
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```text
|
||||
Artifacts/ReplacedPersonMods/ExampleGreedMod-1.0.0.zip
|
||||
GeneratedServers/ReplacedPerson.ServerHost/Mods/ExampleGreedMod/
|
||||
```
|
||||
|
||||
## 包结构
|
||||
|
||||
```text
|
||||
ExampleGreedMod/
|
||||
manifest.json
|
||||
content.json
|
||||
icon.png
|
||||
ExampleGreedMod.Rules.dll
|
||||
ExampleGreedMod.Unity.dll # 可选,仅 Unity 端需要
|
||||
```
|
||||
|
||||
`manifest.json` 的 `files` 必须覆盖包内所有参与联网兼容判断的文件,并写入小写 SHA-256。独服启动时先校验文件,再加载纯规则 DLL;当前房间保留不可变内容快照,`reload-mods` 只影响之后创建的房间。
|
||||
|
||||
不可信 DLL 不在本 Demo 的安全边界内。服务器管理员只应安装可信来源的规则程序集。
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e94c9c61703afeb43a2339f08b037ec1
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,38 @@
|
||||
# 联网协议
|
||||
|
||||
## 传输
|
||||
|
||||
- TCP:默认端口 `18140`。
|
||||
- KCP:默认端口 `18141`。
|
||||
- UDP 房间发现:默认端口 `18142`。
|
||||
- 直接 IP 在端口可达时可用于局域网或公网;不提供匹配、NAT 穿透或账号系统。
|
||||
|
||||
Unity 内置 Host 与 .NET 独服使用同一个 `ReplacedRoomAuthority` 和 `ReplacedMatchEngine`。消息体是 UTF-8 JSON,底层 TCP/KCP 传输负责完整包边界。
|
||||
|
||||
## 消息
|
||||
|
||||
| Kind | 用途 |
|
||||
| --- | --- |
|
||||
| `Create` | 创建房间并占用席位 |
|
||||
| `Join` | 加入房间;房间为空时独服可按配置创建 |
|
||||
| `Ready` | 设置准备状态 |
|
||||
| `Deck` | 提交并校验 12+4 牌组 |
|
||||
| `MatchCommand` | 提交回合指令 |
|
||||
| `MatchSnapshot` | 玩家裁剪快照、房间状态和状态哈希 |
|
||||
| `MatchEvent` | 成功、重复包等权威结果 |
|
||||
| `Reconnect` | 在 30 秒席位保留期内重新绑定 |
|
||||
| `Error` | 结构化错误码和差异详情 |
|
||||
|
||||
所有对局指令包含玩家序号和幂等令牌。已接受令牌的重发返回 `Duplicate=true`,不会重复结算。快照只保留对手隐藏区的数量,不暴露卡牌 ID。
|
||||
|
||||
## Mod 握手
|
||||
|
||||
加入请求携带所有启用 Mod 的 ID、版本及文件 SHA-256。权威端逐文件比较,报告 `missing-mod`、`unexpected-mod`、`version`、`missing-file`、`unexpected-file` 或 `hash` 差异,并拒绝准备。
|
||||
|
||||
房间创建时冻结内容快照。热重载只更新之后创建的房间或下一场单机对局,不修改进行中的状态机。
|
||||
|
||||
## 断线和超时
|
||||
|
||||
- 断线后席位保留 30 秒。
|
||||
- 连续两个回合超时判负。
|
||||
- 客户端重连后以权威快照和状态哈希恢复,不在客户端补算遗漏骰点。
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7824b0b1c4c6ebd45bc397fd2302a6ce
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
# 对局规则
|
||||
|
||||
## 牌组与资源
|
||||
|
||||
- 每套牌固定 12 张普通牌和 4 张结束牌。
|
||||
- 普通牌同名最多 2 张,结束牌同名最多 1 张。
|
||||
- 初始 30 HP、10 COST。首次抽 4 张普通牌和 1 张结束牌,此后每回合抽 2+1。
|
||||
- 普通手牌上限 9。抽牌堆耗尽时,权威 PCG32 将弃牌堆洗回。
|
||||
- 锁牌时支付 COST。回合末恢复 `1 + floor(本回合消耗 / 2)`,最多恢复到 10。
|
||||
- 跳过不支付 COST;未弃掉的结束牌会使下一回合跳过结束牌抽取。
|
||||
|
||||
## 回合顺序
|
||||
|
||||
1. 权威端投先手骰并确定先手。
|
||||
2. 双方抽牌。
|
||||
3. 先手公开锁定 1 至 4 张普通牌和 1 张结束牌,或跳过。
|
||||
4. 后手看到牌序与效果范围后进行针对性锁定。
|
||||
5. 每方可预先标记一个效果槽;该槽初骰不高于 2 时自动重掷一次。
|
||||
6. 三个效果槽从左到右执行继承、合成、拼点、联锁和资源结算。
|
||||
|
||||
结束牌提供三个效果槽。单槽值为 `始数 + 因数 x D6`。平点继续由权威随机源重掷,直到分出胜负。
|
||||
|
||||
## 基础克制
|
||||
|
||||
- 攻击胜出:造成差值伤害,单槽最多 8。
|
||||
- 反击胜出:取消攻击并反伤差值,单槽最多 6。
|
||||
- 闪避胜出:取消攻击,并使成功方下一回合多抽 1 张普通牌。
|
||||
|
||||
## 两牌合成
|
||||
|
||||
| 组合 | 结果 |
|
||||
| --- | --- |
|
||||
| 攻+攻 | 合并值乘 1.5 |
|
||||
| 攻+闪 | 成功后抽 1 张牌并恢复 1 COST |
|
||||
| 攻+反 | 成功后追加 3 伤害 |
|
||||
| 反+反 | 返还首次伤害的 50%,最多 5 |
|
||||
| 闪+反 | 获得 2 点当回合 DEF |
|
||||
| 闪+闪 | 获得一次必定闪避 |
|
||||
|
||||
## 孤注一掷
|
||||
|
||||
双方在同一次结算中同时归零时,只进入一次孤注一掷:各抽 4 张普通牌和主、副两张结束牌,恢复量转为伤害。仍平局时先比较本回合有效果数,最后才使用权威骰决定胜负。
|
||||
|
||||
## 贪婪
|
||||
|
||||
第一场使用 20 HP 的教学形态;第二场使用 30 HP 的完整形态。Boss 牌包括“势利眼”“扭亏为盈”“降薪”。完整形态胜利可获得金色势利眼、金链、褶皱西装和三张对应卡牌。
|
||||
|
||||
AI 的输入是裁剪后的可见对局状态;评分考虑期望值、存活、COST 效率、合成收益和公开对位,不读取未来骰点或隐藏抽牌。
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa254a4eee4dd4e4e9e72373bf0f1ec6
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
# 与论坛原案的差异
|
||||
|
||||
本 Demo 保留原案的牌序反制、结束牌继承、三个效果槽拼点、骰子、合成和“孤注一掷”。以下内容为了可验证性与首章节奏做了明确化或平衡调整。
|
||||
|
||||
| 项目 | 论坛原案 | Demo 实现 |
|
||||
| --- | --- | --- |
|
||||
| 随机源 | 未限定实现 | 单一 PCG32 权威随机源,可回放并跨端复现 |
|
||||
| 单槽掷骰 | 可有多种解释 | 每侧每槽初掷一次;只允许一个预标记的低点重掷 |
|
||||
| 平点 | 继续掷骰 | 保留,并由权威端持续到分胜负 |
|
||||
| 攻击伤害 | 差值 | 差值,单槽封顶 8 |
|
||||
| 反击反伤 | 差值 | 差值,单槽封顶 6 |
|
||||
| COST 恢复 | 原案数值未完全封闭 | `1 + floor(本回合消耗/2)`,上限 10 |
|
||||
| 合成 | 以概念描述为主 | 六种组合使用固定表,避免客户端解释分歧 |
|
||||
| 同时归零 | 孤注一掷 | 只触发一次;有效果数后才用权威骰决胜 |
|
||||
| 内容范围 | 论坛概念和部分牌面 | 首版只完成“贪婪”第一章两战,并补齐四张结束牌 |
|
||||
| 联网 | 未指定 | 权威状态机、序号、幂等令牌、状态哈希与严格 Mod 清单 |
|
||||
|
||||
原案来源:[Game14 - 被替代之人](https://forum.crash.work/d/22-game14-bei-ti-dai-zhi-ren)。
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0d9cba143ca12748867116ba01261f8
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa52c3405309824498188ecc9bba1ed1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "ReplacedPerson.Editor",
|
||||
"rootNamespace": "ReplacedPerson.Editor",
|
||||
"references": [
|
||||
"ReplacedPerson.Core",
|
||||
"ReplacedPerson.Runtime",
|
||||
"ShrinkApp.Core.Runtime",
|
||||
"ShrinkContext.AppAdapter.Runtime",
|
||||
"ShrinkModFramework.Runtime",
|
||||
"ShrinkTutorial.Runtime",
|
||||
"UnityEngine.UI",
|
||||
"Unity.TextMeshPro"
|
||||
],
|
||||
"includePlatforms": ["Editor"],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04e8103b42db45f49966a408dc47dda1
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,524 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ReplacedPerson.Runtime;
|
||||
using ShrinkApp;
|
||||
using ShrinkContext.AppAdapter;
|
||||
using ShrinkModFramework;
|
||||
using ShrinkTutorial;
|
||||
using TMPro;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.TextCore.LowLevel;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace ReplacedPerson.Editor
|
||||
{
|
||||
public static class ReplacedPersonSceneBuilder
|
||||
{
|
||||
private const string Root = "Assets/Demos/ReplacedPerson";
|
||||
private const string PrefabRoot = Root + "/Prefabs";
|
||||
private const string ResourceRoot = Root + "/Resources";
|
||||
private const string ScenePath = Root + "/ReplacedPerson.unity";
|
||||
private const string DemoPrefabPath = PrefabRoot + "/ReplacedPersonDemo.prefab";
|
||||
private const string BattlePrefabPath = PrefabRoot + "/BattleScreen.prefab";
|
||||
private const string ModalPrefabPath = PrefabRoot + "/ModalOverlay.prefab";
|
||||
private const string FontPath = Root + "/Art/NotoSansSC-Variable.ttf";
|
||||
private const string FontAssetPath = Root + "/Art/NotoSansSC SDF.asset";
|
||||
private static TMP_FontAsset? _font;
|
||||
private static Sprite? _paper;
|
||||
private static Sprite? _attack;
|
||||
private static Sprite? _dodge;
|
||||
private static Sprite? _counter;
|
||||
|
||||
[MenuItem("ShrinkSDK/Demos/Replaced Person/Rebuild Full Demo")]
|
||||
public static void Rebuild()
|
||||
{
|
||||
Directory.CreateDirectory(PrefabRoot);
|
||||
Directory.CreateDirectory(ResourceRoot);
|
||||
AssetDatabase.Refresh();
|
||||
EnsureSdkAssets();
|
||||
ConfigureSprites();
|
||||
EnsureFont();
|
||||
BuildBattlePrefab();
|
||||
BuildModalPrefab();
|
||||
BuildDemoPrefab();
|
||||
BuildTutorialAssets();
|
||||
BuildScene();
|
||||
AddToBuildSettings();
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
Debug.Log($"[ReplacedPerson] Demo rebuilt: {ScenePath}");
|
||||
}
|
||||
|
||||
[MenuItem("ShrinkSDK/Demos/Replaced Person/Build Windows Player")]
|
||||
public static void BuildWindowsPlayer()
|
||||
{
|
||||
var output = Path.GetFullPath(Path.Combine(Application.dataPath, "..", "Artifacts", "ReplacedPersonBuild", "ReplacedPerson.exe"));
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(output)!);
|
||||
var report = BuildPipeline.BuildPlayer(new BuildPlayerOptions
|
||||
{
|
||||
scenes = new[] { ScenePath },
|
||||
locationPathName = output,
|
||||
target = BuildTarget.StandaloneWindows64,
|
||||
options = BuildOptions.Development
|
||||
});
|
||||
if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
|
||||
throw new InvalidOperationException($"Windows build failed: errors={report.summary.totalErrors}, warnings={report.summary.totalWarnings}");
|
||||
Debug.Log($"[ReplacedPerson] Windows build complete: {output}, warnings={report.summary.totalWarnings}");
|
||||
}
|
||||
|
||||
private static void EnsureSdkAssets()
|
||||
{
|
||||
const string appSettingsPath = "Assets/Resources/ShrinkAppSettings.asset";
|
||||
var appSettings = AssetDatabase.LoadAssetAtPath<ShrinkAppSettings>(appSettingsPath);
|
||||
var appScript = appSettings == null
|
||||
? null
|
||||
: new SerializedObject(appSettings).FindProperty("m_Script")?.objectReferenceValue;
|
||||
if (appSettings == null || appScript == null)
|
||||
{
|
||||
if (!AssetDatabase.IsValidFolder("Assets/Resources")) AssetDatabase.CreateFolder("Assets", "Resources");
|
||||
if (!string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(appSettingsPath))) AssetDatabase.DeleteAsset(appSettingsPath);
|
||||
appSettings = ScriptableObject.CreateInstance<ReplacedPersonAppSettings>();
|
||||
appSettings.hostingMode = ShrinkAppHostingMode.ContextLoader;
|
||||
appSettings.verboseLogging = false;
|
||||
AssetDatabase.CreateAsset(appSettings, appSettingsPath);
|
||||
}
|
||||
|
||||
const string modSettingsPath = ResourceRoot + "/ShrinkModFrameworkSettings.asset";
|
||||
var modSettings = AssetDatabase.LoadAssetAtPath<ShrinkModFrameworkSettings>(modSettingsPath);
|
||||
if (modSettings == null)
|
||||
{
|
||||
modSettings = ScriptableObject.CreateInstance<ShrinkModFrameworkSettings>();
|
||||
modSettings.verboseLogging = false;
|
||||
AssetDatabase.CreateAsset(modSettings, modSettingsPath);
|
||||
}
|
||||
|
||||
const string profilePath = "Assets/Resources/ShrinkAppComposition.asset";
|
||||
var profile = AssetDatabase.LoadAssetAtPath<ShrinkAppCompositionProfile>(profilePath);
|
||||
if (profile != null)
|
||||
{
|
||||
var document = profile.ResolveDocument();
|
||||
if (document.entries.All(value => !string.Equals(value.id, "demo.replaced-person", StringComparison.OrdinalIgnoreCase)))
|
||||
document.entries.Add(new ShrinkAppCompositionEntry("demo.replaced-person"));
|
||||
profile.SetDocument(document);
|
||||
EditorUtility.SetDirty(profile);
|
||||
}
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
private static void ConfigureSprites()
|
||||
{
|
||||
var paths = new[]
|
||||
{
|
||||
Root + "/Art/ForumOriginal/paper.jpg",
|
||||
Root + "/Art/ForumOriginal/card-attack-a.png",
|
||||
Root + "/Art/ForumOriginal/card-dodge-a.png",
|
||||
Root + "/Art/ForumOriginal/card-counter.png",
|
||||
Root + "/Art/ForumOriginal/card-back.png"
|
||||
};
|
||||
foreach (var path in paths)
|
||||
{
|
||||
if (AssetImporter.GetAtPath(path) is not TextureImporter importer) continue;
|
||||
importer.textureType = TextureImporterType.Sprite;
|
||||
importer.spriteImportMode = SpriteImportMode.Single;
|
||||
importer.mipmapEnabled = false;
|
||||
importer.alphaIsTransparency = true;
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
_paper = AssetDatabase.LoadAssetAtPath<Sprite>(paths[0]);
|
||||
_attack = AssetDatabase.LoadAssetAtPath<Sprite>(paths[1]);
|
||||
_dodge = AssetDatabase.LoadAssetAtPath<Sprite>(paths[2]);
|
||||
_counter = AssetDatabase.LoadAssetAtPath<Sprite>(paths[3]);
|
||||
}
|
||||
|
||||
private static void EnsureFont()
|
||||
{
|
||||
DeleteAssetIfExists(FontAssetPath);
|
||||
var source = AssetDatabase.LoadAssetAtPath<Font>(FontPath);
|
||||
if (source == null) throw new InvalidOperationException("CJK source font missing: " + FontPath);
|
||||
_font = TMP_FontAsset.CreateFontAsset(source, 48, 9, GlyphRenderMode.SDFAA, 1024, 1024,
|
||||
AtlasPopulationMode.Dynamic, true);
|
||||
_font.name = "NotoSansSC SDF";
|
||||
_font.atlasPopulationMode = AtlasPopulationMode.Dynamic;
|
||||
AssetDatabase.CreateAsset(_font, FontAssetPath);
|
||||
foreach (var atlas in _font.atlasTextures)
|
||||
{
|
||||
if (atlas == null || AssetDatabase.Contains(atlas)) continue;
|
||||
atlas.name = _font.name + " Atlas";
|
||||
AssetDatabase.AddObjectToAsset(atlas, _font);
|
||||
}
|
||||
if (_font.material != null && !AssetDatabase.Contains(_font.material))
|
||||
{
|
||||
_font.material.name = _font.name + " Material";
|
||||
AssetDatabase.AddObjectToAsset(_font.material, _font);
|
||||
}
|
||||
EditorUtility.SetDirty(_font);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
private static void BuildBattlePrefab()
|
||||
{
|
||||
var screen = Screen("BattleScreen");
|
||||
try
|
||||
{
|
||||
var header = Panel(screen.transform, "Header", new Color(0.05f, 0.055f, 0.06f, 0.96f),
|
||||
new Vector2(0, .92f), Vector2.one);
|
||||
Button(header.transform, "BackButton", "‹", new Vector2(0, 0), new Vector2(.07f, 1), 32);
|
||||
Text(header.transform, "RoundText", "回合 1", 25, TextAlignmentOptions.Center,
|
||||
new Vector2(.08f, 0), new Vector2(.92f, 1));
|
||||
|
||||
var enemy = Panel(screen.transform, "EnemyArea", new Color(.11f, .12f, .12f, .94f),
|
||||
new Vector2(0, .75f), new Vector2(1, .92f));
|
||||
Text(enemy.transform, "EnemyStatus", "贪婪 HP 30/30 COST 10/10", 24, TextAlignmentOptions.Left,
|
||||
new Vector2(.025f, .56f), new Vector2(.98f, .95f));
|
||||
Text(enemy.transform, "EnemyQueue", "等待敌方锁定", 22, TextAlignmentOptions.Left,
|
||||
new Vector2(.025f, .08f), new Vector2(.98f, .54f));
|
||||
Anchor(enemy.gameObject, "rp.matchup");
|
||||
|
||||
var effects = FullRect(screen.transform, "EffectArea", new Vector2(.03f, .43f), new Vector2(.97f, .74f));
|
||||
var layout = effects.gameObject.AddComponent<HorizontalLayoutGroup>();
|
||||
layout.spacing = 18; layout.childAlignment = TextAnchor.MiddleCenter;
|
||||
layout.childControlWidth = true; layout.childControlHeight = true; layout.childForceExpandWidth = true;
|
||||
for (var i = 1; i <= 3; i++)
|
||||
{
|
||||
var slot = Panel(effects, "Slot" + i, i == 2 ? new Color(.29f, .11f, .10f, .94f) : new Color(.11f, .14f, .14f, .94f), Vector2.zero, Vector2.one);
|
||||
Text(slot.transform, "Text", $"槽 {i}\n等待拼点", 21, TextAlignmentOptions.Center, Vector2.zero, Vector2.one, new Vector2(20, 16), new Vector2(-20, -16));
|
||||
}
|
||||
|
||||
var log = Panel(screen.transform, "LogPanel", new Color(.04f, .045f, .05f, .90f), new Vector2(.03f, .30f), new Vector2(.97f, .42f));
|
||||
Text(log.transform, "LogText", "战斗记录", 15, TextAlignmentOptions.TopLeft, Vector2.zero, new Vector2(.48f, 1), new Vector2(16, 10), new Vector2(-12, -10));
|
||||
Text(log.transform, "CardDetailTitle", "卡牌效果", 18, TextAlignmentOptions.TopLeft,
|
||||
new Vector2(.51f, .60f), new Vector2(.98f, .94f));
|
||||
Text(log.transform, "CardDetailText", "悬停、点击或拖动卡牌查看完整效果。", 15, TextAlignmentOptions.TopLeft,
|
||||
new Vector2(.51f, .06f), new Vector2(.98f, .62f));
|
||||
|
||||
var player = Panel(screen.transform, "PlayerArea", new Color(.08f, .085f, .09f, .97f), new Vector2(0, 0), new Vector2(1, .29f));
|
||||
Text(player.transform, "PlayerStatus", "被替代之人 HP 30/30 COST 10/10", 21, TextAlignmentOptions.Left,
|
||||
new Vector2(.02f, .82f), new Vector2(.5f, .99f));
|
||||
Text(player.transform, "SelectionText", "普通牌:未选择\n结束牌:未选择", 15, TextAlignmentOptions.TopLeft,
|
||||
new Vector2(.51f, .73f), new Vector2(.98f, .99f));
|
||||
var normalHand = FullRect(player.transform, "NormalHand", new Vector2(.02f, .30f), new Vector2(.72f, .81f));
|
||||
var normalLayout = normalHand.gameObject.AddComponent<HorizontalLayoutGroup>();
|
||||
normalLayout.spacing = 8; normalLayout.childControlWidth = false; normalLayout.childControlHeight = true;
|
||||
normalLayout.childForceExpandWidth = false; normalLayout.padding = new RectOffset(0, 0, 4, 4);
|
||||
CardTemplate(normalHand, "CardButtonTemplate");
|
||||
Anchor(normalHand.gameObject, "rp.normal-hand");
|
||||
var endHand = FullRect(player.transform, "EndHand", new Vector2(.73f, .30f), new Vector2(.98f, .81f));
|
||||
var endLayout = endHand.gameObject.AddComponent<HorizontalLayoutGroup>();
|
||||
endLayout.spacing = 8; endLayout.childControlWidth = false; endLayout.childControlHeight = true; endLayout.childForceExpandWidth = false;
|
||||
CardTemplate(endHand, "CardButtonTemplate");
|
||||
Anchor(endHand.gameObject, "rp.end-hand");
|
||||
var actions = FullRect(player.transform, "Actions", new Vector2(.02f, .03f), new Vector2(.98f, .28f));
|
||||
var actionLayout = actions.gameObject.AddComponent<HorizontalLayoutGroup>();
|
||||
actionLayout.spacing = 10; actionLayout.childControlHeight = true; actionLayout.childControlWidth = true; actionLayout.childForceExpandWidth = true;
|
||||
Button(actions, "Reroll1Button", "骰 1", Vector2.zero, Vector2.one, 17);
|
||||
Button(actions, "Reroll2Button", "骰 2", Vector2.zero, Vector2.one, 17);
|
||||
Button(actions, "Reroll3Button", "骰 3", Vector2.zero, Vector2.one, 17);
|
||||
Button(actions, "PassButton", "跳过", Vector2.zero, Vector2.one, 18);
|
||||
Button(actions, "SubmitButton", "锁定", Vector2.zero, Vector2.one, 19, new Color(.66f, .12f, .10f, 1));
|
||||
Anchor(actions.gameObject, "rp.reroll");
|
||||
|
||||
PrefabUtility.SaveAsPrefabAsset(screen, BattlePrefabPath);
|
||||
}
|
||||
finally { UnityEngine.Object.DestroyImmediate(screen); }
|
||||
}
|
||||
|
||||
private static void BuildModalPrefab()
|
||||
{
|
||||
var root = Screen("ModalOverlay");
|
||||
try
|
||||
{
|
||||
root.AddComponent<CanvasGroup>();
|
||||
var scrim = Image(root.transform, "Scrim", null, new Color(0, 0, 0, .72f), Vector2.zero, Vector2.one);
|
||||
scrim.raycastTarget = true;
|
||||
var panel = Panel(root.transform, "Panel", new Color(.11f, .12f, .12f, 1), new Vector2(.3f, .32f), new Vector2(.7f, .68f));
|
||||
Text(panel.transform, "Title", "提示", 30, TextAlignmentOptions.Center, new Vector2(.08f, .67f), new Vector2(.92f, .94f));
|
||||
Text(panel.transform, "Message", "", 20, TextAlignmentOptions.Center, new Vector2(.08f, .28f), new Vector2(.92f, .68f));
|
||||
Button(panel.transform, "CloseButton", "确定", new Vector2(.32f, .08f), new Vector2(.68f, .25f), 20);
|
||||
PrefabUtility.SaveAsPrefabAsset(root, ModalPrefabPath);
|
||||
}
|
||||
finally { UnityEngine.Object.DestroyImmediate(root); }
|
||||
}
|
||||
|
||||
private static void BuildDemoPrefab()
|
||||
{
|
||||
var root = new GameObject("ReplacedPersonDemo", typeof(RectTransform), typeof(ReplacedPersonDemoController));
|
||||
try
|
||||
{
|
||||
var canvasObject = new GameObject("Canvas", typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster));
|
||||
canvasObject.transform.SetParent(root.transform, false);
|
||||
var canvas = canvasObject.GetComponent<Canvas>(); canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
var scaler = canvasObject.GetComponent<CanvasScaler>();
|
||||
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920, 1080); scaler.matchWidthOrHeight = .5f;
|
||||
Stretch(canvasObject.GetComponent<RectTransform>());
|
||||
var background = Image(canvasObject.transform, "Background", _paper, new Color(.32f, .35f, .36f, 1), Vector2.zero, Vector2.one);
|
||||
background.preserveAspect = false;
|
||||
var safe = FullRect(canvasObject.transform, "SafeAreaRoot", Vector2.zero, Vector2.one);
|
||||
safe.gameObject.AddComponent<ReplacedSafeArea>();
|
||||
var screens = FullRect(safe, "Screens", Vector2.zero, Vector2.one);
|
||||
BuildTitle(screens);
|
||||
BuildChapter(screens);
|
||||
BuildDeck(screens);
|
||||
BuildLan(screens);
|
||||
var battlePrefab = AssetDatabase.LoadAssetAtPath<GameObject>(BattlePrefabPath) ?? throw new InvalidOperationException("Battle prefab missing.");
|
||||
var battle = (GameObject)PrefabUtility.InstantiatePrefab(battlePrefab);
|
||||
battle.transform.SetParent(screens, false); Stretch(battle.GetComponent<RectTransform>());
|
||||
BuildReward(screens);
|
||||
BuildSettings(screens);
|
||||
PrefabUtility.SaveAsPrefabAsset(root, DemoPrefabPath);
|
||||
}
|
||||
finally { UnityEngine.Object.DestroyImmediate(root); }
|
||||
}
|
||||
|
||||
private static void BuildTitle(Transform parent)
|
||||
{
|
||||
var screen = Screen("TitleScreen", parent);
|
||||
Text(screen.transform, "Title", "被替代之人", 70, TextAlignmentOptions.Center, new Vector2(.08f, .70f), new Vector2(.92f, .94f));
|
||||
Text(screen.transform, "Subtitle", "第一章 · 贪婪", 24, TextAlignmentOptions.Center, new Vector2(.15f, .62f), new Vector2(.85f, .72f));
|
||||
var art = FullRect(screen.transform, "ArtTriptych", new Vector2(.08f, .20f), new Vector2(.58f, .62f));
|
||||
var layout = art.gameObject.AddComponent<HorizontalLayoutGroup>(); layout.spacing = 20; layout.childControlHeight = true; layout.childControlWidth = true; layout.childForceExpandWidth = true;
|
||||
Image(art, "Attack", _attack, Color.white, Vector2.zero, Vector2.one).preserveAspect = true;
|
||||
Image(art, "Dodge", _dodge, Color.white, Vector2.zero, Vector2.one).preserveAspect = true;
|
||||
Image(art, "Counter", _counter, Color.white, Vector2.zero, Vector2.one).preserveAspect = true;
|
||||
var actions = FullRect(screen.transform, "Actions", new Vector2(.64f, .20f), new Vector2(.91f, .61f));
|
||||
var vertical = actions.gameObject.AddComponent<VerticalLayoutGroup>();
|
||||
vertical.spacing = 14; vertical.childControlWidth = true; vertical.childControlHeight = true; vertical.childForceExpandHeight = true;
|
||||
Button(actions, "ContinueButton", "进入章节", Vector2.zero, Vector2.one, 25, new Color(.67f, .13f, .11f, 1));
|
||||
Button(actions, "DeckButton", "牌组", Vector2.zero, Vector2.one, 22);
|
||||
Button(actions, "LanButton", "局域网", Vector2.zero, Vector2.one, 22);
|
||||
Button(actions, "SettingsButton", "设置", Vector2.zero, Vector2.one, 22);
|
||||
Text(screen.transform, "Footer", "DEMO / WINDOWS PC / v1", 14, TextAlignmentOptions.BottomLeft, new Vector2(.03f, .02f), new Vector2(.7f, .09f));
|
||||
}
|
||||
|
||||
private static void BuildChapter(Transform parent)
|
||||
{
|
||||
var screen = Screen("ChapterScreen", parent);
|
||||
Header(screen.transform, "章节");
|
||||
var content = FullRect(screen.transform, "Content", new Vector2(.10f, .17f), new Vector2(.90f, .88f));
|
||||
Text(content, "ChapterLabel", "第一章 · 贪婪", 42, TextAlignmentOptions.TopLeft, new Vector2(0, .77f), Vector2.one);
|
||||
Text(content, "StoryText", "", 26, TextAlignmentOptions.TopLeft, Vector2.zero, new Vector2(1, .76f));
|
||||
var footer = FullRect(screen.transform, "Footer", new Vector2(.66f, .05f), new Vector2(.90f, .14f));
|
||||
Button(footer, "StartBattleButton", "进入第一战", Vector2.zero, Vector2.one, 24, new Color(.67f, .13f, .11f, 1));
|
||||
}
|
||||
|
||||
private static void BuildDeck(Transform parent)
|
||||
{
|
||||
var screen = Screen("DeckScreen", parent); Header(screen.transform, "牌组编辑");
|
||||
var content = FullRect(screen.transform, "Content", new Vector2(.04f, .15f), new Vector2(.96f, .88f));
|
||||
Text(content, "DeckStatus", "普通牌 12/12", 22, TextAlignmentOptions.Left, new Vector2(0, .91f), Vector2.one);
|
||||
ScrollList(content, "CurrentDeck", "当前牌组 · 点击移除", new Vector2(0, 0), new Vector2(.48f, .89f));
|
||||
ScrollList(content, "Collection", "收藏 · 点击加入", new Vector2(.52f, 0), new Vector2(1, .89f));
|
||||
var footer = FullRect(screen.transform, "Footer", new Vector2(.62f, .04f), new Vector2(.96f, .12f));
|
||||
var layout = footer.gameObject.AddComponent<HorizontalLayoutGroup>(); layout.spacing = 12; layout.childControlHeight = true; layout.childControlWidth = true;
|
||||
Button(footer, "ResetButton", "重置", Vector2.zero, Vector2.one, 20);
|
||||
Button(footer, "SaveButton", "保存", Vector2.zero, Vector2.one, 20, new Color(.67f, .13f, .11f, 1));
|
||||
}
|
||||
|
||||
private static void BuildLan(Transform parent)
|
||||
{
|
||||
var screen = Screen("LanScreen", parent); Header(screen.transform, "局域网大厅");
|
||||
var content = FullRect(screen.transform, "Content", new Vector2(.18f, .16f), new Vector2(.82f, .84f));
|
||||
Text(content, "StatusText", "尚未连接", 24, TextAlignmentOptions.Center, new Vector2(.05f, .68f), new Vector2(.95f, .92f));
|
||||
Input(content, "AddressInput", "127.0.0.1", new Vector2(.18f, .49f), new Vector2(.82f, .62f));
|
||||
Button(content, "HostButton", "创建房间", new Vector2(.18f, .31f), new Vector2(.48f, .43f), 22);
|
||||
Button(content, "JoinButton", "直接加入", new Vector2(.52f, .31f), new Vector2(.82f, .43f), 22, new Color(.67f, .13f, .11f, 1));
|
||||
Button(content, "StartMatchButton", "进入对局", new Vector2(.34f, .16f), new Vector2(.66f, .27f), 21, new Color(.67f, .13f, .11f, 1));
|
||||
Text(content, "DiscoveryText", "局域网发现会自动广播可用房间", 17, TextAlignmentOptions.Center, new Vector2(.1f, .01f), new Vector2(.9f, .14f));
|
||||
}
|
||||
|
||||
private static void BuildReward(Transform parent)
|
||||
{
|
||||
var screen = Screen("RewardScreen", parent);
|
||||
Text(screen.transform, "Title", "结算", 28, TextAlignmentOptions.Center, new Vector2(.2f, .87f), new Vector2(.8f, .96f));
|
||||
var content = FullRect(screen.transform, "Content", new Vector2(.18f, .22f), new Vector2(.82f, .84f));
|
||||
Text(content, "ResultText", "胜利", 52, TextAlignmentOptions.Center, new Vector2(.1f, .75f), new Vector2(.9f, .94f));
|
||||
Text(content, "RewardText", "", 21, TextAlignmentOptions.TopLeft, new Vector2(.05f, .30f), new Vector2(.48f, .73f));
|
||||
Text(content, "AppearanceText", "当前装饰:无", 20, TextAlignmentOptions.Left, new Vector2(.52f, .61f), new Vector2(.98f, .72f));
|
||||
var ornaments = FullRect(content, "Ornaments", new Vector2(.52f, .30f), new Vector2(.98f, .59f));
|
||||
var ornamentLayout = ornaments.gameObject.AddComponent<VerticalLayoutGroup>();
|
||||
ornamentLayout.spacing = 8; ornamentLayout.childControlWidth = true; ornamentLayout.childControlHeight = true; ornamentLayout.childForceExpandHeight = true;
|
||||
Button(ornaments, "GoldEyeButton", "金色势利眼", Vector2.zero, Vector2.one, 17);
|
||||
Button(ornaments, "GoldChainButton", "金链", Vector2.zero, Vector2.one, 17);
|
||||
Button(ornaments, "WornSuitButton", "褶皱西装", Vector2.zero, Vector2.one, 17);
|
||||
var footer = FullRect(screen.transform, "Footer", new Vector2(.38f, .08f), new Vector2(.62f, .17f));
|
||||
Button(footer, "ContinueButton", "继续", Vector2.zero, Vector2.one, 23, new Color(.67f, .13f, .11f, 1));
|
||||
}
|
||||
|
||||
private static void BuildSettings(Transform parent)
|
||||
{
|
||||
var screen = Screen("SettingsScreen", parent); Header(screen.transform, "设置");
|
||||
var content = FullRect(screen.transform, "Content", new Vector2(.24f, .25f), new Vector2(.76f, .78f));
|
||||
Text(content, "TransportStatus", "LAN 传输:TCP", 28, TextAlignmentOptions.Center, new Vector2(.1f, .68f), new Vector2(.9f, .91f));
|
||||
Button(content, "TcpButton", "TCP", new Vector2(.12f, .42f), new Vector2(.48f, .61f), 23);
|
||||
Button(content, "KcpButton", "KCP", new Vector2(.52f, .42f), new Vector2(.88f, .61f), 23);
|
||||
Text(content, "Note", "1920×1080 基准 · 支持 16:10 与 4:3\n拖牌与点牌共用同一提交队列", 18, TextAlignmentOptions.Center, new Vector2(.06f, .09f), new Vector2(.94f, .34f));
|
||||
}
|
||||
|
||||
private static void Header(Transform screen, string title)
|
||||
{
|
||||
var header = Panel(screen, "Header", new Color(.05f, .055f, .06f, .94f), new Vector2(0, .90f), Vector2.one);
|
||||
Button(header.transform, "BackButton", "‹", new Vector2(0, 0), new Vector2(.08f, 1), 34);
|
||||
Text(header.transform, "Title", title, 30, TextAlignmentOptions.Left, new Vector2(.10f, 0), new Vector2(.9f, 1));
|
||||
}
|
||||
|
||||
private static void ScrollList(Transform parent, string name, string title, Vector2 min, Vector2 max)
|
||||
{
|
||||
var root = Panel(parent, name, new Color(.08f, .085f, .09f, .94f), min, max);
|
||||
Text(root.transform, "Title", title, 20, TextAlignmentOptions.Left, new Vector2(.04f, .90f), new Vector2(.96f, .99f));
|
||||
var viewport = FullRect(root.transform, "Viewport", new Vector2(.03f, .03f), new Vector2(.97f, .88f));
|
||||
viewport.gameObject.AddComponent<RectMask2D>();
|
||||
var content = FullRect(viewport, "Content", new Vector2(0, 1), Vector2.one);
|
||||
content.anchorMin = new Vector2(0, 1); content.anchorMax = new Vector2(1, 1); content.pivot = new Vector2(.5f, 1); content.sizeDelta = new Vector2(0, 0);
|
||||
var layout = content.gameObject.AddComponent<VerticalLayoutGroup>();
|
||||
layout.spacing = 6; layout.childControlWidth = true; layout.childControlHeight = true; layout.childForceExpandWidth = true; layout.childForceExpandHeight = false; layout.padding = new RectOffset(4, 4, 4, 4);
|
||||
var fitter = content.gameObject.AddComponent<ContentSizeFitter>(); fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
var row = Button(content, "RowTemplate", "卡牌", Vector2.zero, Vector2.one, 17);
|
||||
row.gameObject.AddComponent<LayoutElement>().preferredHeight = 54; row.gameObject.SetActive(false);
|
||||
var scroll = root.gameObject.AddComponent<ScrollRect>(); scroll.viewport = viewport; scroll.content = content; scroll.horizontal = false; scroll.movementType = ScrollRect.MovementType.Clamped;
|
||||
}
|
||||
|
||||
private static void CardTemplate(Transform parent, string name)
|
||||
{
|
||||
var button = Button(parent, name, "卡牌", Vector2.zero, Vector2.one, 14, new Color(.90f, .87f, .78f, .98f));
|
||||
button.gameObject.AddComponent<ReplacedCardDragHandler>();
|
||||
var layout = button.gameObject.AddComponent<LayoutElement>(); layout.preferredWidth = 132; layout.minWidth = 116;
|
||||
var rect = button.GetComponent<RectTransform>(); rect.sizeDelta = new Vector2(132, 132);
|
||||
button.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private static GameObject Screen(string name, Transform? parent = null)
|
||||
{
|
||||
var result = new GameObject(name, typeof(RectTransform));
|
||||
if (parent != null) result.transform.SetParent(parent, false);
|
||||
Stretch(result.GetComponent<RectTransform>());
|
||||
return result;
|
||||
}
|
||||
|
||||
private static RectTransform FullRect(Transform parent, string name, Vector2 min, Vector2 max)
|
||||
{
|
||||
var result = new GameObject(name, typeof(RectTransform)).GetComponent<RectTransform>();
|
||||
result.SetParent(parent, false); result.anchorMin = min; result.anchorMax = max; result.offsetMin = Vector2.zero; result.offsetMax = Vector2.zero;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Image Panel(Transform parent, string name, Color color, Vector2 min, Vector2 max) => Image(parent, name, null, color, min, max);
|
||||
|
||||
private static Image Image(Transform parent, string name, Sprite? sprite, Color color, Vector2 min, Vector2 max)
|
||||
{
|
||||
var rect = FullRect(parent, name, min, max);
|
||||
var image = rect.gameObject.AddComponent<Image>(); image.sprite = sprite; image.color = color; image.raycastTarget = false;
|
||||
return image;
|
||||
}
|
||||
|
||||
private static TMP_Text Text(Transform parent, string name, string value, float size, TextAlignmentOptions alignment,
|
||||
Vector2 min, Vector2 max, Vector2? offsetMin = null, Vector2? offsetMax = null)
|
||||
{
|
||||
var rect = FullRect(parent, name, min, max); rect.offsetMin = offsetMin ?? Vector2.zero; rect.offsetMax = offsetMax ?? Vector2.zero;
|
||||
var text = rect.gameObject.AddComponent<TextMeshProUGUI>(); text.font = _font; text.text = value; text.fontSize = size; text.alignment = alignment;
|
||||
text.color = new Color(.92f, .91f, .86f, 1); text.enableWordWrapping = true; text.overflowMode = TextOverflowModes.Ellipsis; text.raycastTarget = false;
|
||||
return text;
|
||||
}
|
||||
|
||||
private static Button Button(Transform parent, string name, string label, Vector2 min, Vector2 max, float size, Color? color = null)
|
||||
{
|
||||
var image = Image(parent, name, null, color ?? new Color(.18f, .19f, .19f, .98f), min, max); image.raycastTarget = true;
|
||||
var button = image.gameObject.AddComponent<Button>(); button.targetGraphic = image;
|
||||
Text(image.transform, "Label", label, size, TextAlignmentOptions.Center, Vector2.zero, Vector2.one, new Vector2(8, 4), new Vector2(-8, -4));
|
||||
return button;
|
||||
}
|
||||
|
||||
private static TMP_InputField Input(Transform parent, string name, string placeholder, Vector2 min, Vector2 max)
|
||||
{
|
||||
var background = Image(parent, name, null, new Color(.92f, .90f, .84f, 1), min, max); background.raycastTarget = true;
|
||||
var area = FullRect(background.transform, "TextArea", new Vector2(.04f, .1f), new Vector2(.96f, .9f)); area.gameObject.AddComponent<RectMask2D>();
|
||||
var text = Text(area, "Text", string.Empty, 22, TextAlignmentOptions.Left, Vector2.zero, Vector2.one); text.color = Color.black;
|
||||
var hint = Text(area, "Placeholder", placeholder, 22, TextAlignmentOptions.Left, Vector2.zero, Vector2.one); hint.color = new Color(.2f, .2f, .2f, .45f);
|
||||
var input = background.gameObject.AddComponent<TMP_InputField>(); input.textViewport = area; input.textComponent = (TMP_Text)text; input.placeholder = hint;
|
||||
return input;
|
||||
}
|
||||
|
||||
private static void Anchor(GameObject target, string id)
|
||||
{
|
||||
var anchor = target.AddComponent<ShrinkTutorialAnchor>(); anchor.SetAnchorId(id);
|
||||
}
|
||||
|
||||
private static void Stretch(RectTransform rect)
|
||||
{
|
||||
rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.offsetMin = Vector2.zero; rect.offsetMax = Vector2.zero;
|
||||
}
|
||||
|
||||
private static void BuildTutorialAssets()
|
||||
{
|
||||
DeleteAssetIfExists(ResourceRoot + "/ReplacedPersonFirstMatchTutorial.asset");
|
||||
DeleteAssetIfExists(ResourceRoot + "/ReplacedPersonTutorialDatabase.asset");
|
||||
DeleteAssetIfExists(ResourceRoot + "/ShrinkTutorialSettings.asset");
|
||||
DeleteAssetIfExists(ResourceRoot + "/ReplacedPersonTutorialSettings.asset");
|
||||
var tutorial = ScriptableObject.CreateInstance<ShrinkTutorialData>();
|
||||
tutorial.tutorialId = "replaced-person.first-match";
|
||||
tutorial.steps = new List<ShrinkTutorialStep>
|
||||
{
|
||||
Step("rp.normal-hand", "rp.card-selected", "选择一张普通牌。牌面顺序会从左到右继承到结束牌。", ShrinkTutorialDialogAnchor.Top),
|
||||
Step("rp.end-hand", "rp.end-selected", "选择结束牌。它提供三个效果槽,并锁定本次提交。", ShrinkTutorialDialogAnchor.Top),
|
||||
Step("rp.matchup", "rp.matchup-submitted", "后手能看到先手牌序。对齐克制关系后再锁定。", ShrinkTutorialDialogAnchor.Bottom),
|
||||
Step("rp.reroll", "rp.reroll-marked", "标记一个效果槽;初次骰点不高于 2 时会自动重掷一次。", ShrinkTutorialDialogAnchor.Top)
|
||||
};
|
||||
AssetDatabase.CreateAsset(tutorial, ResourceRoot + "/ReplacedPersonFirstMatchTutorial.asset");
|
||||
var database = ScriptableObject.CreateInstance<ShrinkTutorialDatabase>();
|
||||
var serialized = new SerializedObject(database); var tutorials = serialized.FindProperty("tutorials"); tutorials.arraySize = 1; tutorials.GetArrayElementAtIndex(0).objectReferenceValue = tutorial; serialized.ApplyModifiedPropertiesWithoutUndo();
|
||||
AssetDatabase.CreateAsset(database, ResourceRoot + "/ReplacedPersonTutorialDatabase.asset");
|
||||
var settings = ScriptableObject.CreateInstance<ShrinkTutorialSettings>(); settings.database = database; settings.playerPrefsStorageKey = "ReplacedPerson.Tutorial"; settings.showSkipButton = true; settings.canvasSortingOrder = 5000;
|
||||
settings.name = "ReplacedPersonTutorialSettings";
|
||||
AssetDatabase.CreateAsset(settings, ResourceRoot + "/ReplacedPersonTutorialSettings.asset");
|
||||
}
|
||||
|
||||
private static ShrinkTutorialStep Step(string anchor, string signal, string text, ShrinkTutorialDialogAnchor dialogAnchor) => new()
|
||||
{
|
||||
targetMode = ShrinkTutorialTargetMode.AnchorId,
|
||||
anchorId = anchor,
|
||||
completeCondition = ShrinkTutorialCompleteCondition.CustomEvent,
|
||||
customEventName = signal,
|
||||
fallbackText = text,
|
||||
dialogAnchor = dialogAnchor,
|
||||
maskShape = ShrinkTutorialMaskShape.Rect,
|
||||
maskPadding = 10,
|
||||
waitForTarget = true,
|
||||
waitTimeout = 3
|
||||
};
|
||||
|
||||
private static void BuildScene()
|
||||
{
|
||||
var scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(DemoPrefabPath) ?? throw new InvalidOperationException("Demo prefab missing.");
|
||||
var instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab, scene); instance.name = "ReplacedPersonDemo";
|
||||
var cameraObject = new GameObject("Main Camera", typeof(Camera), typeof(AudioListener));
|
||||
cameraObject.tag = "MainCamera";
|
||||
cameraObject.transform.position = new Vector3(0, 0, -10);
|
||||
var camera = cameraObject.GetComponent<Camera>();
|
||||
camera.clearFlags = CameraClearFlags.SolidColor;
|
||||
camera.backgroundColor = new Color(.02f, .025f, .03f, 1);
|
||||
camera.cullingMask = 0;
|
||||
camera.orthographic = true;
|
||||
camera.depth = -100;
|
||||
new GameObject("EventSystem", typeof(EventSystem), typeof(StandaloneInputModule));
|
||||
EditorSceneManager.SaveScene(scene, ScenePath);
|
||||
}
|
||||
|
||||
private static void AddToBuildSettings()
|
||||
{
|
||||
var scenes = EditorBuildSettings.scenes.ToList();
|
||||
var existing = scenes.FindIndex(value => value.path == ScenePath);
|
||||
if (existing >= 0) scenes[existing] = new EditorBuildSettingsScene(ScenePath, true);
|
||||
else scenes.Add(new EditorBuildSettingsScene(ScenePath, true));
|
||||
EditorBuildSettings.scenes = scenes.ToArray();
|
||||
}
|
||||
|
||||
private static void DeleteAssetIfExists(string path) { if (AssetDatabase.LoadMainAssetAtPath(path) != null) AssetDatabase.DeleteAsset(path); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ebf6b9d7b155d3547a01f5a0aa2b2154
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e7dc26bd42476a4c8191a4363d6ca28
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f1b4f95bd66e1c84cb9dc77af99ee9cb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c18deeb181f6fc94d92fbd8276548949
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "ExampleGreedMod.Rules",
|
||||
"rootNamespace": "ExampleGreedMod",
|
||||
"references": ["ReplacedPerson.Core"],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": true
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 375cebea661eef74dae3870143ca3f6e
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using ReplacedPerson.Core;
|
||||
|
||||
namespace ExampleGreedMod
|
||||
{
|
||||
public sealed class ExampleGreedRules : IReplacedPersonMod
|
||||
{
|
||||
public string Id => "example.greedy-training";
|
||||
public string Version => "1.0.0";
|
||||
|
||||
public void Register(IReplacedPersonRegistry registry)
|
||||
{
|
||||
registry.RegisterCard(new ReplacedCardDefinition
|
||||
{
|
||||
Id = "example.audit",
|
||||
Name = "审计",
|
||||
Description = "测试卡:反击成功后额外恢复 1 COST。",
|
||||
EffectType = ReplacedEffectType.Counter,
|
||||
Cost = 2,
|
||||
BaseValue = 4,
|
||||
Factor = 2,
|
||||
SpecialEffectId = "example.audit-refund"
|
||||
});
|
||||
registry.RegisterEffectResolver("example.audit-refund", new AuditRefundResolver());
|
||||
registry.RegisterEnemy(new ReplacedEnemyDefinition
|
||||
{
|
||||
Id = "example.training",
|
||||
Name = "训练用审计员",
|
||||
MaxHealth = 18,
|
||||
NormalDeck = new List<string>
|
||||
{
|
||||
"example.audit", "example.audit", "attack.kill", "attack.kill", "attack.elbow", "attack.elbow",
|
||||
"dodge.flash", "dodge.flash", "counter.blood", "counter.blood", "greed.snob", "greed.snob"
|
||||
},
|
||||
EndDeck = new List<string> { "end.inherit", "end.ledger", "end.severance", "end.black" },
|
||||
RewardIds = new List<string> { "example.audit" }
|
||||
});
|
||||
registry.RegisterReward("example.audit", "审计卡");
|
||||
registry.RegisterStory("example.training.story", "审计训练", "账本上的每一行都在回望你。");
|
||||
registry.RegisterCommand("example audit", _ => "audit-ready");
|
||||
}
|
||||
|
||||
private sealed class AuditRefundResolver : IReplacedPersonEffectResolver
|
||||
{
|
||||
public ReplacedEffectResult Resolve(ReplacedEffectContext context) => new()
|
||||
{
|
||||
CostDelta = 1,
|
||||
Log = "审计返还 1 COST"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e717a2e339d03044a80d69f36999b23
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89bbdbc3beff793428dc10c25f88c27e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "ExampleGreedMod.Unity",
|
||||
"rootNamespace": "ExampleGreedMod",
|
||||
"references": ["ExampleGreedMod.Rules", "ReplacedPerson.Core", "ReplacedPerson.Runtime", "ShrinkModFramework.Runtime"],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16ac024bec35a9143a014e25d8b5f634
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
#nullable enable
|
||||
|
||||
using ReplacedPerson.Core;
|
||||
using ReplacedPerson.Runtime;
|
||||
using ShrinkModFramework;
|
||||
|
||||
namespace ExampleGreedMod
|
||||
{
|
||||
[ShrinkMod("example.greedy-training", "贪婪训练 Mod", "1.0.0", AutoApplyHarmonyPatches = false)]
|
||||
public sealed class ExampleGreedUnityMod : ShrinkModBase
|
||||
{
|
||||
public override void OnRegisterContent(ShrinkModContext context)
|
||||
{
|
||||
context.GetRegistry<IReplacedPersonMod>(ReplacedPersonModBridge.RegistryName)
|
||||
.Register(context.ModInfo.ModId, context.ModInfo.ModId, new ExampleGreedRules());
|
||||
}
|
||||
|
||||
public override void OnReady(ShrinkModContext context)
|
||||
{
|
||||
context.Log("Formal registry integration ready; no Harmony patching used.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b6c3206fd5108243b0e11bc7d4f0194
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"cards": ["example.audit"],
|
||||
"effects": ["example.audit-refund"],
|
||||
"enemies": ["example.training"],
|
||||
"commands": ["example audit"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee633347fcb672343b380db07a6b05f4
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 627 KiB |
@@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ec4baff1b62606418c49acbda4b0a50
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"id": "example.greedy-training",
|
||||
"version": "1.0.0",
|
||||
"rulesAssembly": "ExampleGreedMod.Rules.dll",
|
||||
"unityAssembly": "ExampleGreedMod.Unity.dll",
|
||||
"content": "content.json",
|
||||
"icon": "icon.png",
|
||||
"networkCompatible": true,
|
||||
"files": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e393e811edc18443b507bf3a2112174
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80fa129ba99db0c42b4a2ba7124be22d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 692b0f6e220f978478a4cbb5c68bb2b7
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,728 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &109461749179269432
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7134254617425657058}
|
||||
- component: {fileID: 3922028287645489926}
|
||||
- component: {fileID: 5260202726735049939}
|
||||
m_Layer: 0
|
||||
m_Name: Scrim
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &7134254617425657058
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 109461749179269432}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 4709999122157385881}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &3922028287645489926
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 109461749179269432}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &5260202726735049939
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 109461749179269432}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0, g: 0, b: 0, a: 0.72}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &1071967189918236762
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4060912498424251528}
|
||||
- component: {fileID: 6470522395222180645}
|
||||
- component: {fileID: 7838437069278855208}
|
||||
m_Layer: 0
|
||||
m_Name: Title
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4060912498424251528
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1071967189918236762}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8277422716032291198}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.08, y: 0.67}
|
||||
m_AnchorMax: {x: 0.92, y: 0.94}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &6470522395222180645
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1071967189918236762}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &7838437069278855208
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1071967189918236762}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: "\u63D0\u793A"
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 13367afdf20e47f40b184469b5e36efd, type: 2}
|
||||
m_sharedMaterial: {fileID: 8333056236493354663, guid: 13367afdf20e47f40b184469b5e36efd, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 0.92, g: 0.91, b: 0.86, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 30
|
||||
m_fontSizeBase: 30
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 1
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &1193336366473257478
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3844761814136918061}
|
||||
- component: {fileID: 996824119279668335}
|
||||
- component: {fileID: 2500486358091292699}
|
||||
m_Layer: 0
|
||||
m_Name: Label
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3844761814136918061
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1193336366473257478}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8638408449368862406}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: -16, y: -8}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &996824119279668335
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1193336366473257478}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &2500486358091292699
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1193336366473257478}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: "\u786E\u5B9A"
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 13367afdf20e47f40b184469b5e36efd, type: 2}
|
||||
m_sharedMaterial: {fileID: 8333056236493354663, guid: 13367afdf20e47f40b184469b5e36efd, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 0.92, g: 0.91, b: 0.86, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 20
|
||||
m_fontSizeBase: 20
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 1
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &1305232677574263801
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 2439426371679133391}
|
||||
- component: {fileID: 4157319648314641653}
|
||||
- component: {fileID: 7101854651374399573}
|
||||
m_Layer: 0
|
||||
m_Name: Message
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &2439426371679133391
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1305232677574263801}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8277422716032291198}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.08, y: 0.28}
|
||||
m_AnchorMax: {x: 0.92, y: 0.68}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &4157319648314641653
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1305232677574263801}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &7101854651374399573
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1305232677574263801}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text:
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 13367afdf20e47f40b184469b5e36efd, type: 2}
|
||||
m_sharedMaterial: {fileID: 8333056236493354663, guid: 13367afdf20e47f40b184469b5e36efd, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 0.92, g: 0.91, b: 0.86, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 20
|
||||
m_fontSizeBase: 20
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 1
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &3028599952828932685
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8638408449368862406}
|
||||
- component: {fileID: 9093197756632392431}
|
||||
- component: {fileID: 8448248933604724443}
|
||||
- component: {fileID: 571939219385614648}
|
||||
m_Layer: 0
|
||||
m_Name: CloseButton
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &8638408449368862406
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3028599952828932685}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 3844761814136918061}
|
||||
m_Father: {fileID: 8277422716032291198}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.32, y: 0.08}
|
||||
m_AnchorMax: {x: 0.68, y: 0.25}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &9093197756632392431
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3028599952828932685}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &8448248933604724443
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3028599952828932685}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.18, g: 0.19, b: 0.19, a: 0.98}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &571939219385614648
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3028599952828932685}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 8448248933604724443}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &5016995505581043146
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8277422716032291198}
|
||||
- component: {fileID: 9109043046766128537}
|
||||
- component: {fileID: 3344880143442789142}
|
||||
m_Layer: 0
|
||||
m_Name: Panel
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &8277422716032291198
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5016995505581043146}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 4060912498424251528}
|
||||
- {fileID: 2439426371679133391}
|
||||
- {fileID: 8638408449368862406}
|
||||
m_Father: {fileID: 4709999122157385881}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.3, y: 0.32}
|
||||
m_AnchorMax: {x: 0.7, y: 0.68}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &9109043046766128537
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5016995505581043146}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &3344880143442789142
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5016995505581043146}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.11, g: 0.12, b: 0.12, a: 1}
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &6064900120442679474
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4709999122157385881}
|
||||
- component: {fileID: 4245676085209672744}
|
||||
m_Layer: 0
|
||||
m_Name: ModalOverlay
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4709999122157385881
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6064900120442679474}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 7134254617425657058}
|
||||
- {fileID: 8277422716032291198}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!225 &4245676085209672744
|
||||
CanvasGroup:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6064900120442679474}
|
||||
m_Enabled: 1
|
||||
m_Alpha: 1
|
||||
m_Interactable: 1
|
||||
m_BlocksRaycasts: 1
|
||||
m_IgnoreParentGroups: 0
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fce8f35ff57b4a428f1c1a1e3a1de62
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||