Build clean UPM package for Hand Driver

upm
SuGar-456 3 months ago
parent a2715844f6
commit eeb4498e5a
  1. 10
      HandDriver/package.json
  2. 8
      Samples~/Hand Driver Demo/HandDriver/Model.meta
  3. BIN
      Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.jpg
  4. 135
      Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.jpg.meta
  5. 82
      Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.mat
  6. 8
      Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_color.mat.meta
  7. BIN
      Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_new.fbx
  8. 106
      Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_new.fbx.meta
  9. BIN
      Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_normal.png
  10. 135
      Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_normal.png.meta
  11. BIN
      Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_right_model.fbx
  12. 106
      Samples~/Hand Driver Demo/HandDriver/Model/vr_glove_right_model.fbx.meta
  13. BIN
      Samples~/Hand Driver Demo/HandDriver/Model/vr_gloves_prototype.fbx
  14. 106
      Samples~/Hand Driver Demo/HandDriver/Model/vr_gloves_prototype.fbx.meta
  15. 8
      Samples~/Hand Driver Demo/HandDriver/Plugins.meta
  16. 8
      Samples~/Hand Driver Demo/HandDriver/Scenes.meta
  17. 2561
      Samples~/Hand Driver Demo/HandDriver/Scenes/Sample.unity
  18. 7
      Samples~/Hand Driver Demo/HandDriver/Scenes/Sample.unity.meta
  19. 8
      Samples~/Hand Driver Demo/HandDriver/Scripts.meta
  20. 698
      Samples~/Hand Driver Demo/HandDriver/Scripts/HandDriver.cs
  21. 11
      Samples~/Hand Driver Demo/HandDriver/Scripts/HandDriver.cs.meta
  22. 35
      Samples~/Hand Driver Demo/HandDriver/Scripts/InputData.cs
  23. 11
      Samples~/Hand Driver Demo/HandDriver/Scripts/InputData.cs.meta
  24. 207
      Samples~/Hand Driver Demo/HandDriver/Scripts/Network.cs
  25. 11
      Samples~/Hand Driver Demo/HandDriver/Scripts/Network.cs.meta
  26. 33
      Samples~/Hand Driver Demo/HandDriver/Scripts/VibrationData.cs
  27. 11
      Samples~/Hand Driver Demo/HandDriver/Scripts/VibrationData.cs.meta
  28. 8
      Samples~/Hand Driver Demo/HandDriver/_3rd.meta
  29. 8
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket.meta
  30. 8
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core.meta
  31. 8
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager.meta
  32. 1309
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ByteBlock.cs
  33. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ByteBlock.cs.meta
  34. 438
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytePool.cs
  35. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytePool.cs.meta
  36. 57
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytesQueue.cs
  37. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/BytesQueue.cs.meta
  38. 1249
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ValueByteBlock.cs
  39. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/ByteManager/ValueByteBlock.cs.meta
  40. 8
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching.meta
  41. 61
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheEntry.cs
  42. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheEntry.cs.meta
  43. 58
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheManagementExtensions.cs
  44. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/CacheManagementExtensions.cs.meta
  45. 106
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICache.cs
  46. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICache.cs.meta
  47. 48
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICacheEntry.cs
  48. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/ICacheEntry.cs.meta
  49. 319
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/MemoryCache.cs
  50. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Caching/MemoryCache.cs.meta
  51. 8
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections.meta
  52. 8
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent.meta
  53. 125
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentDoublyDictionary.cs
  54. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentDoublyDictionary.cs.meta
  55. 680
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentList.cs
  56. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentList.cs.meta
  57. 194
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentMultiDictionary.cs
  58. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/ConcurrentMultiDictionary.cs.meta
  59. 78
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentConcurrentQueue.cs
  60. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentConcurrentQueue.cs.meta
  61. 233
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentDataQueue.cs
  62. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/IntelligentDataQueue.cs.meta
  63. 150
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/TriggerQueue.cs
  64. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/Concurrent/TriggerQueue.cs.meta
  65. 32
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/IgnoreCaseNameValueCollection.cs
  66. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/IgnoreCaseNameValueCollection.cs.meta
  67. 50
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/NameValueCollectionDebugView.cs
  68. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Collections/NameValueCollectionDebugView.cs.meta
  69. 8
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common.meta
  70. 137
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/AppConfigBase.cs
  71. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/AppConfigBase.cs.meta
  72. 48
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DateExtensions.cs
  73. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DateExtensions.cs.meta
  74. 51
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DisposableObject.cs
  75. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/DisposableObject.cs.meta
  76. 8
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum.meta
  77. 31
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/EndianType.cs
  78. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/EndianType.cs.meta
  79. 56
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/ResultCode.cs
  80. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Enum/ResultCode.cs.meta
  81. 112
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/FlowGate.cs
  82. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/FlowGate.cs.meta
  83. 19
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/GlobalEnvironment.cs
  84. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/GlobalEnvironment.cs.meta
  85. 30
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IResult.cs
  86. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IResult.cs.meta
  87. 35
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IWrite.cs
  88. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/IWrite.cs.meta
  89. 69
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Locker.cs
  90. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Locker.cs.meta
  91. 70
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Metadata.cs
  92. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Metadata.cs.meta
  93. 43
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/MetadataFastBinaryConverter.cs
  94. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/MetadataFastBinaryConverter.cs.meta
  95. 26
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/OptimizedPlatforms.cs
  96. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/OptimizedPlatforms.cs.meta
  97. 268
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Result.cs
  98. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/Result.cs.meta
  99. 129
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/SnowflakeIDGenerator.cs
  100. 11
      Samples~/Hand Driver Demo/HandDriver/_3rd/TouchSocket/Core/Common/SnowflakeIDGenerator.cs.meta
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,10 +0,0 @@
{
"name": "com.udexreal.handdriver",
"displayName": "HandDriver",
"description": ""HandDriver",
"version": "2.1.8",
"unity": "2022.3",
"license": "MIT",
"dependencies": {
}
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 KiB

@ -0,0 +1,135 @@
fileFormatVersion: 2
guid: 8589e8bfc64b93b4a8143d70c9127abd
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,82 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: vr_glove_color
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_ValidKeywords:
- _EMISSION
- _NORMALMAP
m_InvalidKeywords: []
m_LightmapFlags: 1
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 2800000, guid: ed1b2724730cc594aa8c79b70d2deb24, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: f1ba7622665bf7e44aee3f43fc62e51d, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
m_BuildTextureStacks: []

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a824637846136a043bd018d27422dfd7
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,106 @@
fileFormatVersion: 2
guid: 7c6fe65dc83e437438be792aad474a5d
ModelImporter:
serializedVersion: 21300
internalIDToNameTable: []
externalObjects: {}
materials:
materialImportMode: 2
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 1
motionNodeName:
rigImportErrors:
rigImportWarnings:
animationImportErrors:
animationImportWarnings:
animationRetargetingWarnings:
animationDoRetargetingWarnings: 0
importAnimatedCustomProperties: 0
importConstraints: 0
animationCompression: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
meshes:
lODScreenPercentages: []
globalScale: 1
meshCompression: 0
addColliders: 0
useSRGBMaterialColor: 1
sortHierarchyByName: 1
importVisibility: 1
importBlendShapes: 1
importCameras: 1
importLights: 1
nodeNameCollisionStrategy: 1
fileIdsGeneration: 2
swapUVChannels: 0
generateSecondaryUV: 0
useFileUnits: 1
keepQuads: 0
weldVertices: 1
bakeAxisConversion: 0
preserveHierarchy: 0
skinWeightsMode: 0
maxBonesPerVertex: 4
minBoneWeight: 0.001
optimizeBones: 1
meshOptimizationFlags: -1
indexFormat: 0
secondaryUVAngleDistortion: 8
secondaryUVAreaDistortion: 15.000001
secondaryUVHardAngle: 88
secondaryUVMarginMethod: 1
secondaryUVMinLightmapResolution: 40
secondaryUVMinObjectScale: 1
secondaryUVPackMargin: 4
useFileScale: 1
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
humanDescription:
serializedVersion: 3
human: []
skeleton: []
armTwist: 0.5
foreArmTwist: 0.5
upperLegTwist: 0.5
legTwist: 0.5
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
globalScale: 1
rootMotionBoneName:
hasTranslationDoF: 0
hasExtraRoot: 0
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 0
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

@ -0,0 +1,135 @@
fileFormatVersion: 2
guid: 3748dee6899f1094a9133c221951f5e9
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 1
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,106 @@
fileFormatVersion: 2
guid: c4e403660ace5984b8a2ec3594efa03b
ModelImporter:
serializedVersion: 21300
internalIDToNameTable: []
externalObjects: {}
materials:
materialImportMode: 2
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 1
motionNodeName:
rigImportErrors:
rigImportWarnings:
animationImportErrors:
animationImportWarnings:
animationRetargetingWarnings:
animationDoRetargetingWarnings: 0
importAnimatedCustomProperties: 0
importConstraints: 0
animationCompression: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
meshes:
lODScreenPercentages: []
globalScale: 1
meshCompression: 0
addColliders: 0
useSRGBMaterialColor: 1
sortHierarchyByName: 1
importVisibility: 1
importBlendShapes: 1
importCameras: 1
importLights: 1
nodeNameCollisionStrategy: 1
fileIdsGeneration: 2
swapUVChannels: 0
generateSecondaryUV: 0
useFileUnits: 1
keepQuads: 0
weldVertices: 1
bakeAxisConversion: 0
preserveHierarchy: 0
skinWeightsMode: 0
maxBonesPerVertex: 4
minBoneWeight: 0.001
optimizeBones: 1
meshOptimizationFlags: -1
indexFormat: 0
secondaryUVAngleDistortion: 8
secondaryUVAreaDistortion: 15.000001
secondaryUVHardAngle: 88
secondaryUVMarginMethod: 1
secondaryUVMinLightmapResolution: 40
secondaryUVMinObjectScale: 1
secondaryUVPackMargin: 4
useFileScale: 1
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
humanDescription:
serializedVersion: 3
human: []
skeleton: []
armTwist: 0.5
foreArmTwist: 0.5
upperLegTwist: 0.5
legTwist: 0.5
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
globalScale: 1
rootMotionBoneName:
hasTranslationDoF: 0
hasExtraRoot: 0
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 0
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,106 @@
fileFormatVersion: 2
guid: fd5d3b6f78f09274297fdd339530e6cf
ModelImporter:
serializedVersion: 21300
internalIDToNameTable: []
externalObjects: {}
materials:
materialImportMode: 2
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 1
motionNodeName:
rigImportErrors:
rigImportWarnings:
animationImportErrors:
animationImportWarnings:
animationRetargetingWarnings:
animationDoRetargetingWarnings: 0
importAnimatedCustomProperties: 0
importConstraints: 0
animationCompression: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
meshes:
lODScreenPercentages: []
globalScale: 1
meshCompression: 0
addColliders: 0
useSRGBMaterialColor: 1
sortHierarchyByName: 1
importVisibility: 1
importBlendShapes: 1
importCameras: 1
importLights: 1
nodeNameCollisionStrategy: 1
fileIdsGeneration: 2
swapUVChannels: 0
generateSecondaryUV: 0
useFileUnits: 1
keepQuads: 0
weldVertices: 1
bakeAxisConversion: 0
preserveHierarchy: 0
skinWeightsMode: 0
maxBonesPerVertex: 4
minBoneWeight: 0.001
optimizeBones: 1
meshOptimizationFlags: -1
indexFormat: 0
secondaryUVAngleDistortion: 8
secondaryUVAreaDistortion: 15.000001
secondaryUVHardAngle: 88
secondaryUVMarginMethod: 1
secondaryUVMinLightmapResolution: 40
secondaryUVMinObjectScale: 1
secondaryUVPackMargin: 4
useFileScale: 1
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
humanDescription:
serializedVersion: 3
human: []
skeleton: []
armTwist: 0.5
foreArmTwist: 0.5
upperLegTwist: 0.5
legTwist: 0.5
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
globalScale: 1
rootMotionBoneName:
hasTranslationDoF: 0
hasExtraRoot: 0
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 0
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:

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

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

File diff suppressed because it is too large Load Diff

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

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

@ -0,0 +1,698 @@
using NaughtyAttributes;
using System.Collections.Generic;
using TouchSocket.Core;
using UnityEngine;
public class HandDriver : MonoBehaviour
{
public Network Network;
public enum HandType
{
Left,
Right
}
public enum Axis
{
x,
y,
z,
x_n,
y_n,
z_n
}
public string CharacterName = string.Empty;
public HandType Hand;
private Dictionary<string, Quaternion> _originQuaternionDic;
public Transform Thumb1;
public Transform Thumb2;
public Transform Thumb3;
public Transform Index1;
public Transform Index2;
public Transform Index3;
public Transform Middle1;
public Transform Middle2;
public Transform Middle3;
public Transform Ring1;
public Transform Ring2;
public Transform Ring3;
public Transform Pinky1;
public Transform Pinky2;
public Transform Pinky3;
public Transform Wrist;
[Header("[Axis OffSet]")]
public Axis Pitch = Axis.x;
public Axis Roll = Axis.y;
public Axis Yaw = Axis.z;
[Header("[IMU(On/Off)]")] public bool HasIMU = false;
[Header("[Thumb Root Coefficient]")] [Range(0, 1)] public float coefficient = 0.6f;
[Header("[Thumb Root OffSet]")] public Vector3 Thumb1Offset;
[Header("[App Options]")]
public bool NeedRealTransfrom;
//[HideInInspector]
public bool UsingNetwork;
public bool UsingAndroidService;
[Header("[Vector3 Angles]")]
public Vector3 thumb1;
public Vector3 thumb2;
public Vector3 thumb3;
public Vector3 index1;
public Vector3 index2;
public Vector3 index3;
public Vector3 middle1;
public Vector3 middle2;
public Vector3 middle3;
public Vector3 ring1;
public Vector3 ring2;
public Vector3 ring3;
public Vector3 pinky1;
public Vector3 pinky2;
public Vector3 pinky3;
[Header("[Controller Values]")]
public float Joy_X;
public float Joy_Y;
public bool Button_A;
public bool Button_B;
public bool Button_Joystick;
public bool Button_Menu;
public InputData inputData = new();
[Header("[Vibration Control]")]
public string SendBackIP;
public VibrationData vibrationData;
[BoxGroup("Vibrator 1"), Min(0), Label("Million Second")]
public int Duration1 = 20;
[BoxGroup("Vibrator 1"), Range(4, 10)]
public int Amplitude1 = 4;
[Button]
public void Vibrator_1Active()
{
if (Network == null) return;
SingleVirbator[] Virbators;
if (Hand == HandType.Left)
{
Virbators = new SingleVirbator[2]
{
new SingleVirbator(1, Duration1, Amplitude1),
new SingleVirbator()
};
vibrationData = new VibrationData(Virbators);
}
else
{
Virbators = new SingleVirbator[2]
{
new SingleVirbator(),
new SingleVirbator(1, Duration1, Amplitude1),
};
vibrationData = new VibrationData(Virbators);
}
Network.SendVibrationMsg(CharacterName, SendBackIP, vibrationData);
}
[BoxGroup("Vibrator 2"), Min(0), Label("Million Second")]
public int Duration2 = 20;
[BoxGroup("Vibrator 2"), Range(4, 10)]
public int Amplitude2 = 4;
[Button]
public void Vibrator_2Active()
{
if (Network == null) return;
SingleVirbator[] Virbators;
if (Hand == HandType.Left)
{
Virbators = new SingleVirbator[2]
{
new SingleVirbator(2, Duration2, Amplitude2),
new SingleVirbator()
};
vibrationData = new VibrationData(Virbators);
}
else
{
Virbators = new SingleVirbator[2]
{
new SingleVirbator(),
new SingleVirbator(2, Duration2, Amplitude2),
};
vibrationData = new VibrationData(Virbators);
}
Network.SendVibrationMsg(CharacterName, SendBackIP, vibrationData);
}
[Button]
public void BothActiveWithVibrator_1Parameters()
{
if (Network == null) return;
SingleVirbator[] Virbators;
if (Hand == HandType.Left)
{
Virbators = new SingleVirbator[2]
{
new SingleVirbator(3, Duration1, Amplitude1),
new SingleVirbator()
};
vibrationData = new VibrationData(Virbators);
}
else
{
Virbators = new SingleVirbator[2]
{
new SingleVirbator(),
new SingleVirbator(3, Duration1, Amplitude1),
};
vibrationData = new VibrationData(Virbators);
}
Network.SendVibrationMsg(CharacterName, SendBackIP, vibrationData);
}
// Start is called before the first frame update
void Start()
{
if (GameObject.Find("Network") == null && (UsingAndroidService || UsingNetwork))
{
GameObject network = new GameObject("Network");
network.AddComponent<Network>();
Network = GameObject.Find("Network").GetComponent<Network>();
}
else if (UsingAndroidService || UsingNetwork)
{
Network = GameObject.Find("Network").GetComponent<Network>();
}
_originQuaternionDic = new Dictionary<string, Quaternion>();
InitJoints();
if (string.IsNullOrEmpty(SendBackIP) || UsingAndroidService)
{
SendBackIP = "127.0.0.1";
}
var Virbators = new SingleVirbator[2]
{
new SingleVirbator(0, 0, 1),
new SingleVirbator(0, 0, 1)
};
vibrationData = new VibrationData(Virbators);
if(UsingAndroidService)
{
CharacterName = "AndroidService";
}
}
private void InitJoints()
{
_originQuaternionDic.AddOrUpdate(Thumb1.name, Thumb1.localRotation);
_originQuaternionDic.AddOrUpdate(Thumb2.name, Thumb2.localRotation);
_originQuaternionDic.AddOrUpdate(Thumb3.name, Thumb3.localRotation);
_originQuaternionDic.AddOrUpdate(Index1.name, Index1.localRotation);
_originQuaternionDic.AddOrUpdate(Index2.name, Index2.localRotation);
_originQuaternionDic.AddOrUpdate(Index3.name, Index3.localRotation);
_originQuaternionDic.AddOrUpdate(Middle1.name, Middle1.localRotation);
_originQuaternionDic.AddOrUpdate(Middle2.name, Middle2.localRotation);
_originQuaternionDic.AddOrUpdate(Middle3.name, Middle3.localRotation);
_originQuaternionDic.AddOrUpdate(Ring1.name, Ring1.localRotation);
_originQuaternionDic.AddOrUpdate(Ring2.name, Ring2.localRotation);
_originQuaternionDic.AddOrUpdate(Ring3.name, Ring3.localRotation);
_originQuaternionDic.AddOrUpdate(Pinky1.name, Pinky1.localRotation);
_originQuaternionDic.AddOrUpdate(Pinky2.name, Pinky2.localRotation);
_originQuaternionDic.AddOrUpdate(Pinky3.name, Pinky3.localRotation);
_originQuaternionDic.AddOrUpdate(Wrist.name, Wrist.localRotation);
}
private void Rotate(Transform tran, float angle, Axis angleType)
{
if (!NeedRealTransfrom) return;
float angleX = 0;
float angleY = 0;
float angleZ = 0;
switch (angleType)
{
case Axis.x_n:
angleX = -angle;
break;
case Axis.y_n:
angleY = -angle;
break;
case Axis.z_n:
angleZ = -angle;
break;
case Axis.x:
angleX = angle;
break;
case Axis.y:
angleY = angle;
break;
case Axis.z:
angleZ = angle;
break;
}
tran.Rotate(angleX, angleY, angleZ);
}
private Vector3 ConvertAngleToVec3(Vector3 current, float angle, Axis angleType)
{
float angleX = 0;
float angleY = 0;
float angleZ = 0;
switch (angleType)
{
case Axis.x_n:
angleX = -angle;
break;
case Axis.y_n:
angleY = -angle;
break;
case Axis.z_n:
angleZ = -angle;
break;
case Axis.x:
angleX = angle;
break;
case Axis.y:
angleY = angle;
break;
case Axis.z:
angleZ = angle;
break;
}
return current + new Vector3(angleX, angleY, angleZ);
}
private void ResetRotation(Transform trans)
{
if (_originQuaternionDic.TryGetValue(trans.name, out Quaternion rot))
{
trans.localRotation = rot;
}
}
public void GetVec3Value(Vector3[] value)
{
thumb1 = value[0];
thumb2 = value[1];
thumb3 = value[2];
index1 = value[3];
index2 = value[4];
index3 = value[5];
middle1 = value[6];
middle2 = value[7];
middle3 = value[8];
ring1 = value[9];
ring2 = value[10];
ring3 = value[11];
pinky1 = value[12];
pinky2 = value[13];
pinky3 = value[14];
}
// Update is called once per frame
void Update()
{
if (UsingNetwork || UsingAndroidService)
{
UpdateThumb();
UpdateIndex();
UpdateMiddle();
UpdateRing();
UpdatePinky();
UpdateWrist();
UpdateController();
}
}
private void UpdateWrist()
{
if (HasIMU)
{
if (Hand == HandType.Left)
{
Quaternion quat_r = new Quaternion(
Network.Convert2Angle(CharacterName, "l26"),//x
Network.Convert2Angle(CharacterName, "l25"),//y
Network.Convert2Angle(CharacterName, "l27"),//z
Network.Convert2Angle(CharacterName, "l24"));//w
ResetRotation(Wrist);
quat_r = ConvertQuaternion(quat_r);
Wrist.rotation = quat_r;
}
else
{
Quaternion quat_r = new Quaternion(Network.Convert2Angle(CharacterName, "r26"),
Network.Convert2Angle(CharacterName, "r25"),
Network.Convert2Angle(CharacterName, "r27"), Network.Convert2Angle(CharacterName, "r24"));
ResetRotation(Wrist);
quat_r = ConvertQuaternion(quat_r);
Wrist.rotation = quat_r;
}
}
}
private void UpdateController()
{
if (Hand == HandType.Left)
{
Joy_X = Network.Convert2Angle(CharacterName, "l_joyX");
Joy_Y = Network.Convert2Angle(CharacterName, "l_joyY");
Button_A = Network.Convert2Bool(CharacterName, "l_aButton");
Button_B = Network.Convert2Bool(CharacterName, "l_bButton");
Button_Joystick = Network.Convert2Bool(CharacterName, "l_joyButton");
Button_Menu = Network.Convert2Bool(CharacterName, "l_menu");
inputData.joyX = Joy_X;
inputData.joyY = Joy_Y;
inputData.aButton = Button_A;
inputData.bButton = Button_B;
inputData.joyButton = Button_Joystick;
inputData.menu = Button_Menu;
}
else
{
Joy_X = Network.Convert2Angle(CharacterName, "r_joyX");
Joy_Y = Network.Convert2Angle(CharacterName, "r_joyY");
Button_A = Network.Convert2Bool(CharacterName, "r_aButton");
Button_B = Network.Convert2Bool(CharacterName, "r_bButton");
Button_Joystick = Network.Convert2Bool(CharacterName, "r_joyButton");
Button_Menu = Network.Convert2Bool(CharacterName, "r_menu");
inputData.joyX = Joy_X;
inputData.joyY = Joy_Y;
inputData.aButton = Button_A;
inputData.bButton = Button_B;
inputData.joyButton = Button_Joystick;
inputData.menu = Button_Menu;
}
}
//z轴朝上的右手坐标系 四元数 转换为 Y轴朝上的左手坐标系 四元数
private Quaternion ConvertQuaternion(Quaternion quat)
{
Quaternion quat_r = new Quaternion(quat.x, quat.y, quat.z, quat.w);
quat_r = Quaternion.Euler(quat_r.eulerAngles.z, -quat_r.eulerAngles.x, quat_r.eulerAngles.y);
return quat_r;
}
private void UpdateThumb()
{
if (NeedRealTransfrom)
{
ResetRotation(Thumb1);
ResetRotation(Thumb2);
ResetRotation(Thumb3);
}
if (Hand == HandType.Left)
{
var thumb3Pitch = Network.Convert2Angle(CharacterName, "l0");
var thumb2Pitch = Network.Convert2Angle(CharacterName, "l1");
var thumb1Pitch = Network.Convert2Angle(CharacterName, "l2") * coefficient + Thumb1Offset.y;
var thumb1Yaw = Network.Convert2Angle(CharacterName, "l3") + Thumb1Offset.z;
var thumb1Roll = Network.Convert2Angle(CharacterName, "l20") + Thumb1Offset.x;
thumb3 = ConvertAngleToVec3(Vector3.zero, thumb3Pitch, Pitch);
thumb2 = ConvertAngleToVec3(Vector3.zero, thumb2Pitch, Pitch);
thumb1 = ConvertAngleToVec3(Vector3.zero, thumb1Pitch, Pitch);
thumb1 = ConvertAngleToVec3(thumb1, thumb1Yaw, Yaw);
thumb1 = ConvertAngleToVec3(thumb1, thumb1Roll, Roll);
Rotate(Thumb3, thumb3Pitch, Pitch);
Rotate(Thumb2, thumb2Pitch, Pitch);
Rotate(Thumb1, thumb1Pitch, Pitch);
Rotate(Thumb1, thumb1Yaw, Yaw);
Rotate(Thumb1, thumb1Roll, Roll);
}
else
{
var thumb3Pitch = Network.Convert2Angle(CharacterName, "r0");
var thumb2Pitch = Network.Convert2Angle(CharacterName, "r1");
var thumb1Pitch = Network.Convert2Angle(CharacterName, "r2") * coefficient + Thumb1Offset.y;
var thumb1Yaw = Network.Convert2Angle(CharacterName, "r3") + Thumb1Offset.z;
var thumb1Roll = Network.Convert2Angle(CharacterName, "r20") + Thumb1Offset.x;
thumb3 = ConvertAngleToVec3(Vector3.zero, thumb3Pitch, Pitch);
thumb2 = ConvertAngleToVec3(Vector3.zero, thumb2Pitch, Pitch);
thumb1 = ConvertAngleToVec3(Vector3.zero, thumb1Pitch, Pitch);
thumb1 = ConvertAngleToVec3(thumb1, thumb1Yaw, Yaw);
thumb1 = ConvertAngleToVec3(thumb1, thumb1Roll, Roll);
Rotate(Thumb3, thumb3Pitch, Pitch);
Rotate(Thumb2, thumb2Pitch, Pitch);
Rotate(Thumb1, thumb1Pitch, Pitch);
Rotate(Thumb1, thumb1Yaw, Yaw);
Rotate(Thumb1, thumb1Roll, Roll);
}
}
private void UpdateIndex()
{
if (NeedRealTransfrom)
{
ResetRotation(Index1);
ResetRotation(Index2);
ResetRotation(Index3);
}
if (Hand == HandType.Left)
{
var index3Pitch = Network.Convert2Angle(CharacterName, "l4");
var index2Pitch = Network.Convert2Angle(CharacterName, "l5");
var index1Pitch = Network.Convert2Angle(CharacterName, "l6");
var index1Yaw = Network.Convert2Angle(CharacterName, "l7");
var index1Roll = Network.Convert2Angle(CharacterName, "l21");
index3 = ConvertAngleToVec3(Vector3.zero, index3Pitch, Pitch);
index2 = ConvertAngleToVec3(Vector3.zero, index2Pitch, Pitch);
index1 = ConvertAngleToVec3(Vector3.zero, index1Pitch, Pitch);
index1 = ConvertAngleToVec3(index1, index1Yaw, Yaw);
index1 = ConvertAngleToVec3(index1, index1Roll, Roll);
Rotate(Index3, index3Pitch, Pitch);
Rotate(Index2, index2Pitch, Pitch);
Rotate(Index1, index1Pitch, Pitch);
Rotate(Index1, index1Yaw, Yaw);
Rotate(Index1, index1Roll, Roll);
}
else
{
var index3Pitch = Network.Convert2Angle(CharacterName, "r4");
var index2Pitch = Network.Convert2Angle(CharacterName, "r5");
var index1Pitch = Network.Convert2Angle(CharacterName, "r6");
var index1Yaw = Network.Convert2Angle(CharacterName, "r7");
var index1Roll = Network.Convert2Angle(CharacterName, "r21");
index3 = ConvertAngleToVec3(Vector3.zero, index3Pitch, Pitch);
index2 = ConvertAngleToVec3(Vector3.zero, index2Pitch, Pitch);
index1 = ConvertAngleToVec3(Vector3.zero, index1Pitch, Pitch);
index1 = ConvertAngleToVec3(index1, index1Yaw, Yaw);
index1 = ConvertAngleToVec3(index1, index1Roll, Roll);
Rotate(Index3, index3Pitch, Pitch);
Rotate(Index2, index2Pitch, Pitch);
Rotate(Index1, index1Pitch, Pitch);
Rotate(Index1, index1Yaw, Yaw);
Rotate(Index1, index1Roll, Roll);
}
}
private void UpdateMiddle()
{
if (NeedRealTransfrom)
{
ResetRotation(Middle1);
ResetRotation(Middle2);
ResetRotation(Middle3);
}
if (Hand == HandType.Left)
{
var middle3Pitch = Network.Convert2Angle(CharacterName, "l8");
var middle2Pitch = Network.Convert2Angle(CharacterName, "l9");
var middle1Pitch = Network.Convert2Angle(CharacterName, "l10");
var middle1Yaw = Network.Convert2Angle(CharacterName, "l11");
middle3 = ConvertAngleToVec3(Vector3.zero, middle3Pitch, Pitch);
middle2 = ConvertAngleToVec3(Vector3.zero, middle2Pitch, Pitch);
middle1 = ConvertAngleToVec3(Vector3.zero, middle1Pitch, Pitch);
middle1 = ConvertAngleToVec3(middle1, middle1Yaw, Yaw);
Rotate(Middle3, middle3Pitch, Pitch);
Rotate(Middle2, middle2Pitch, Pitch);
Rotate(Middle1, middle1Pitch, Pitch);
Rotate(Middle1, middle1Yaw, Yaw);
}
else
{
var middle3Pitch = Network.Convert2Angle(CharacterName, "r8");
var middle2Pitch = Network.Convert2Angle(CharacterName, "r9");
var middle1Pitch = Network.Convert2Angle(CharacterName, "r10");
var middle1Yaw = Network.Convert2Angle(CharacterName, "r11");
middle3 = ConvertAngleToVec3(Vector3.zero, middle3Pitch, Pitch);
middle2 = ConvertAngleToVec3(Vector3.zero, middle2Pitch, Pitch);
middle1 = ConvertAngleToVec3(Vector3.zero, middle1Pitch, Pitch);
middle1 = ConvertAngleToVec3(middle1, middle1Yaw, Yaw);
Rotate(Middle3, middle3Pitch, Pitch);
Rotate(Middle2, middle2Pitch, Pitch);
Rotate(Middle1, middle1Pitch, Pitch);
Rotate(Middle1, middle1Yaw, Yaw);
}
}
private void UpdateRing()
{
if (NeedRealTransfrom)
{
ResetRotation(Ring1);
ResetRotation(Ring2);
ResetRotation(Ring3);
}
if (Hand == HandType.Left)
{
var ring3Pitch = Network.Convert2Angle(CharacterName, "l12");
var ring2Pitch = Network.Convert2Angle(CharacterName, "l13");
var ring1Pitch = Network.Convert2Angle(CharacterName, "l14");
var ring1Yaw = Network.Convert2Angle(CharacterName, "l15");
ring3 = ConvertAngleToVec3(Vector3.zero, ring3Pitch, Pitch);
ring2 = ConvertAngleToVec3(Vector3.zero, ring2Pitch, Pitch);
ring1 = ConvertAngleToVec3(Vector3.zero, ring1Pitch, Pitch);
ring1 = ConvertAngleToVec3(ring1, ring1Yaw, Yaw);
Rotate(Ring3, ring3Pitch, Pitch);
Rotate(Ring2, ring2Pitch, Pitch);
Rotate(Ring1, ring1Pitch, Pitch);
Rotate(Ring1, ring1Yaw, Yaw);
}
else
{
var ring3Pitch = Network.Convert2Angle(CharacterName, "r12");
var ring2Pitch = Network.Convert2Angle(CharacterName, "r13");
var ring1Pitch = Network.Convert2Angle(CharacterName, "r14");
var ring1Yaw = Network.Convert2Angle(CharacterName, "r15");
ring3 = ConvertAngleToVec3(Vector3.zero, ring3Pitch, Pitch);
ring2 = ConvertAngleToVec3(Vector3.zero, ring2Pitch, Pitch);
ring1 = ConvertAngleToVec3(Vector3.zero, ring1Pitch, Pitch);
ring1 = ConvertAngleToVec3(ring1, ring1Yaw, Yaw);
Rotate(Ring3, ring3Pitch, Pitch);
Rotate(Ring2, ring2Pitch, Pitch);
Rotate(Ring1, ring1Pitch, Pitch);
Rotate(Ring1, ring1Yaw, Yaw);
}
}
private void UpdatePinky()
{
if (NeedRealTransfrom)
{
ResetRotation(Pinky1);
ResetRotation(Pinky2);
ResetRotation(Pinky3);
}
if (Hand == HandType.Left)
{
var pinky3Pitch = Network.Convert2Angle(CharacterName, "l16");
var pinky2Pitch = Network.Convert2Angle(CharacterName, "l17");
var pinky1Pitch = Network.Convert2Angle(CharacterName, "l18");
var pinky1Yaw = Network.Convert2Angle(CharacterName, "l19");
var pinky1Roll = Network.Convert2Angle(CharacterName, "l22");
pinky3 = ConvertAngleToVec3(Vector3.zero, pinky3Pitch, Pitch);
pinky2 = ConvertAngleToVec3(Vector3.zero, pinky2Pitch, Pitch);
pinky1 = ConvertAngleToVec3(Vector3.zero, pinky1Pitch, Pitch);
pinky1 = ConvertAngleToVec3(pinky1, pinky1Yaw, Yaw);
pinky1 = ConvertAngleToVec3(pinky1, pinky1Roll, Roll);
Rotate(Pinky3, pinky3Pitch, Pitch);
Rotate(Pinky2, pinky2Pitch, Pitch);
Rotate(Pinky1, pinky1Pitch, Pitch);
Rotate(Pinky1, pinky1Yaw, Yaw);
Rotate(Pinky1, pinky1Roll, Roll);
}
else
{
var pinky3Pitch = Network.Convert2Angle(CharacterName, "r16");
var pinky2Pitch = Network.Convert2Angle(CharacterName, "r17");
var pinky1Pitch = Network.Convert2Angle(CharacterName, "r18");
var pinky1Yaw = Network.Convert2Angle(CharacterName, "r19");
var pinky1Roll = Network.Convert2Angle(CharacterName, "r22");
pinky3 = ConvertAngleToVec3(Vector3.zero, pinky3Pitch, Pitch);
pinky2 = ConvertAngleToVec3(Vector3.zero, pinky2Pitch, Pitch);
pinky1 = ConvertAngleToVec3(Vector3.zero, pinky1Pitch, Pitch);
pinky1 = ConvertAngleToVec3(pinky1, pinky1Yaw, Yaw);
pinky1 = ConvertAngleToVec3(pinky1, pinky1Roll, Roll);
Rotate(Pinky3, pinky3Pitch, Pitch);
Rotate(Pinky2, pinky2Pitch, Pitch);
Rotate(Pinky1, pinky1Pitch, Pitch);
Rotate(Pinky1, pinky1Yaw, Yaw);
Rotate(Pinky1, pinky1Roll, Roll);
}
}
public void ServiceVibrationControl(int VirbatorIndex = 1, int DurationSecond = 20, int Strength = 10)
{
if (Network == null || !UsingAndroidService) return;
SingleVirbator[] Virbators;
if (Hand == HandType.Left)
{
Virbators = new SingleVirbator[2]
{
new SingleVirbator(VirbatorIndex, DurationSecond, Strength),
new SingleVirbator()
};
vibrationData = new VibrationData(Virbators);
}
else
{
Virbators = new SingleVirbator[2]
{
new SingleVirbator(),
new SingleVirbator(VirbatorIndex, DurationSecond, Strength),
};
vibrationData = new VibrationData(Virbators);
}
Network.SendVibrationMsg("AndroidService", "127.0.0.1", vibrationData);
}
}

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

@ -0,0 +1,35 @@
//Struct InputData is a struct that contains all of the button, finger, and linear inputs. This is what's sent to the driver via the named pipe.
public struct InputData
{
public float joyX; //range: -1 -> 1
public float joyY; //range: -1 -> 1
public bool joyButton;
public bool trgButton;
public bool aButton;
public bool bButton;
public bool grab;
//public bool pinch;
public bool menu;
//public bool calibrate;
public bool trackpad_touch;
public float trgValue; //range: 0 -> 1
//constructor that uses a 1d array for flexion.
public InputData(float joyX, float joyY, bool joyButton, bool trgButton,
bool aButton, bool bButton, bool grab, bool pinch, bool menu, bool calibrate, float trgValue,bool trackpad_touch)
{
this.joyX = joyX;
this.joyY = joyY;
this.joyButton = joyButton;
this.trgButton = trgButton;
this.aButton = aButton;
this.bButton = bButton;
this.grab = grab;
//this.pinch = pinch;
this.menu = menu;
//this.calibrate = calibrate;
this.trgValue = trgValue;
this.trackpad_touch = trackpad_touch;
}
}

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

@ -0,0 +1,207 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Net;
using System.Text;
using TouchSocket.Core;
using TouchSocket.Sockets;
using UnityEngine;
public class Network : MonoBehaviour
{
public int Port = 5555;
private UdpSession _udpClient;
private ConcurrentDictionary<string, ConcurrentDictionary<string, string>> _deviceReadMessages;
private StreamWriter writer;
private string _txtPath;
void Start()
{
_txtPath = Application.dataPath + "stream.data";
_deviceReadMessages = new ConcurrentDictionary<string, ConcurrentDictionary<string, string>>();
_udpClient = new UdpSession();
_udpClient.Received += ReceiveMsg;
_udpClient.Setup(new TouchSocketConfig()
.SetBindIPHost(new IPHost(Port))
.SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter()))
.Start();
Debug.Log("UDP Client Start!!");
}
private void WriteIntoTxt(string message)
{
FileInfo file = new FileInfo(_txtPath);
if (!file.Exists)
{
writer = file.CreateText();
}
else
{
writer = file.AppendText();
}
writer.WriteLine(message);
writer.Flush();
writer.Dispose();
writer.Close();
}
private void ReceiveMsg(EndPoint endpoint, ByteBlock byteblock, IRequestInfo requestinfo)
{
string msg = Encoding.UTF8.GetString(byteblock.Buffer, 0, byteblock.Len);
Debug.Log(msg);
//WriteIntoTxt(msg);
JObject obj = JObject.Parse(msg);
var jps = obj.Properties();
foreach (var jp in jps)
{
string role_name = jp.Name;
JToken token = obj.GetValue(role_name);
JArray array = token["Parameter"] as JArray;
ConcurrentDictionary<string, string> _deviceMsg = new ConcurrentDictionary<string, string>();
for (int i = 0; i < array.Count; i++)
{
JObject obj1 = array[i] as JObject;
string key = obj1.GetValue("Name").ToString();
string value = obj1.GetValue("Value").ToString();
_deviceMsg.TryAdd(key, value);
}
if (_deviceReadMessages.ContainsKey(role_name))
{
_deviceReadMessages[role_name] = _deviceMsg;
}
else
{
_deviceReadMessages.TryAdd(role_name, _deviceMsg);
}
}
//JToken token = obj.GetValue("Device1_"+Port);
//JArray array = token["Parameter"] as JArray;
//for (int i = 0; i < array.Count; i++)
//{
// JObject obj1 = array[i] as JObject;
// string key = obj1.GetValue("Name").ToString();
// string value = obj1.GetValue("Value").ToString();
// _device1ReadMessages.AddOrUpdate(key, value);
//}
//JToken token2 = obj.GetValue("Device2_"+Port);
//JArray array2 = token2["Parameter"] as JArray;
//for (int i = 0; i < array.Count; i++)
//{
// JObject obj1 = array2[i] as JObject;
// string key = obj1.GetValue("Name").ToString();
// string value = obj1.GetValue("Value").ToString();
// _device2ReadMessages.AddOrUpdate(key, value);
//}
}
// Update is called once per frame
void Update()
{
}
public float Convert2Angle(string role_name, string key)
{
float angle = 0;
if (!string.IsNullOrEmpty(role_name))
{
if (!_deviceReadMessages.ContainsKey(role_name))
{
return 0;
}
string str = _deviceReadMessages[role_name][key];
if (!string.IsNullOrEmpty(str))
{
angle = Single.Parse(str);
}
}
return angle;
}
public bool Convert2Bool(string role_name, string key)
{
bool flag = false;
if (!string.IsNullOrEmpty(role_name))
{
if (!_deviceReadMessages.ContainsKey(role_name))
{
return false;
}
string str = _deviceReadMessages[role_name][key];
if (!string.IsNullOrEmpty(str))
{
flag = bool.Parse(str);
}
}
return flag;
}
public void SendVibrationMsg(string RoleName, string IP, VibrationData data)
{
var json_role = new JObject();
var json_one = new JObject();
var parameterArrayLeft = new JArray();
var parameterArrayRight = new JArray();
var _Lpara_active = new JObject();
_Lpara_active.Add("Name", "Vibrators");
_Lpara_active.Add("Value", data.Virbators[0].ActiveCommand);
var _Lpara_duration = new JObject();
_Lpara_duration.Add("Name", "Duration");
_Lpara_duration.Add("Value", data.Virbators[0].Duration);
var _Lpara_amplitude = new JObject();
_Lpara_amplitude.Add("Name", "Amplitude");
_Lpara_amplitude.Add("Value", data.Virbators[0].Amplitude);
parameterArrayLeft.Add(_Lpara_active);
parameterArrayLeft.Add(_Lpara_duration);
parameterArrayLeft.Add(_Lpara_amplitude);
var _Rpara_active = new JObject();
_Rpara_active.Add("Name", "Vibrators");
_Rpara_active.Add("Value", data.Virbators[1].ActiveCommand);
var _Rpara_duration = new JObject();
_Rpara_duration.Add("Name", "Duration");
_Rpara_duration.Add("Value", data.Virbators[1].Duration);
var _Rpara_amplitude = new JObject();
_Rpara_amplitude.Add("Name", "Amplitude");
_Rpara_amplitude.Add("Value", data.Virbators[1].Amplitude);
parameterArrayRight.Add(_Rpara_active);
parameterArrayRight.Add(_Rpara_duration);
parameterArrayRight.Add(_Rpara_amplitude);
json_one.Add("LeftHand", parameterArrayLeft);
json_one.Add("RightHand", parameterArrayRight);
json_role.Add(RoleName, json_one);
Debug.Log(json_role.ToJson());
_udpClient.Send(new IPEndPoint(IPAddress.Parse(IP), 8920), Encoding.UTF8.GetBytes(json_role.ToJson()));
}
private void OnDestroy()
{
_udpClient.Received -= ReceiveMsg;
_udpClient.Stop();
_udpClient.Dispose();
}
}

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

@ -0,0 +1,33 @@
public struct SingleVirbator
{
public int ActiveCommand;
public int Duration;
public int Amplitude;
public SingleVirbator(int command = 1, int duration = 0, int amplitude = 4)
{
command = command < 1 ? 1 : command > 3 ? 3 : command;
duration = duration < 0 ? 0 : duration;
amplitude = amplitude < 4 ? 4 : amplitude > 10 ? 10 : amplitude;
ActiveCommand = command;
Duration = duration;
Amplitude = amplitude;
}
}
public class VibrationData
{
public SingleVirbator[] Virbators = new SingleVirbator[2];
public VibrationData(SingleVirbator[] virbators)
{
if (virbators.Length != 2) return;
for (int i = 0; i < virbators.Length; i++)
{
Virbators[i] = virbators[i];
}
}
}

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

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

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

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

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

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

@ -0,0 +1,438 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
namespace TouchSocket.Core
{
/// <summary>
/// 内存池
/// </summary>
//[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)]
public partial class BytePool
{
private readonly ConcurrentDictionary<long, BytesQueue> bytesDictionary = new ConcurrentDictionary<long, BytesQueue>();
private readonly Timer m_timer;
private long m_fullSize;
private long m_maxSize;
static BytePool()
{
Default = new BytePool();
}
/// <summary>
/// 内存池
/// </summary>
public BytePool()
{
m_timer = new Timer((o) =>
{
Clear();
}, null, 1000 * 60 * 60, 1000 * 60 * 60);
KeyCapacity = 100;
AutoZero = false;
m_maxSize = 1024 * 1024 * 512;
SetBlockSize(1024, 1024 * 1024 * 20);
AddSizeKey(10240);
}
/// <summary>
/// 默认的内存池实例
/// </summary>
public static BytePool Default { get; }
/// <summary>
/// 回收内存时,自动归零
/// </summary>
public bool AutoZero { get; set; }
/// <summary>
/// 键容量
/// </summary>
public int KeyCapacity { get; set; }
/// <summary>
/// 单个块最大值
/// </summary>
public int MaxBlockSize { get; private set; }
/// <summary>
/// 允许的内存池最大值
/// </summary>
public long MaxSize
{
get => m_maxSize;
set
{
if (value < 1024)
{
value = 1024;
}
m_maxSize = value;
}
}
/// <summary>
/// 单个块最小值
/// </summary>
public int MinBlockSize { get; private set; }
/// <summary>
/// 添加尺寸键
/// </summary>
/// <param name="byteSize"></param>
/// <returns></returns>
public bool AddSizeKey(int byteSize)
{
if (bytesDictionary.TryAdd(byteSize, new BytesQueue(byteSize)))
{
return true;
}
return false;
}
/// <summary>
/// 清理
/// </summary>
public void Clear()
{
bytesDictionary.Clear();
GC.Collect();
}
/// <summary>
/// 确定是否包含指定尺寸键
/// </summary>
/// <param name="byteSize"></param>
/// <returns></returns>
public bool ContainsSizeKey(int byteSize)
{
return bytesDictionary.ContainsKey(byteSize);
}
/// <summary>
/// 获取所以内存键
/// </summary>
/// <returns></returns>
public long[] GetAllSizeKeys()
{
return bytesDictionary.Keys.ToArray();
}
/// <summary>
/// 获取ByteBlock
/// </summary>
/// <param name="byteSize">长度</param>
/// <param name="equalSize">要求长度相同</param>
/// <returns></returns>
public ByteBlock GetByteBlock(int byteSize, bool equalSize)
{
return new ByteBlock(byteSize, equalSize);
}
/// <summary>
/// 获取ByteBlock
/// </summary>
/// <param name="byteSize"></param>
/// <returns></returns>
public ByteBlock GetByteBlock(int byteSize)
{
return new ByteBlock(byteSize, false);
}
/// <summary>
/// 获取内存核心。获取的核心可以不用归还。
/// 如果要调用<see cref="Recycle(byte[])"/>归还,切记不要有持久性引用。
/// </summary>
/// <param name="byteSize"></param>
/// <param name="equalSize"></param>
/// <returns></returns>
public byte[] GetByteCore(int byteSize, bool equalSize = false)
{
BytesQueue bytesCollection;
if (equalSize)
{
//等长
if (bytesDictionary.TryGetValue(byteSize, out bytesCollection))
{
if (bytesCollection.TryGet(out byte[] bytes))
{
m_fullSize -= byteSize;
return bytes;
}
}
else
{
CheckKeyCapacity(byteSize);
}
return new byte[byteSize];
}
else
{
//byteSize = HitSize(byteSize);
//byteSize = byteSize;
//搜索已创建集合
if (bytesDictionary.TryGetValue(byteSize, out bytesCollection))
{
if (bytesCollection.TryGet(out byte[] bytes))
{
m_fullSize -= byteSize;
return bytes;
}
}
else
{
CheckKeyCapacity(byteSize);
}
return new byte[byteSize];
}
}
/// <summary>
/// 获取内存池容量
/// </summary>
/// <returns></returns>
public long GetPoolSize()
{
long size = 0;
foreach (var item in bytesDictionary.Values)
{
size += item.FullSize;
}
return size;
}
/// <summary>
/// 获取ValueByteBlock
/// </summary>
/// <param name="byteSize"></param>
/// <param name="equalSize"></param>
/// <returns></returns>
//[IntelligentCoder.AsyncMethodIgnore]
public ValueByteBlock GetValueByteBlock(int byteSize, bool equalSize)
{
return new ValueByteBlock(byteSize, equalSize);
}
/// <summary>
/// 获取ValueByteBlock
/// </summary>
/// <param name="byteSize"></param>
/// <returns></returns>
//[IntelligentCoder.AsyncMethodIgnore]
public ValueByteBlock GetValueByteBlock(int byteSize)
{
return new ValueByteBlock(byteSize, false);
}
/// <summary>
/// 回收内存核心。
/// <para>注意:回收的内存,必须百分百确定该对象没有再被其他引用。不然这属于危险操作。</para>
/// </summary>
/// <param name="bytes"></param>
public void Recycle(byte[] bytes)
{
if (bytes == null || bytes.Length > MaxBlockSize || bytes.Length < MinBlockSize)
{
return;
}
if (m_maxSize > m_fullSize)
{
if (bytesDictionary.TryGetValue(bytes.Length, out BytesQueue bytesQueue))
{
if (AutoZero)
{
Array.Clear(bytes, 0, bytes.Length);
}
m_fullSize += bytes.Length;
bytesQueue.Add(bytes);
}
}
else
{
long size = 0;
foreach (var collection in bytesDictionary.Values)
{
size += collection.FullSize;
}
m_fullSize = size;
}
}
/// <summary>
/// 移除尺寸键
/// </summary>
/// <param name="byteSize"></param>
/// <returns></returns>
public bool RemoveSizeKey(int byteSize)
{
if (bytesDictionary.TryRemove(byteSize, out BytesQueue queue))
{
queue.Clear();
return true;
}
return false;
}
/// <summary>
/// 设置内存块参数
/// </summary>
/// <param name="minBlockSize"></param>
/// <param name="maxBlockSize"></param>
public void SetBlockSize(int minBlockSize, int maxBlockSize)
{
this.MaxBlockSize = maxBlockSize;
this.MinBlockSize = minBlockSize;
bytesDictionary.Clear();
}
private void CheckKeyCapacity(int byteSize)
{
if (byteSize < MinBlockSize || byteSize > MaxBlockSize)
{
return;
}
if (bytesDictionary.Count < KeyCapacity)
{
bytesDictionary.TryAdd(byteSize, new BytesQueue(byteSize));
}
else
{
List<BytesQueue> bytesQueues = bytesDictionary.Values.ToList();
bytesQueues.Sort((x, y) => { return x.m_referenced > y.m_referenced ? -1 : 1; });
for (int i = (int)(bytesQueues.Count * 0.2); i < bytesQueues.Count; i++)
{
if (bytesDictionary.TryRemove(bytesQueues[i].m_size, out BytesQueue queue))
{
queue.Clear();
}
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int HitSize(int num)
{
if (num < MinBlockSize)
{
num = MinBlockSize;
}
if (num <= 10240)//10k
{
return 10240;
}
else if (num <= 65536)//64k
{
return 65536;
}
else if (num <= 102400)//100k
{
return 102400;
}
else if (num <= 524288) //512k
{
return 524288;
}
else if (num <= 1048576)//1Mb
{
return 1048576;
}
else if (num <= 1048576 * 2)//2Mb
{
return 1048576 * 2;
}
else if (num <= 1048576 * 3)//3Mb
{
return 1048576 * 3;
}
else if (num <= 1048576 * 4)//4Mb
{
return 1048576 * 4;
}
else if (num <= 1048576 * 5)//5Mb
{
return 1048576 * 5;
}
else if (num <= 1048576 * 6)//6Mb
{
return 1048576 * 6;
}
else if (num <= 1048576 * 7)//7Mb
{
return 1048576 * 7;
}
else if (num <= 1048576 * 8)//8Mb
{
return 1048576 * 8;
}
else if (num <= 1048576 * 9)//9Mb
{
return 1048576 * 9;
}
else if (num <= 10485760)//10Mb
{
return 10485760;
}
else if (num <= 1024 * 1024 * 12)//12Mb
{
return 1024 * 1024 * 12;
}
else if (num <= 1024 * 1024 * 15)//15Mb
{
return 1024 * 1024 * 15;
}
else if (num <= 1024 * 1024 * 18)//18Mb
{
return 1024 * 1024 * 18;
}
else if (num <= 1024 * 1024 * 20)//20Mb
{
return 1024 * 1024 * 20;
}
else if (num <= 1024 * 1024 * 30)//30Mb
{
return 1024 * 1024 * 30;
}
else if (num <= 1024 * 1024 * 40)//40Mb
{
return 1024 * 1024 * 40;
}
else if (num <= 1024 * 1024 * 50)//50Mb
{
return 1024 * 1024 * 50;
}
else if (num <= 1024 * 1024 * 100)//100Mb
{
return 1024 * 1024 * 100;
}
else if (num <= 1024 * 1024 * 500)//500Mb
{
return 1024 * 1024 * 500;
}
else if (num <= 1024 * 1024 * 1024)//1Gb
{
return 1024 * 1024 * 1024;
}
else
{
return num;
}
}
}
}

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

@ -0,0 +1,57 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections.Concurrent;
using System.Diagnostics;
namespace TouchSocket.Core
{
/// <summary>
/// 字节块集合
/// </summary>
[DebuggerDisplay("Count = {bytesQueue.Count}")]
internal class BytesQueue: ConcurrentStack<byte[]>
{
internal int m_size;
internal BytesQueue(int size)
{
m_size = size;
}
/// <summary>
/// 占用空间
/// </summary>
public long FullSize => m_size * this.Count;
internal long m_referenced;
/// <summary>
/// 获取当前实例中的空闲的Block
/// </summary>
/// <returns></returns>
public bool TryGet(out byte[] bytes)
{
m_referenced++;
return base.TryPop(out bytes);
}
/// <summary>
/// 向当前集合添加Block
/// </summary>
/// <param name="bytes"></param>
public void Add(byte[] bytes)
{
base.Push(bytes);
}
}
}

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

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

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

@ -0,0 +1,61 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
namespace TouchSocket.Core
{
/// <summary>
/// 缓存实体
/// </summary>
public class CacheEntry<TKey, TValue> : ICacheEntry<TKey, TValue>
{
/// <summary>
/// 缓存实体
/// </summary>
/// <param name="key"></param>
public CacheEntry(TKey key) : this(key, default)
{
}
/// <summary>
/// 缓存实体
/// </summary>
public CacheEntry(TKey key, TValue value)
{
UpdateTime = DateTime.Now;
Duration = TimeSpan.FromSeconds(60);
Key = key;
Value = value;
}
/// <summary>
/// 有效区间。如果想长期有效,请使用<see cref="TimeSpan.Zero"/>
/// </summary>
public TimeSpan Duration { get; set; }
/// <summary>
/// 键
/// </summary>
public TKey Key { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime UpdateTime { get; set; }
/// <summary>
/// 值
/// </summary>
public TValue Value { get; set; }
}
}

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

@ -0,0 +1,58 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
namespace TouchSocket.Core
{
/// <summary>
/// CacheExtensions
/// </summary>
public static class CacheManagementExtensions
{
/// <summary>
/// <inheritdoc cref="ICache{TKey, TValue}.AddCache(ICacheEntry{TKey, TValue})"/>
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="cacheManagement"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="duration"></param>
public static void AddCache<TKey, TValue>(this ICache<TKey, TValue> cacheManagement, TKey key, TValue value, int duration = 60 * 1000)
{
cacheManagement.AddCache(new CacheEntry<TKey, TValue>(key)
{
Value = value,
Duration = TimeSpan.FromMilliseconds(duration)
});
}
/// <summary>
/// <inheritdoc cref="ICache{TKey, TValue}.SetCache(ICacheEntry{TKey, TValue})"/>
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="cacheManagement"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="duration"></param>
public static void SetCache<TKey, TValue>(this ICache<TKey, TValue> cacheManagement, TKey key, TValue value, int duration = 60 * 1000)
{
cacheManagement.SetCache(new CacheEntry<TKey, TValue>(key)
{
Value = value,
Duration = TimeSpan.FromMilliseconds(duration)
});
}
}
}

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

@ -0,0 +1,106 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Threading.Tasks;
namespace TouchSocket.Core
{
/// <summary>
/// 缓存键值
/// </summary>
//[IntelligentCoder.AsyncMethodPoster(Flags = IntelligentCoder.MemberFlags.Public)]
public partial interface ICache<TKey, TValue>
{
/// <summary>
/// 添加缓存。当缓存存在时,不会添加成功。
/// </summary>
/// <param name="entity">缓存实体</param>
/// <exception cref="ArgumentNullException"></exception>
bool AddCache(ICacheEntry<TKey, TValue> entity);
/// <summary>
/// 清空所有缓存
/// </summary>
void ClearCache();
/// <summary>
/// 清空所有缓存
/// </summary>
/// <returns></returns>
Task ClearCacheAsync();
/// <summary>
/// 判断缓存是否存在,且在生命周期内。
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
bool ContainsCache(TKey key);
/// <summary>
/// 判断缓存是否存在,且在生命周期内。
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
Task<bool> ContainsCacheAsync(TKey key);
/// <summary>
/// 设置缓存,不管缓存存不存在,都会添加。
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
bool SetCache(ICacheEntry<TKey, TValue> entity);
/// <summary>
/// 设置缓存,不管缓存存不存在,都会添加。
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
Task<bool> SetCacheAsync(ICacheEntry<TKey, TValue> entity);
/// <summary>
/// 获取指定键的缓存。
/// </summary>
/// <param name="key">键</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
ICacheEntry<TKey, TValue> GetCache(TKey key);
/// <summary>
/// 获取指定键的缓存。
/// </summary>
/// <param name="key">键</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
Task<ICacheEntry<TKey, TValue>> GetCacheAsync(TKey key);
/// <summary>
/// 移除指定键的缓存。
/// </summary>
/// <param name="key">键</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
bool RemoveCache(TKey key);
/// <summary>
/// 移除指定键的缓存。
/// </summary>
/// <param name="key">键</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
Task<bool> RemoveCacheAsync(TKey key);
}
}

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

@ -0,0 +1,48 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
namespace TouchSocket.Core
{
/// <summary>
/// 缓存实体接口
/// </summary>
public interface ICacheEntry
{
/// <summary>
/// 有效区间。如果想长期有效,请使用<see cref="TimeSpan.Zero"/>
/// </summary>
public TimeSpan Duration { get; }
/// <summary>
/// 更新时间
/// </summary>
public DateTime UpdateTime { get; set; }
}
/// <summary>
/// 缓存实体接口
/// </summary>
public interface ICacheEntry<out TKey, TValue> : ICacheEntry
{
/// <summary>
/// 键
/// </summary>
public TKey Key { get; }
/// <summary>
/// 值
/// </summary>
public TValue Value { get; set; }
}
}

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

@ -0,0 +1,319 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace TouchSocket.Core
{
/// <summary>
/// 一个简单的内存缓存
/// </summary>
public class MemoryCache<TKey, TValue> : IEnumerable<ICacheEntry<TKey, TValue>>, ICache<TKey, TValue>
{
private readonly ConcurrentDictionary<TKey, ICacheEntry<TKey, TValue>> m_pairs = new ConcurrentDictionary<TKey, ICacheEntry<TKey, TValue>>();
private readonly Timer m_timer;
/// <summary>
/// 一个简单的内存缓存
/// </summary>
public MemoryCache()
{
m_timer = new Timer((o) =>
{
List<TKey> list = new List<TKey>();
foreach (var item in m_pairs)
{
if (DateTime.Now - item.Value.UpdateTime > item.Value.Duration)
{
list.Add(item.Key);
}
}
foreach (var item in list)
{
OnRemove(item, out _);
}
}, null, 0, 60 * 1000);
}
/// <summary>
/// 当每个元素超时被移除时触发。
/// </summary>
public Action<ICacheEntry<TKey, TValue>> Remove { get; set; }
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="entity"></param>
public bool AddCache(ICacheEntry<TKey, TValue> entity)
{
return m_pairs.TryAdd(entity.Key, entity);
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public Task<bool> AddCacheAsync(ICacheEntry<TKey, TValue> entity)
{
return EasyTask.Run(() =>
{
return AddCache(entity);
});
}
/// <summary>
/// 清空所有缓存
/// </summary>
public void ClearCache()
{
m_pairs.Clear();
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
public Task ClearCacheAsync()
{
return EasyTask.Run(() =>
{
ClearCache();
});
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool ContainsCache(TKey key)
{
if (m_pairs.TryGetValue(key, out ICacheEntry<TKey, TValue> cache))
{
if (cache.Duration == TimeSpan.Zero)
{
return true;
}
else
{
if (DateTime.Now - cache.UpdateTime > cache.Duration)
{
OnRemove(key, out _);
return false;
}
else
{
return true;
}
}
}
return false;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task<bool> ContainsCacheAsync(TKey key)
{
return EasyTask.Run(() =>
{
return ContainsCache(key);
});
}
/// <summary>
/// 获取缓存实体。
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public ICacheEntry<TKey, TValue> GetCache(TKey key)
{
ICacheEntry<TKey, TValue> cache;
if (m_pairs.TryGetValue(key, out cache))
{
if (cache.Duration == TimeSpan.Zero)
{
return cache;
}
else
{
if (DateTime.Now - cache.UpdateTime > cache.Duration)
{
OnRemove(key, out _);
return default;
}
else
{
return cache;
}
}
}
return default;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task<ICacheEntry<TKey, TValue>> GetCacheAsync(TKey key)
{
return EasyTask.Run(() =>
{
return GetCache(key);
});
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
public IEnumerator<ICacheEntry<TKey, TValue>> GetEnumerator()
{
return m_pairs.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 移除缓存
/// </summary>
/// <param name="key"></param>
/// <param name="entity"></param>
/// <returns></returns>
public bool RemoveCache(TKey key, out ICacheEntry<TKey, TValue> entity)
{
return OnRemove(key, out entity);
}
/// <summary>
/// 移除缓存
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool RemoveCache(TKey key)
{
return OnRemove(key, out _);
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task<bool> RemoveCacheAsync(TKey key)
{
return EasyTask.Run(() =>
{
return RemoveCache(key);
});
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public bool SetCache(ICacheEntry<TKey, TValue> entity)
{
m_pairs.AddOrUpdate(entity.Key, entity, (k, v) =>
{
return entity;
});
return true;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public Task<bool> SetCacheAsync(ICacheEntry<TKey, TValue> entity)
{
return EasyTask.Run(() =>
{
return SetCache(entity);
});
}
/// <summary>
/// 获取对应的值。
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="update"></param>
/// <returns></returns>
public bool TryGetValue(TKey key, out TValue value, bool update = false)
{
if (m_pairs.TryGetValue(key, out ICacheEntry<TKey, TValue> cache))
{
if (cache.Duration == TimeSpan.Zero)
{
if (update)
{
cache.UpdateTime = DateTime.Now;
}
value = cache.Value;
return true;
}
else
{
if (DateTime.Now - cache.UpdateTime > cache.Duration)
{
RemoveCache(key);
value = default;
return false;
}
else
{
if (update)
{
cache.UpdateTime = DateTime.Now;
}
value = (TValue)cache.Value;
return true;
}
}
}
value = default;
return false;
}
private bool OnRemove(TKey key, out ICacheEntry<TKey, TValue> cache)
{
if (m_pairs.TryRemove(key, out cache))
{
try
{
Remove?.Invoke(cache);
return true;
}
catch
{
}
}
return false;
}
}
}

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

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

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

@ -0,0 +1,125 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections.Concurrent;
namespace TouchSocket.Core
{
/// <summary>
/// 安全双向字典
/// </summary>
public class ConcurrentDoublyDictionary<TKey, TValue>
{
private readonly ConcurrentDictionary<TKey, TValue> m_keyToValue;
private readonly ConcurrentDictionary<TValue, TKey> m_valueToKey;
/// <summary>
/// 构造函数
/// </summary>
public ConcurrentDoublyDictionary()
{
m_keyToValue = new ConcurrentDictionary<TKey, TValue>();
m_valueToKey = new ConcurrentDictionary<TValue, TKey>();
}
/// <summary>
/// 由键指向值得集合
/// </summary>
public ConcurrentDictionary<TKey, TValue> KeyToValue => m_keyToValue;
/// <summary>
/// 由值指向键的集合
/// </summary>
public ConcurrentDictionary<TValue, TKey> ValueToKey => m_valueToKey;
/// <summary>
/// 尝试将指定的键和值添加到字典中。
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TryAdd(TKey key, TValue value)
{
if (m_keyToValue.TryAdd(key, value))
{
if (m_valueToKey.TryAdd(value, key))
{
return true;
}
else
{
m_keyToValue.TryRemove(key, out _);
return false;
}
}
return false;
}
/// <summary>
/// 由键尝试移除
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TryRemoveFromKey(TKey key, out TValue value)
{
if (m_keyToValue.TryRemove(key, out value))
{
if (m_valueToKey.TryRemove(value, out _))
{
return true;
}
}
return false;
}
/// <summary>
/// 由值尝试移除
/// </summary>
/// <param name="value"></param>
/// <param name="key"></param>
/// <returns></returns>
public bool TryRemoveFromValue(TValue value, out TKey key)
{
if (m_valueToKey.TryRemove(value, out key))
{
if (m_keyToValue.TryRemove(key, out _))
{
return true;
}
}
return false;
}
/// <summary>
/// 由键获取到值
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TryGetFromKey(TKey key, out TValue value)
{
return m_keyToValue.TryGetValue(key, out value);
}
/// <summary>
/// 由值获取到键
/// </summary>
/// <param name="value"></param>
/// <param name="key"></param>
/// <returns></returns>
public bool TryGetFromValue(TValue value, out TKey key)
{
return m_valueToKey.TryGetValue(value, out key);
}
}
}

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

@ -0,0 +1,680 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace TouchSocket.Core
{
/// <summary>
/// 线程安全的List,其基本操作和List一致。
/// </summary>
/// <typeparam name="T"></typeparam>
public class ConcurrentList<T> : IList<T>
{
private readonly List<T> m_list;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="collection"></param>
public ConcurrentList(IEnumerable<T> collection)
{
m_list = new List<T>(collection);
}
/// <summary>
/// 构造函数
/// </summary>
public ConcurrentList()
{
m_list = new List<T>();
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="capacity"></param>
public ConcurrentList(int capacity)
{
m_list = new List<T>(capacity);
}
/// <summary>
/// 元素数量
/// </summary>
public int Count
{
get
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.Count;
}
}
}
/// <summary>
/// 是否为只读
/// </summary>
public bool IsReadOnly => false;
/// <summary>
/// 获取索引元素
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T this[int index]
{
get
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list[index];
}
}
set
{
lock (((ICollection)m_list).SyncRoot)
{
m_list[index] = value;
}
}
}
/// <summary>
/// 添加元素
/// </summary>
/// <param name="item"></param>
public void Add(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Add(item);
}
}
/// <summary>
/// 清空所有元素
/// </summary>
public void Clear()
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Clear();
}
}
/// <summary>
/// 是否包含某个元素
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Contains(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.Contains(item);
}
}
/// <summary>
/// 复制到
/// </summary>
/// <param name="array"></param>
/// <param name="arrayIndex"></param>
public void CopyTo(T[] array, int arrayIndex)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.CopyTo(array, arrayIndex);
}
}
/// <summary>
/// 返回迭代器
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.ToList().GetEnumerator();
}
}
/// <summary>
/// 返回迭代器组合
/// </summary>
/// <returns></returns>
IEnumerator IEnumerable.GetEnumerator()
{
lock (((ICollection)m_list).SyncRoot)
{
return GetEnumerator();
}
}
/// <summary>
/// 索引
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int IndexOf(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.IndexOf(item);
}
}
/// <summary>
/// 插入
/// </summary>
/// <param name="index"></param>
/// <param name="item"></param>
public void Insert(int index, T item)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Insert(index, item);
}
}
/// <summary>
/// 移除元素
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Remove(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.Remove(item);
}
}
/// <summary>
/// 按索引移除
/// </summary>
/// <param name="index"></param>
public void RemoveAt(int index)
{
lock (((ICollection)m_list).SyncRoot)
{
if (index < m_list.Count)
{
m_list.RemoveAt(index);
}
}
}
/// <summary>
/// 获取或设置容量
/// </summary>
public int Capacity
{
get
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.Capacity;
}
}
set
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Capacity = value;
}
}
}
/// <summary>
/// <inheritdoc cref="List{T}.AddRange(IEnumerable{T})"/>
/// </summary>
/// <param name="collection"></param>
public void AddRange(IEnumerable<T> collection)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.AddRange(collection);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.BinarySearch(T)"/>
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int BinarySearch(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.BinarySearch(item);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.BinarySearch(T, IComparer{T})"/>
/// </summary>
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public int BinarySearch(T item, IComparer<T> comparer)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.BinarySearch(item, comparer);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.BinarySearch(int, int, T, IComparer{T})"/>
/// </summary>
/// <param name="index"></param>
/// <param name="count"></param>
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public int BinarySearch(int index, int count, T item, IComparer<T> comparer)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.BinarySearch(index, count, item, comparer);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.ConvertAll{TOutput}(Converter{T, TOutput})"/>
/// </summary>
/// <typeparam name="TOutput"></typeparam>
/// <param name="converter"></param>
/// <returns></returns>
public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.ConvertAll(converter);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Find(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public T Find(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.Find(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindAll(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public List<T> FindAll(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindAll(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindIndex(int, int, Predicate{T})"/>
/// </summary>
/// <param name="startIndex"></param>
/// <param name="count"></param>
/// <param name="match"></param>
/// <returns></returns>
public int FindIndex(int startIndex, int count, Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindIndex(startIndex, count, match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindIndex(int, Predicate{T})"/>
/// </summary>
/// <param name="startIndex"></param>
/// <param name="match"></param>
/// <returns></returns>
public int FindIndex(int startIndex, Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindIndex(startIndex, match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindIndex(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public int FindIndex(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindIndex(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindLast(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public T FindLast(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindLast(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindLastIndex(int, int, Predicate{T})"/>
/// </summary>
/// <param name="startIndex"></param>
/// <param name="count"></param>
/// <param name="match"></param>
/// <returns></returns>
public int FindLastIndex(int startIndex, int count, Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindLastIndex(startIndex, count, match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindLastIndex(int, Predicate{T})"/>
/// </summary>
/// <param name="startIndex"></param>
/// <param name="match"></param>
/// <returns></returns>
public int FindLastIndex(int startIndex, Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindLastIndex(startIndex, match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.FindLastIndex(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public int FindLastIndex(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.FindLastIndex(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.ForEach(Action{T})"/>
/// </summary>
/// <param name="action"></param>
public void ForEach(Action<T> action)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.ForEach(action);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.GetRange(int, int)"/>
/// </summary>
/// <param name="index"></param>
/// <param name="count"></param>
/// <returns></returns>
public List<T> GetRange(int index, int count)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.GetRange(index, count);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.IndexOf(T, int)"/>
/// </summary>
/// <param name="item"></param>
/// <param name="index"></param>
/// <returns></returns>
public int IndexOf(T item, int index)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.IndexOf(item, index);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.IndexOf(T, int, int)"/>
/// </summary>
/// <param name="item"></param>
/// <param name="index"></param>
/// <param name="count"></param>
/// <returns></returns>
public int IndexOf(T item, int index, int count)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.IndexOf(item, index, count);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.InsertRange(int, IEnumerable{T})"/>
/// </summary>
/// <param name="index"></param>
/// <param name="collection"></param>
public void InsertRange(int index, IEnumerable<T> collection)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.InsertRange(index, collection);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.LastIndexOf(T)"/>
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int LastIndexOf(T item)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.IndexOf(item);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.LastIndexOf(T, int)"/>
/// </summary>
/// <param name="item"></param>
/// <param name="index"></param>
/// <returns></returns>
public int LastIndexOf(T item, int index)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.LastIndexOf(item, index);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.LastIndexOf(T, int, int)"/>
/// </summary>
/// <param name="item"></param>
/// <param name="index"></param>
/// <param name="count"></param>
/// <returns></returns>
public int LastIndexOf(T item, int index, int count)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.LastIndexOf(item, index, count);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.RemoveAll(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
public void RemoveAll(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.RemoveAll(match);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.RemoveRange(int, int)"/>
/// </summary>
/// <param name="index"></param>
/// <param name="count"></param>
public void RemoveRange(int index, int count)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.RemoveRange(index, count);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Reverse()"/>
/// </summary>
public void Reverse()
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Reverse();
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Reverse(int, int)"/>
/// </summary>
/// <param name="index"></param>
/// <param name="count"></param>
public void Reverse(int index, int count)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Reverse(index, count);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Sort()"/>
/// </summary>
public void Sort()
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Sort();
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Sort(Comparison{T})"/>
/// </summary>
/// <param name="comparison"></param>
public void Sort(Comparison<T> comparison)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Sort(comparison);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Sort(IComparer{T})"/>
/// </summary>
/// <param name="comparer"></param>
public void Sort(IComparer<T> comparer)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Sort(comparer);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.Sort(int, int, IComparer{T})"/>
/// </summary>
/// <param name="index"></param>
/// <param name="count"></param>
/// <param name="comparer"></param>
public void Sort(int index, int count, IComparer<T> comparer)
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.Sort(index, count, comparer);
}
}
/// <summary>
/// <inheritdoc cref="List{T}.ToArray"/>
/// </summary>
/// <returns></returns>
public T[] ToArray()
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.ToArray();
}
}
/// <summary>
/// <inheritdoc cref="List{T}.TrimExcess"/>
/// </summary>
public void TrimExcess()
{
lock (((ICollection)m_list).SyncRoot)
{
m_list.TrimExcess();
}
}
/// <summary>
/// <inheritdoc cref="List{T}.TrueForAll(Predicate{T})"/>
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public bool TrueForAll(Predicate<T> match)
{
lock (((ICollection)m_list).SyncRoot)
{
return m_list.TrueForAll(match);
}
}
}
}

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

@ -0,0 +1,194 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections.Concurrent;
namespace TouchSocket.Core
{
/// <summary>
/// 三元组合
/// </summary>
/// <typeparam name="TKey1"></typeparam>
/// <typeparam name="TKey2"></typeparam>
/// <typeparam name="TValue"></typeparam>
public readonly struct Ternary<TKey1, TKey2, TValue>
{
/// <summary>
/// 三元组合
/// </summary>
/// <param name="key1"></param>
/// <param name="key2"></param>
/// <param name="value"></param>
public Ternary(TKey1 key1, TKey2 key2, TValue value)
{
Key1 = key1;
Key2 = key2;
Value = value;
}
/// <summary>
/// 首键
/// </summary>
public readonly TKey1 Key1 { get; }
/// <summary>
/// 次键
/// </summary>
public readonly TKey2 Key2 { get; }
/// <summary>
/// 值
/// </summary>
public readonly TValue Value { get; }
}
/// <summary>
/// 线程安全的双键字典
/// </summary>
/// <typeparam name="TKey1"></typeparam>
/// <typeparam name="TKey2"></typeparam>
/// <typeparam name="TValue"></typeparam>
public class ConcurrentMultiDictionary<TKey1, TKey2, TValue>
{
private readonly ConcurrentDictionary<TKey1, Ternary<TKey1, TKey2, TValue>> m_key1ToValue =
new ConcurrentDictionary<TKey1, Ternary<TKey1, TKey2, TValue>>();
private readonly ConcurrentDictionary<TKey2, Ternary<TKey1, TKey2, TValue>> m_key2ToValue =
new ConcurrentDictionary<TKey2, Ternary<TKey1, TKey2, TValue>>();
/// <summary>
/// 元素数量。
/// </summary>
public int Count { get => m_key1ToValue.Count; }
/// <summary>
/// 清空所有元素。
/// </summary>
public void Clear()
{
m_key1ToValue.Clear();
m_key2ToValue.Clear();
}
/// <summary>
/// 是否包含指定键。
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool ContainsKey(TKey2 key)
{
return m_key2ToValue.ContainsKey(key);
}
/// <summary>
/// 是否包含指定键。
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool ContainsKey(TKey1 key)
{
return m_key1ToValue.ContainsKey(key);
}
/// <summary>
/// 尝试添加。
/// </summary>
/// <param name="key1"></param>
/// <param name="key2"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TryAdd(TKey1 key1, TKey2 key2, TValue value)
{
var ternary = new Ternary<TKey1, TKey2, TValue>(key1, key2, value);
if (m_key1ToValue.TryAdd(key1, ternary) && m_key2ToValue.TryAdd(key2, ternary))
{
return true;
}
else
{
m_key1ToValue.TryRemove(key1, out _);
m_key2ToValue.TryRemove(key2, out _);
return false;
}
}
/// <summary>
/// 由首键删除
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TryRemove(TKey1 key, out TValue value)
{
if (m_key1ToValue.TryRemove(key, out var ternary))
{
m_key2ToValue.TryRemove(ternary.Key2, out _);
value = ternary.Value;
return true;
}
value = default;
return false;
}
/// <summary>
/// 由次键删除
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TryRemove(TKey2 key, out TValue value)
{
if (m_key2ToValue.TryRemove(key, out var ternary))
{
m_key1ToValue.TryRemove(ternary.Key1, out _);
value = ternary.Value;
return true;
}
value = default;
return false;
}
/// <summary>
/// 由首键获取值
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TryGetValue(TKey1 key, out TValue value)
{
if (m_key1ToValue.TryGetValue(key, out var ternary))
{
value = ternary.Value;
return true;
}
value = default;
return false;
}
/// <summary>
/// 由次键获取值
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TryGetValue(TKey2 key, out TValue value)
{
if (m_key2ToValue.TryGetValue(key, out var ternary))
{
value = ternary.Value;
return true;
}
value = default;
return false;
}
}
}

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

@ -0,0 +1,78 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections.Concurrent;
using System.Threading;
namespace TouchSocket.Core
{
/// <summary>
/// 智能安全队列
/// </summary>
/// <typeparam name="T"></typeparam>
public class IntelligentConcurrentQueue<T> : ConcurrentQueue<T>
{
private int m_count;
private readonly int m_maxCount;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="maxCount"></param>
public IntelligentConcurrentQueue(int maxCount)
{
m_maxCount = maxCount;
}
/// <summary>
/// 允许的最大长度
/// </summary>
public int MaxCount => m_maxCount;
/// <summary>
/// 长度
/// </summary>
public new int Count => m_count;
/// <summary>
/// 入队
/// </summary>
/// <param name="item"></param>
public new void Enqueue(T item)
{
SpinWait.SpinUntil(Check);
Interlocked.Increment(ref m_count);
base.Enqueue(item);
}
/// <summary>
/// 出队
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public new bool TryDequeue(out T result)
{
if (base.TryDequeue(out result))
{
Interlocked.Decrement(ref m_count);
return true;
}
return false;
}
private bool Check()
{
return m_count < m_maxCount;
}
}
}

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

@ -0,0 +1,233 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace TouchSocket.Core
{
/// <summary>
/// 队列数据
/// </summary>
public interface IQueueData
{
/// <summary>
/// 数据长度
/// </summary>
int Size { get; }
}
/// <summary>
/// 传输字节
/// </summary>
public class QueueDataBytes : IQueueData
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="length"></param>
public QueueDataBytes(byte[] buffer, int offset, int length)
{
Offset = offset;
Length = length;
Buffer = buffer;
Size = length;
}
/// <summary>
/// 从指定内存创建一个新对象,且内存也为新创建。
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="length"></param>
/// <returns></returns>
public static QueueDataBytes CreateNew(byte[] buffer, int offset, int length)
{
byte[] buf = new byte[length];
Array.Copy(buffer, offset, buf, 0, length);
return new QueueDataBytes(buf);
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="buffer"></param>
public QueueDataBytes(byte[] buffer) : this(buffer, 0, buffer.Length)
{
}
/// <summary>
/// 数据内存
/// </summary>
public byte[] Buffer { get; }
/// <summary>
/// 长度
/// </summary>
public int Length { get; }
/// <summary>
/// 偏移
/// </summary>
public int Offset { get; }
/// <summary>
/// 尺寸
/// </summary>
public int Size { get; }
}
/// <summary>
/// 智能数据安全队列
/// </summary>
/// <typeparam name="T"></typeparam>
public class IntelligentDataQueue<T> : ConcurrentQueue<T> where T : IQueueData
{
private long m_actualSize;
private bool m_free;
private long m_maxSize;
private Action<bool> m_onQueueChanged;
private bool m_overflowWait;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="maxSize"></param>
public IntelligentDataQueue(long maxSize)
{
m_free = true;
m_overflowWait = true;
MaxSize = maxSize;
}
/// <summary>
/// 构造函数
/// </summary>
public IntelligentDataQueue() : this(1024 * 1024 * 10)
{
}
/// <summary>
/// 实际尺寸
/// </summary>
public long ActualSize => m_actualSize;
/// <summary>
/// 是否有空位允许入队
/// </summary>
public bool Free => m_free;
/// <summary>
/// 允许的最大长度
/// </summary>
public long MaxSize
{
get => m_maxSize;
set
{
if (value < 1)
{
value = 1;
}
m_maxSize = value;
}
}
/// <summary>
/// 在队列修改时
/// </summary>
public Action<bool> OnQueueChanged
{
get => m_onQueueChanged;
set => m_onQueueChanged = value;
}
/// <summary>
/// 溢出等待
/// </summary>
public bool OverflowWait
{
get => m_overflowWait;
set => m_overflowWait = value;
}
/// <summary>
/// 超时时间。默认1000*30ms;
/// </summary>
public int Timeout { get; set; } = 1000 * 30;
/// <summary>
/// 清空队列
/// </summary>
public void Clear(Action<T> onClear)
{
while (base.TryDequeue(out T t))
{
onClear?.Invoke(t);
}
}
/// <summary>
/// 入队
/// </summary>
/// <param name="item"></param>
public new void Enqueue(T item)
{
lock (this)
{
bool free = m_actualSize < m_maxSize;
if (m_free != free)
{
m_free = free;
m_onQueueChanged?.Invoke(m_free);
}
if (m_overflowWait)
{
SpinWait.SpinUntil(Check, Timeout);
}
Interlocked.Add(ref m_actualSize, item.Size);
base.Enqueue(item);
}
}
/// <summary>
/// 出队
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public new bool TryDequeue(out T result)
{
if (base.TryDequeue(out result))
{
Interlocked.Add(ref m_actualSize, -result.Size);
bool free = m_actualSize < m_maxSize;
if (m_free != free)
{
m_free = free;
m_onQueueChanged?.Invoke(m_free);
}
return true;
}
return false;
}
private bool Check()
{
return m_actualSize < m_maxSize;
}
}
}

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

@ -0,0 +1,150 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace TouchSocket.Core
{
/// <summary>
/// 触发器队列
/// </summary>
/// <typeparam name="T"></typeparam>
public class TriggerQueue<T> : DisposableObject
{
private readonly ReaderWriterLockSlim m_lockSlim;
private readonly ConcurrentQueue<T> m_queue;
private readonly Timer m_timer;
private volatile bool m_sending;
/// <summary>
/// 触发器队列
/// </summary>
public TriggerQueue()
{
m_lockSlim = new ReaderWriterLockSlim();
m_queue = new ConcurrentQueue<T>();
m_timer = new Timer(TimerRun, null, 10, 10);
}
/// <summary>
/// 析构函数
/// </summary>
~TriggerQueue()
{
Dispose(false);
}
/// <summary>
/// 出队列处理。
/// </summary>
public Action<T> OnDequeue { get; set; }
/// <summary>
/// 发生错误
/// </summary>
public Action<Exception> OnError { get; set; }
/// <summary>
/// 是否处于发送状态
/// </summary>
public bool Sending
{
get
{
using (new ReadLock(m_lockSlim))
{
return m_sending;
}
}
private set
{
using (new WriteLock(m_lockSlim))
{
m_sending = value;
}
}
}
/// <summary>
/// 发送
/// </summary>
public void Enqueue(T data)
{
m_queue.Enqueue(data);
if (SwitchToRun())
{
ThreadPool.QueueUserWorkItem(BeginTrigger);
}
}
/// <summary>
/// 释放
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
m_timer.SafeDispose();
m_queue.Clear();
base.Dispose(disposing);
}
private void BeginTrigger(object o)
{
while (true)
{
try
{
if (m_queue.TryDequeue(out T data))
{
OnDequeue?.Invoke(data);
}
else
{
break;
}
}
catch (Exception ex)
{
OnError?.Invoke(ex);
}
}
Sending = false;
}
private bool SwitchToRun()
{
using (new ReadLock(m_lockSlim))
{
if (m_sending)
{
return false;
}
else
{
m_sending = true;
return true;
}
}
}
private void TimerRun(object state)
{
if (SwitchToRun())
{
BeginTrigger(null);
}
}
}
}

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

@ -0,0 +1,32 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Collections.Specialized;
using System.Diagnostics;
namespace TouchSocket.Core
{
/// <summary>
/// IgnoreCaseNameValueCollection
/// </summary>
[DebuggerTypeProxy(typeof(NameValueCollectionDebugView))]
public class IgnoreCaseNameValueCollection : NameValueCollection
{
/// <summary>
/// IgnoreCaseNameValueCollection
/// </summary>
public IgnoreCaseNameValueCollection() : base(StringComparer.OrdinalIgnoreCase)
{
}
}
}

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

@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
namespace TouchSocket.Core
{
/// <summary>
/// NameValueCollectionDebugView
/// </summary>
public class NameValueCollectionDebugView
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly NameValueCollection m_nameValue;
/// <summary>
/// NameValueCollectionDebugView
/// </summary>
/// <param name="nameValue"></param>
public NameValueCollectionDebugView(NameValueCollection nameValue)
{
m_nameValue = nameValue;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
private Dictionary<string, string> KV
{
get
{
var dic = new Dictionary<string, string>();
foreach (var item in m_nameValue.AllKeys)
{
dic.TryAdd(item, m_nameValue[item]);
}
return dic;
}
}
}
}

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

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

@ -0,0 +1,137 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
namespace TouchSocket.Core
{
/// <summary>
/// 运行配置类
/// </summary>
public abstract class AppConfigBase
{
private readonly string m_fullPath;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="fullPath"></param>
public AppConfigBase(string fullPath)
{
if (string.IsNullOrEmpty(fullPath))
{
throw new ArgumentException($"“{nameof(fullPath)}”不能为 null 或空。", nameof(fullPath));
}
m_fullPath = fullPath;
}
/// <summary>
/// 保存配置
/// </summary>
/// <param name="overwrite"></param>
/// <param name="msg"></param>
/// <returns></returns>
public bool Save(bool overwrite, out string msg)
{
if (overwrite == false && File.Exists(m_fullPath))
{
msg = null;
return true;
}
try
{
File.WriteAllText(m_fullPath, this.ToJson());
msg = null;
return true;
}
catch (Exception ex)
{
msg = ex.Message;
return false;
}
}
/// <summary>
/// 加载配置
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public bool Load(out string msg)
{
try
{
if (!File.Exists(m_fullPath))
{
Save(false, out _);
}
var obj = File.ReadAllText(m_fullPath).FromJson(GetType());
var ps = GetType().GetProperties();
foreach (var item in ps)
{
item.SetValue(this, item.GetValue(obj));
}
msg = null;
return true;
}
catch (Exception ex)
{
msg = ex.Message;
return false;
}
}
/// <summary>
/// 获取默认配置。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetDefault<T>() where T : AppConfigBase, new()
{
Type type = typeof(T);
if (list.TryGetValue(type, out object value))
{
return (T)value;
}
T _default = ((T)Activator.CreateInstance(typeof(T)));
_default.Load(out _);
list.Add(type, _default);
return _default;
}
private static readonly Dictionary<Type, object> list = new Dictionary<Type, object>();
/// <summary>
/// 获取默认配置,每次调用该方法时,都会重新加载配置。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetNewDefault<T>() where T : AppConfigBase, new()
{
T _default = ((T)Activator.CreateInstance(typeof(T)));
_default.Load(out _);
if (list.ContainsKey(_default.GetType()))
{
list[_default.GetType()] = _default;
}
else
{
list.Add(_default.GetType(), _default);
}
return _default;
}
}
}

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

@ -0,0 +1,48 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
namespace TouchSocket.Core
{
/// <summary>
/// DateExtensions
/// </summary>
public static class DateExtensions
{
private static readonly DateTime m_utc_time = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
/// <summary>
/// 将时间转为毫秒级别的短整形
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint ConvertTime(this in DateTime time)
{
return (uint)(Convert.ToInt64(time.Subtract(m_utc_time).TotalMilliseconds) & 0xffffffff);
}
private static readonly DateTimeOffset m_utc1970 = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
/// <summary>
/// 将时间转为毫秒级别的短整形
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint ConvertTime(this in DateTimeOffset time)
{
return (uint)(Convert.ToInt64(time.Subtract(m_utc1970).TotalMilliseconds) & 0xffffffff);
}
}
}

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

@ -0,0 +1,51 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
namespace TouchSocket.Core
{
/// <summary>
/// 具有释放的对象。
/// 并未实现析构函数相关。
/// </summary>
public class DisposableObject : IDisposable
{
/// <summary>
/// 判断是否已释放。
/// </summary>
private volatile bool m_disposedValue;
/// <summary>
/// 标识该对象是否已被释放
/// </summary>
public bool DisposedValue { get => m_disposedValue; }
/// <summary>
/// 调用释放,切换释放状态。
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
m_disposedValue = true;
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}

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

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

@ -0,0 +1,31 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace TouchSocket.Core
{
/// <summary>
/// 大小端类型
/// </summary>
public enum EndianType
{
/// <summary>
/// 小端模式
/// </summary>
Little,
/// <summary>
/// 大端模式
/// </summary>
Big
}
}

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

@ -0,0 +1,56 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace TouchSocket.Core
{
/// <summary>
/// 结果类型
/// </summary>
public enum ResultCode
{
/// <summary>
/// 默认
/// </summary>
Default,
/// <summary>
/// 错误
/// </summary>
Error,
/// <summary>
/// 异常
/// </summary>
Exception,
/// <summary>
/// 成功
/// </summary>
Success,
/// <summary>
/// 失败
/// </summary>
Fail,
/// <summary>
/// 操作超时
/// </summary>
Overtime,
/// <summary>
/// 操作取消
/// </summary>
Canceled
}
}

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

@ -0,0 +1,112 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace TouchSocket.Core
{
/// <summary>
/// 流量控制
/// </summary>
public class FlowGate
{
private readonly Stopwatch m_stopwatch;
private long m_timeTick;
private long m_transferLength;
/// <summary>
/// 构造函数
/// </summary>
public FlowGate()
{
m_stopwatch = new Stopwatch();
}
/// <summary>
/// 最大值
/// </summary>
public long Maximum { get; set; } = long.MaxValue;
/// <summary>
/// 最长休眠周期。默认为5*1000ms.
/// <para>当设置为5000时,假如设置的<see cref="Maximum"/>=10,而一次递增了100,则理应会休眠10s,但是会休眠5s。反之,如果设置1,则每秒周期都会清空。</para>
/// </summary>
public int MaximumPeriod { get; set; } = 5000;
/// <summary>
/// 检测等待
/// </summary>
public void AddCheckWait(int increment)
{
if (GetNowTick() - m_timeTick > 0)
{
//时间过了一秒
m_timeTick = FlowGate.GetNowTick();
m_transferLength = 0;
m_stopwatch.Restart();
}
else
{
//在这一秒中
if (Interlocked.Add(ref m_transferLength, increment) > Maximum)
{
//上传饱和
m_stopwatch.Stop();
int sleepTime = 1000 - (int)m_stopwatch.ElapsedMilliseconds <= 0 ? 0 : GetBaseNum() - (int)m_stopwatch.ElapsedMilliseconds;
Thread.Sleep(sleepTime);
}
}
}
/// <summary>
/// 检测等待
/// </summary>
/// <param name="increment"></param>
/// <returns></returns>
public async Task AddCheckWaitAsync(int increment)
{
if (GetNowTick() - m_timeTick > 0)
{
//时间过了一秒
m_timeTick = FlowGate.GetNowTick();
m_transferLength = 0;
m_stopwatch.Restart();
}
else
{
//在这一秒中
if (Interlocked.Add(ref m_transferLength, increment) > Maximum)
{
//上传饱和
m_stopwatch.Stop();
int sleepTime = 1000 - (int)m_stopwatch.ElapsedMilliseconds <= 0 ? 0 : GetBaseNum() - (int)m_stopwatch.ElapsedMilliseconds;
await Task.Delay(sleepTime);
}
}
}
private static long GetNowTick()
{
return DateTime.Now.Ticks / 10000000;
}
private int GetBaseNum()
{
return Math.Min((int)((double)m_transferLength / Maximum * 1000), MaximumPeriod);
}
}
}

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

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TouchSocket.Core
{
/// <summary>
/// 全局环境设置
/// </summary>
public static class GlobalEnvironment
{
/// <summary>
/// 优化平台
/// </summary>
public static OptimizedPlatforms OptimizedPlatforms { get; set; } = OptimizedPlatforms.None;
}
}

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

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace TouchSocket.Core
{
/// <summary>
/// 返回通知接口
/// </summary>
public interface IResult
{
/// <summary>
/// 是否成功
/// </summary>
ResultCode ResultCode { get; }
/// <summary>
/// 消息
/// </summary>
string Message { get; }
}
}

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

@ -0,0 +1,35 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace TouchSocket.Core
{
/// <summary>
/// 规范写端口,提供更多扩展
/// </summary>
public interface IWrite
{
/// <summary>
/// 写入
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="length"></param>
void Write(byte[] buffer, int offset, int length);
/// <summary>
/// 写入
/// </summary>
/// <param name="buffer"></param>
void Write(byte[] buffer);
}
}

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

@ -0,0 +1,69 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Threading;
namespace TouchSocket.Core
{
/// <summary>
/// 读取锁
/// </summary>
public struct ReadLock : IDisposable
{
private readonly ReaderWriterLockSlim m_locks;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="locks"></param>
public ReadLock(ReaderWriterLockSlim locks)
{
m_locks = locks;
m_locks.EnterReadLock();
}
/// <summary>
/// 释放
/// </summary>
public void Dispose()
{
m_locks.ExitReadLock();
}
}
/// <summary>
/// 写入锁
/// </summary>
public struct WriteLock : IDisposable
{
private readonly ReaderWriterLockSlim m_locks;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="locks"></param>
public WriteLock(ReaderWriterLockSlim locks)
{
m_locks = locks;
m_locks.EnterWriteLock();
}
/// <summary>
/// 释放
/// </summary>
public void Dispose()
{
m_locks.ExitWriteLock();
}
}
}

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

@ -0,0 +1,70 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections.Specialized;
namespace TouchSocket.Core
{
/// <summary>
/// 元数据键值对。
/// </summary>
[FastConverter(typeof(MetadataFastBinaryConverter))]
public class Metadata : NameValueCollection, IPackage
{
/// <summary>
/// 元数据键值对。
/// </summary>
public Metadata()
{
}
/// <summary>
/// 添加。如果键存在,将被覆盖。
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public new Metadata Add(string name, string value)
{
base.Add(name, value);
return this;
}
/// <summary>
/// 打包
/// </summary>
/// <param name="byteBlock"></param>
public void Package(ByteBlock byteBlock)
{
byteBlock.Write(Count);
foreach (var item in AllKeys)
{
byteBlock.Write(item);
byteBlock.Write(this[item]);
}
}
/// <summary>
/// 解包
/// </summary>
/// <param name="byteBlock"></param>
public void Unpackage(ByteBlock byteBlock)
{
int count = byteBlock.ReadInt32();
for (int i = 0; i < count; i++)
{
string key = byteBlock.ReadString();
string value = byteBlock.ReadString();
Add(key, value);
}
}
}
}

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

@ -0,0 +1,43 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace TouchSocket.Core
{
/// <summary>
/// MetadataFastBinaryConverter
/// </summary>
internal sealed class MetadataFastBinaryConverter : FastBinaryConverter<Metadata>
{
protected override Metadata Read(byte[] buffer, int offset, int len)
{
ByteBlock byteBlock = new ByteBlock(buffer);
byteBlock.Pos = offset;
Metadata metadata = new Metadata();
while (byteBlock.Pos < offset + len)
{
metadata.Add(byteBlock.ReadString(), byteBlock.ReadString());
}
return metadata;
}
protected override int Write(ByteBlock byteBlock, Metadata obj)
{
int pos = byteBlock.Pos;
foreach (var item in obj.AllKeys)
{
byteBlock.Write(item);
byteBlock.Write(obj[item]);
}
return byteBlock.Pos - pos;
}
}
}

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

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TouchSocket.Core
{
/// <summary>
/// 优化平台
/// </summary>
[Flags]
public enum OptimizedPlatforms
{
/// <summary>
/// 无特殊优化
/// </summary>
None=0,
/// <summary>
/// 针对Unity2020及以下优化。
/// 一般来说,当在unity2020及以下版本,中执行il2cpp编译时,需要设置该值。
/// </summary>
Unity = 1
}
}

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

@ -0,0 +1,268 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using TouchSocket.Resources;
namespace TouchSocket.Core
{
/// <summary>
/// 结果返回
/// </summary>
public struct Result : IResult
{
/// <summary>
/// 成功
/// </summary>
public static readonly Result Success = new Result(ResultCode.Success, "Success");
/// <summary>
/// 初始状态
/// </summary>
public static readonly Result Default = new Result(ResultCode.Default, "Default");
/// <summary>
/// 未知失败
/// </summary>
public static readonly Result UnknownFail = new Result(ResultCode.Fail, TouchSocketStatus.UnknownError.GetDescription());
/// <summary>
/// 超时
/// </summary>
public static readonly Result Overtime = new Result(ResultCode.Overtime, TouchSocketStatus.Overtime.GetDescription());
/// <summary>
/// 取消
/// </summary>
public static readonly Result Canceled = new Result(ResultCode.Canceled, TouchSocketStatus.Canceled.GetDescription());
/// <summary>
/// 构造函数
/// </summary>
/// <param name="resultCode"></param>
/// <param name="message"></param>
public Result(ResultCode resultCode, string message)
{
ResultCode = resultCode;
Message = message;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="result"></param>
public Result(IResult result)
{
ResultCode = result.ResultCode;
Message = result.Message;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="exception"></param>
public Result(Exception exception)
{
ResultCode = ResultCode.Exception;
Message = exception.Message;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="resultCode"></param>
public Result(ResultCode resultCode)
{
ResultCode = resultCode;
Message = resultCode.GetDescription();
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public ResultCode ResultCode { get; private set; }
/// <summary>
/// <inheritdoc/>
/// </summary>
public string Message { get; private set; }
/// <summary>
/// 创建来自<see cref="ResultCode.Canceled"/>的<see cref="Result"/>
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static Result FromCanceled(string msg)
{
return new Result(ResultCode.Canceled, msg);
}
/// <summary>
/// 创建来自<see cref="ResultCode.Error"/>的<see cref="Result"/>
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static Result FromError(string msg)
{
return new Result(ResultCode.Error, msg);
}
/// <summary>
/// 创建来自<see cref="ResultCode.Exception"/>的<see cref="Result"/>
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static Result FromException(string msg)
{
return new Result(ResultCode.Exception, msg);
}
/// <summary>
/// 创建来自<see cref="ResultCode.Overtime"/>的<see cref="Result"/>
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static Result FromFail(string msg)
{
return new Result(ResultCode.Fail, msg);
}
/// <summary>
/// 创建来自<see cref="ResultCode.Overtime"/>的<see cref="Result"/>
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static Result FromOvertime(string msg)
{
return new Result(ResultCode.Overtime, msg);
}
/// <summary>
/// 创建来自<see cref="ResultCode.Success"/>的<see cref="Result"/>
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public static Result FromSuccess(string msg)
{
return new Result(ResultCode.Success, msg);
}
/// <summary>
/// ToString
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"类型:{ResultCode},信息:{Message}";
}
}
/// <summary>
/// 结果返回
/// </summary>
public class ResultBase : IResult
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="resultCode"></param>
/// <param name="message"></param>
public ResultBase(ResultCode resultCode, string message)
{
ResultCode = resultCode;
Message = message;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="resultCode"></param>
public ResultBase(ResultCode resultCode)
{
ResultCode = resultCode;
Message = resultCode.GetDescription();
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="result"></param>
public ResultBase(Result result)
{
ResultCode = result.ResultCode;
Message = result.Message;
}
/// <summary>
/// 构造函数
/// </summary>
public ResultBase()
{
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public ResultCode ResultCode { get; protected set; }
/// <summary>
/// <inheritdoc/>
/// </summary>
public string Message { get; protected set; }
/// <summary>
/// ToString
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"类型:{ResultCode},信息:{Message}";
}
}
/// <summary>
/// ResultExtensions
/// </summary>
public static class ResultExtensions
{
/// <summary>
/// 是否成功。
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public static bool IsSuccess(this IResult result)
{
return result.ResultCode == ResultCode.Success;
}
/// <summary>
/// 是否没有成功。
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public static bool NotSuccess(this IResult result)
{
return result.ResultCode != ResultCode.Success;
}
/// <summary>
/// 转换为<see cref="Result"/>
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public static Result ToResult(this IResult result)
{
return new Result(result);
}
}
}

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

@ -0,0 +1,129 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
namespace TouchSocket.Core
{
/// <summary>
/// 雪花ID生成器(该代码来自网络)
/// </summary>
public class SnowflakeIDGenerator
{
private const int SequenceBits = 10;
/// <summary>
/// 一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
/// </summary>
private const long SequenceMask = -1L ^ -1L << SequenceBits;
private const int TimestampLeftShift = SequenceBits + WorkerIdBits;
private const int WorkerIdBits = 4;
//计数器字节数,10个字节用来保存计数码
private const int WorkerIdShift = SequenceBits;
private static long Sequence = 0L;
//机器ID
private static long WorkerId;
private readonly long Twepoch = 687888001020L;
private long m_lastTimestamp = -1L;
static SnowflakeIDGenerator()
{
}
//一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
/// <summary>
/// 机器码
/// </summary>
/// <param name="workerId"></param>
public SnowflakeIDGenerator(long workerId)
{
if (workerId > MaxWorkerId || workerId < 0)
throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0 ", MaxWorkerId));
SnowflakeIDGenerator.WorkerId = workerId;
Twepoch = DateTime.Now.Ticks - 10000;
}
/// <summary>
/// 最大机器ID
/// </summary>
public static long MaxWorkerId { get; private set; } = -1L ^ (-1L << WorkerIdBits); //最大机器ID
//唯一时间,这是一个避免重复的随机量,自行设定不要大于当前时间戳
//机器码字节数。4个字节用来保存机器码(定义为Long类型会出现,最大偏移64位,所以左移64位没有意义)
//机器码数据左移位数,就是后面计数器占用的位数
//时间戳左移动位数就是机器码和计数器总字节数
/// <summary>
/// 获取ID
/// </summary>
/// <returns></returns>
public long NextID()
{
lock (this)
{
long timestamp = timeGen();
if (m_lastTimestamp == timestamp)
{ //同一微妙中生成ID
Sequence = (Sequence + 1) & SequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
if (Sequence == 0)
{
//一微妙内产生的ID计数已达上限,等待下一微妙
timestamp = tillNextMillis(m_lastTimestamp);
}
}
else
{ //不同微秒生成ID
Sequence = 0; //计数清0
}
if (timestamp < m_lastTimestamp)
{ //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过
throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds",
m_lastTimestamp - timestamp));
}
m_lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
long nextId = (timestamp - Twepoch << TimestampLeftShift) | WorkerId << WorkerIdShift | Sequence;
return nextId;
}
}
/// <summary>
/// 获取下一微秒时间戳
/// </summary>
/// <param name="lastTimestamp"></param>
/// <returns></returns>
private long tillNextMillis(long lastTimestamp)
{
long timestamp = timeGen();
while (timestamp <= lastTimestamp)
{
timestamp = timeGen();
}
return timestamp;
}
/// <summary>
/// 生成当前时间戳
/// </summary>
/// <returns></returns>
private long timeGen()
{
return Environment.TickCount;
}
}
}

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

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save