[Add] FishNet

This commit is contained in:
2026-03-30 20:11:57 +07:00
parent ee793a3361
commit c22c08753a
1797 changed files with 197950 additions and 1 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 92540a55e648a2448bb430e825f01bc4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,457 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 9
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GIWorkflowMode: 1
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 2
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
accuratePlacement: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &279669268
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 279669271}
- component: {fileID: 279669270}
- component: {fileID: 279669269}
m_Layer: 0
m_Name: EventSystem
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &279669269
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 279669268}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
m_Name:
m_EditorClassIdentifier:
m_SendPointerHoverToParent: 1
m_HorizontalAxis: Horizontal
m_VerticalAxis: Vertical
m_SubmitButton: Submit
m_CancelButton: Cancel
m_InputActionsPerSecond: 10
m_RepeatDelay: 0.5
m_ForceModuleActive: 0
--- !u!114 &279669270
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 279669268}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
m_Name:
m_EditorClassIdentifier:
m_FirstSelected: {fileID: 0}
m_sendNavigationEvents: 1
m_DragThreshold: 10
--- !u!4 &279669271
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 279669268}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &842004460
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 842004462}
- component: {fileID: 842004461}
m_Layer: 0
m_Name: GameObject
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &842004461
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 842004460}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3}
m_Name:
m_EditorClassIdentifier:
<IsNested>k__BackingField: 0
WasActiveDuringEdit: 1
WasActiveDuringEdit_Set1: 1
<ComponentIndex>k__BackingField: 0
<PredictedSpawn>k__BackingField: {fileID: 0}
<PredictedOwner>k__BackingField: {fileID: 0}
NetworkBehaviours: []
InitializedParentNetworkBehaviour: {fileID: 0}
InitializedNestedNetworkObjects: []
RuntimeParentNetworkBehaviour: {fileID: 0}
RuntimeChildNetworkBehaviours: []
_isNetworked: 1
_isSpawnable: 1
_isGlobal: 0
_initializeOrder: 0
_preventDespawnOnDisconnect: 0
_defaultDespawnType: 0
_initializedTimestamp: 0
NetworkObserver: {fileID: 0}
_enablePrediction: 0
_predictionType: 0
_graphicalObject: {fileID: 0}
_detachGraphicalObject: 0
_enableStateForwarding: 1
_networkTransform: {fileID: 0}
_ownerInterpolation: 1
_ownerSmoothedProperties: 255
_adaptiveInterpolation: 3
_spectatorSmoothedProperties: 255
_spectatorInterpolation: 2
_enableTeleport: 0
_teleportThreshold: 1
<PrefabId>k__BackingField: 65535
<SpawnableCollectionId>k__BackingField: 0
<AssetPathHash>k__BackingField: 0
SceneId: 954982270
SerializedTransformProperties:
Position: {x: 0, y: 0, z: 0}
Rotation: {x: 0, y: 0, z: 0, w: 0}
Scale: {x: 0, y: 0, z: 0}
IsValid: 0
--- !u!4 &842004462
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 842004460}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 100.55502, y: 9.688629, z: 1.996249}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &1689326519
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_Pivot.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_Pivot.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_RootOrder
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058994, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: _autoStartType
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4393252310969058995, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
propertyPath: m_Name
value: NetworkHudCanvas
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3}
--- !u!114 &1759771918
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7443408886491481971}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 226e4eaf2fa685f48bdc3dfaa87c1453, type: 3}
m_Name:
m_EditorClassIdentifier:
_allowHostAuthentication: 0
_password: HelloWorld
--- !u!4 &7443408886491481969
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7443408886491481971}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &7443408886491481970
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7443408886491481971}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d2c95dfde7d73b54dbbdc23155d35d36, type: 3}
m_Name:
m_EditorClassIdentifier:
_refreshDefaultPrefabs: 0
_runInBackground: 1
_dontDestroyOnLoad: 1
_objectPool: {fileID: 0}
_persistence: 0
_logging: {fileID: 0}
_spawnablePrefabs: {fileID: 11400000, guid: ef18464092139404db8e515b0bf59331, type: 2}
--- !u!1 &7443408886491481971
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7443408886491481969}
- component: {fileID: 7443408886491481970}
- component: {fileID: 1759771918}
- component: {fileID: 7443408886491481972}
m_Layer: 0
m_Name: NetworkManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &7443408886491481972
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7443408886491481971}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 91f4cf5273666764789e6f8bada05e3e, type: 3}
m_Name:
m_EditorClassIdentifier:
@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 0bc02b628363de5499d5e7c00bd63b1b
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
assetPath: Assets/FishNet/Demos/Authenticator/Scenes/Authenticator.unity
uploadId: 866910
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0cb111b6bede3a1478c9b179a609d822
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,19 @@
using FishNet.Broadcast;
namespace FishNet.Example.Authenticating
{
public struct HostPasswordBroadcast : IBroadcast
{
public string Password;
}
public struct PasswordBroadcast : IBroadcast
{
public string Password;
}
public struct ResponseBroadcast : IBroadcast
{
public bool Passed;
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d26bb0c99070e9b49bc8632dc0b68214
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
assetPath: Assets/FishNet/Demos/Authenticator/Scripts/Broadcasts.cs
uploadId: 866910
@@ -0,0 +1,153 @@
using FishNet.Connection;
using FishNet.Example.Authenticating;
using FishNet.Managing;
using FishNet.Transporting;
using System;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
namespace FishNet.Authenticating
{
/// <summary>
/// This authenticator is an example of how to let host bypass the authentication process.
/// When checking to authenticate on the client side call AuthenticateAsHost, and if returned true skip normal authentication.
/// </summary>
public abstract class HostAuthenticator : Authenticator
{
#region Serialized.
/// <summary>
/// True to enable use of AuthenticateAsHost.
/// </summary>
[Tooltip("True to enable use of AuthenticateAsHost.")]
[SerializeField]
private bool _allowHostAuthentication;
/// <summary>
/// Sets if to allow host authentication.
/// </summary>
/// <param name = "value"></param>
public void SetAllowHostAuthentication(bool value) => _allowHostAuthentication = value;
/// <summary>
/// Returns if AllowHostAuthentication is enabled.
/// </summary>
/// <returns></returns>
public bool GetAllowHostAuthentication() => _allowHostAuthentication;
#endregion
#region Private.
/// <summary>
/// A random hash which only exist if the server is started.
/// </summary>
private static string _hostHash = string.Empty;
#endregion
/// <summary>
/// Initializes this script for use.
/// </summary>
/// <param name = "networkManager"></param>
public override void InitializeOnce(NetworkManager networkManager)
{
base.InitializeOnce(networkManager);
// Listen for connection state of local server to set hash.
NetworkManager.ServerManager.OnServerConnectionState += ServerManager_OnServerConnectionState;
// Listen for broadcast from client. Be sure to set requireAuthentication to false.
NetworkManager.ServerManager.RegisterBroadcast<HostPasswordBroadcast>(OnHostPasswordBroadcast, false);
}
/// <summary>
/// Called after the local server connection state changes.
/// </summary>
private void ServerManager_OnServerConnectionState(ServerConnectionStateArgs obj)
{
int length = obj.ConnectionState == LocalConnectionState.Started ? 25 : 0;
SetHostHash(length);
}
/// <summary>
/// Received on server when a client sends the password broadcast message.
/// </summary>
/// <param name = "conn">Connection sending broadcast.</param>
/// <param name = "hpb"></param>
private void OnHostPasswordBroadcast(NetworkConnection conn, HostPasswordBroadcast hpb, Channel channel)
{
// Not accepting host authentications. This could be an attack.
if (!_allowHostAuthentication)
{
conn.Disconnect(true);
return;
}
/* If client is already authenticated this could be an attack. Connections
* are removed when a client disconnects so there is no reason they should
* already be considered authenticated. */
if (conn.IsAuthenticated)
{
conn.Disconnect(true);
return;
}
bool correctPassword = hpb.Password == _hostHash;
OnHostAuthenticationResult(conn, correctPassword);
}
/// <summary>
/// Called after handling a host authentication result.
/// </summary>
/// <param name = "conn">Connection authenticating.</param>
/// <param name = "authenticated">True if authentication passed.</param>
protected abstract void OnHostAuthenticationResult(NetworkConnection conn, bool authenticated);
/// <summary>
/// Sets a host hash of length.
/// </summary>
/// https://stackoverflow.com/questions/32932679/using-rngcryptoserviceprovider-to-generate-random-string
private void SetHostHash(int length)
{
if (length <= 0)
{
_hostHash = string.Empty;
}
else
{
const string charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()";
StringBuilder result = new();
using (RNGCryptoServiceProvider rng = new())
{
byte[] uintBuffer = new byte[sizeof(uint)];
while (length-- > 0)
{
rng.GetBytes(uintBuffer);
uint num = BitConverter.ToUInt32(uintBuffer, 0);
result.Append(charPool[(int)(num % (uint)charPool.Length)]);
}
}
_hostHash = result.ToString();
}
}
/// <summary>
/// Returns true if authentication was sent as the clientHost.
/// </summary>
/// <remarks>This should only be called from the client side when receiving an authentication request.</remarks>
protected bool TryAuthenticateAsClientHost()
{
if (!_allowHostAuthentication)
return false;
/* Host hash would only exist if also
* the server. */
if (_hostHash == string.Empty)
return false;
/* Send the password as it is only on the host. */
HostPasswordBroadcast hpb = new()
{
Password = _hostHash
};
NetworkManager.ClientManager.Broadcast(hpb);
return true;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c7497d751bb68f444b4343e3edc28e39
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
assetPath: Assets/FishNet/Demos/Authenticator/Scripts/HostAuthenticator.cs
uploadId: 866910
@@ -0,0 +1,136 @@
using FishNet.Authenticating;
using FishNet.Connection;
using FishNet.Managing;
using FishNet.Managing.Logging;
using FishNet.Transporting;
using System;
using FishNet.Managing.Transporting;
using UnityEngine;
namespace FishNet.Example.Authenticating
{
/// <summary>
/// This is an example of a password authenticator.
/// Never send passwords without encryption.
/// </summary>
public class PasswordAuthenticator : HostAuthenticator
{
#region Public.
/// <summary>
/// Called when authenticator has concluded a result for a connection. Boolean is true if authentication passed, false if failed.
/// Server listens for this event automatically.
/// </summary>
public override event Action<NetworkConnection, bool> OnAuthenticationResult;
#endregion
#region Serialized.
/// <summary>
/// Password to authenticate.
/// </summary>
[Tooltip("Password to authenticate.")]
[SerializeField]
private string _password = "HelloWorld";
#endregion
public override void InitializeOnce(NetworkManager networkManager)
{
base.InitializeOnce(networkManager);
// Listen for connection state change as client.
NetworkManager.ClientManager.OnClientConnectionState += ClientManager_OnClientConnectionState;
// Listen for broadcast from client. Be sure to set requireAuthentication to false.
NetworkManager.ServerManager.RegisterBroadcast<PasswordBroadcast>(OnPasswordBroadcast, false);
// Listen to response from server.
NetworkManager.ClientManager.RegisterBroadcast<ResponseBroadcast>(OnResponseBroadcast);
}
/// <summary>
/// Called when a connection state changes for the local client.
/// </summary>
private void ClientManager_OnClientConnectionState(ClientConnectionStateArgs args)
{
/* If anything but the started state then exit early.
* Only try to authenticate on started state. The server
* doesn't have to send an authentication request before client
* can authenticate, that is entirely optional and up to you. In this
* example the client tries to authenticate soon as they connect. */
if (args.ConnectionState != LocalConnectionState.Started)
return;
/* If was able to authenticate as clientHost
* there is no need to send the password authentication.
* Host authentication uses its own authentication approach. */
if (TryAuthenticateAsClientHost())
return;
/* If not sending host authentication, then
* authenticate normally. */
PasswordBroadcast pb = new()
{
Password = _password
};
NetworkManager.ClientManager.Broadcast(pb);
}
/// <summary>
/// Received on server when a client sends the password broadcast message.
/// </summary>
/// <param name = "conn">Connection sending broadcast.</param>
/// <param name = "pb"></param>
private void OnPasswordBroadcast(NetworkConnection conn, PasswordBroadcast pb, Channel channel)
{
/* If client is already authenticated this could be an attack. Connections
* are removed when a client disconnects so there is no reason they should
* already be considered authenticated. */
if (conn.IsAuthenticated)
{
conn.Disconnect(true);
return;
}
bool correctPassword = pb.Password == _password;
SendAuthenticationResponse(conn, correctPassword);
/* Invoke result. This is handled internally to complete the connection or kick client.
* It's important to call this after sending the broadcast so that the broadcast
* makes it out to the client before the kick. */
OnAuthenticationResult?.Invoke(conn, correctPassword);
}
/// <summary>
/// Received on client after server sends an authentication response.
/// </summary>
/// <param name = "rb"></param>
private void OnResponseBroadcast(ResponseBroadcast rb, Channel channel)
{
string result = rb.Passed ? "Authentication complete." : "Authentication failed.";
NetworkManager.Log(result);
}
/// <summary>
/// Sends an authentication result to a connection.
/// </summary>
private void SendAuthenticationResponse(NetworkConnection conn, bool authenticated)
{
/* Tell client if they authenticated or not. This is
* entirely optional but does demonstrate that you can send
* broadcasts to client on pass or fail. */
ResponseBroadcast rb = new()
{
Passed = authenticated
};
NetworkManager.ServerManager.Broadcast(conn, rb, false);
}
/// <summary>
/// Called after handling a host authentication result.
/// </summary>
/// <param name = "conn">Connection authenticating.</param>
/// <param name = "authenticated">True if authentication passed.</param>
protected override void OnHostAuthenticationResult(NetworkConnection conn, bool authenticated)
{
SendAuthenticationResponse(conn, authenticated);
OnAuthenticationResult?.Invoke(conn, authenticated);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 226e4eaf2fa685f48bdc3dfaa87c1453
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
assetPath: Assets/FishNet/Demos/Authenticator/Scripts/PasswordAuthenticator.cs
uploadId: 866910