饭太稀
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Fantasy.Helper;
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace Fantasy.IdFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示一个唯一实体的ID。
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct EntityIdStruct
|
||||
{
|
||||
// EntityId:39 + 16 + 18 = 64
|
||||
// +-------------------+-----------------------------+------------------------------------+
|
||||
// | time(30) 最大34年 | SceneId(16) 最多65535个Scene | sequence(18) 每秒每个进程能生产262143个
|
||||
// +-------------------+-----------------------------+------------------------------------+
|
||||
public uint Time { get; set; }
|
||||
public uint SceneId { get; set; }
|
||||
public uint Sequence { get; set; }
|
||||
|
||||
public const uint MaskSequence = 0x3FFFF;
|
||||
public const uint MaskSceneId = 0xFFFF;
|
||||
public const uint MaskTime = 0x3FFFFFFF;
|
||||
|
||||
/// <summary>
|
||||
/// WorldEntityIdStruct(如果超过下面参数的设定该ID会失效)。
|
||||
/// </summary>
|
||||
/// <param name="time">time不能超过1073741823</param>
|
||||
/// <param name="sceneId">sceneId不能超过65535</param>
|
||||
/// <param name="sequence">sequence不能超过262143</param>
|
||||
public EntityIdStruct(uint time, uint sceneId, uint sequence)
|
||||
{
|
||||
// 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。
|
||||
Time = time;
|
||||
SceneId = sceneId;
|
||||
Sequence = sequence;
|
||||
}
|
||||
|
||||
public static implicit operator long(EntityIdStruct entityIdStruct)
|
||||
{
|
||||
ulong result = 0;
|
||||
result |= entityIdStruct.Sequence;
|
||||
result |= (ulong)entityIdStruct.SceneId << 18;
|
||||
result |= (ulong)entityIdStruct.Time << 34;
|
||||
return (long)result;
|
||||
}
|
||||
|
||||
public static implicit operator EntityIdStruct(long entityId)
|
||||
{
|
||||
var result = (ulong) entityId;
|
||||
var entityIdStruct = new EntityIdStruct
|
||||
{
|
||||
Sequence = (uint)(result & MaskSequence)
|
||||
};
|
||||
result >>= 18;
|
||||
entityIdStruct.SceneId = (uint)(result & MaskSceneId);
|
||||
result >>= 16;
|
||||
entityIdStruct.Time = (uint)(result & MaskTime);
|
||||
return entityIdStruct;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class EntityIdFactory : IEntityIdFactory
|
||||
{
|
||||
private readonly ushort _sceneId;
|
||||
|
||||
private uint _lastTime;
|
||||
private uint _lastSequence;
|
||||
private static readonly long Epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000;
|
||||
private static readonly long EpochThisYear = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000 - Epoch1970;
|
||||
|
||||
private EntityIdFactory() { }
|
||||
|
||||
public EntityIdFactory(uint sceneId)
|
||||
{
|
||||
switch (sceneId)
|
||||
{
|
||||
case > 65535:
|
||||
{
|
||||
throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255");
|
||||
}
|
||||
default:
|
||||
{
|
||||
_sceneId = (ushort)sceneId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long Create
|
||||
{
|
||||
get
|
||||
{
|
||||
var time = (uint)((TimeHelper.Now - EpochThisYear) / 1000);
|
||||
|
||||
if (time > _lastTime)
|
||||
{
|
||||
_lastTime = time;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
else if (++_lastSequence > EntityIdStruct.MaskSequence - 1)
|
||||
{
|
||||
_lastTime++;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
|
||||
return new EntityIdStruct(time, _sceneId, _lastSequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class EntityIdFactoryTool : IIdFactoryTool
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(ref long entityId)
|
||||
{
|
||||
var result = (ulong)entityId >> 34;
|
||||
return (uint)(result & EntityIdStruct.MaskTime);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(ref long entityId)
|
||||
{
|
||||
var result = (ulong)entityId >> 18;
|
||||
return (uint)(result & EntityIdStruct.MaskSceneId);
|
||||
}
|
||||
|
||||
public byte GetWorldId(ref long entityId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Fantasy.Helper;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace Fantasy.IdFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示一个运行时的ID。
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct RuntimeIdStruct
|
||||
{
|
||||
// RuntimeId:23 + 8 + 8 + 25 = 64
|
||||
// +-------------------+-----------------------------+--------------------------------------+
|
||||
// | time(23) 最大60天 | SceneId(16) 最多65535个Scene | sequence(25) 每秒每个进程能生产33554431个
|
||||
// +-------------------+-----------------------------+--------------------------------------+
|
||||
public uint Time { get; private set; }
|
||||
public uint SceneId { get; private set; }
|
||||
public uint Sequence { get; private set; }
|
||||
|
||||
public const uint MaskSequence = 0x1FFFFFF;
|
||||
public const uint MaskSceneId = 0xFFFF;
|
||||
public const uint MaskTime = 0x7FFFFF;
|
||||
|
||||
/// <summary>
|
||||
/// RuntimeIdStruct(如果超过下面参数的设定该ID会失效)。
|
||||
/// </summary>
|
||||
/// <param name="time">time不能超过8388607</param>
|
||||
/// <param name="sceneId">sceneId不能超过65535</param>
|
||||
/// <param name="sequence">sequence不能超过33554431</param>
|
||||
public RuntimeIdStruct(uint time, uint sceneId, uint sequence)
|
||||
{
|
||||
// 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。
|
||||
Time = time;
|
||||
SceneId = sceneId;
|
||||
Sequence = sequence;
|
||||
}
|
||||
|
||||
public static implicit operator long(RuntimeIdStruct runtimeIdStruct)
|
||||
{
|
||||
ulong result = runtimeIdStruct.Sequence;
|
||||
result |= (ulong)runtimeIdStruct.SceneId << 25;
|
||||
result |= (ulong)runtimeIdStruct.Time << 41;
|
||||
return (long)result;
|
||||
}
|
||||
|
||||
public static implicit operator RuntimeIdStruct(long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId;
|
||||
var runtimeIdStruct = new RuntimeIdStruct
|
||||
{
|
||||
Sequence = (uint)(result & MaskSequence)
|
||||
};
|
||||
result >>= 25;
|
||||
runtimeIdStruct.SceneId = (byte)(result & MaskSceneId);
|
||||
result >>= 16;
|
||||
runtimeIdStruct.Time = (uint)(result & MaskTime);
|
||||
return runtimeIdStruct;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RuntimeIdFactory : IRuntimeIdFactory
|
||||
{
|
||||
private readonly uint _sceneId;
|
||||
|
||||
private uint _lastTime;
|
||||
private uint _lastSequence;
|
||||
private readonly long _epochNow;
|
||||
private readonly long _epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000;
|
||||
|
||||
private RuntimeIdFactory() { }
|
||||
|
||||
public RuntimeIdFactory(uint sceneId) : this(TimeHelper.Now, sceneId) { }
|
||||
|
||||
public RuntimeIdFactory(long epochNow, uint sceneId)
|
||||
{
|
||||
switch (sceneId)
|
||||
{
|
||||
case > 65535:
|
||||
{
|
||||
throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255");
|
||||
}
|
||||
default:
|
||||
{
|
||||
_sceneId = (ushort)sceneId;
|
||||
_epochNow = epochNow - _epoch1970;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long Create
|
||||
{
|
||||
get
|
||||
{
|
||||
var time = (uint)((TimeHelper.Now - _epochNow) / 1000);
|
||||
|
||||
if (time > _lastTime)
|
||||
{
|
||||
_lastTime = time;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
else if (++_lastSequence > RuntimeIdStruct.MaskSequence - 1)
|
||||
{
|
||||
_lastTime++;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
|
||||
return new RuntimeIdStruct(time, _sceneId, _lastSequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RuntimeIdFactoryTool : IIdFactoryTool
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(ref long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId >> 41;
|
||||
return (uint)(result & RuntimeIdStruct.MaskTime);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(ref long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId >> 25;
|
||||
return (uint)(result & RuntimeIdStruct.MaskSceneId);
|
||||
}
|
||||
|
||||
public byte GetWorldId(ref long entityId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Fantasy.Helper;
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
|
||||
namespace Fantasy.IdFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Id生成器帮助类
|
||||
/// </summary>
|
||||
public static class IdFactoryHelper
|
||||
{
|
||||
private static IdFactoryType _idFactoryType = IdFactoryType.World;
|
||||
|
||||
/// <summary>
|
||||
/// EntityId工具
|
||||
/// </summary>
|
||||
public static IIdFactoryTool EntityIdTool { get; private set; } = new WorldEntityIdFactoryTool();
|
||||
|
||||
/// <summary>
|
||||
/// RuntimeId工具
|
||||
/// </summary>
|
||||
public static IIdFactoryTool RuntimeIdTool { get; private set; } = new WorldRuntimeIdFactoryTool();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="idFactoryType"></param>
|
||||
public static void Initialize(IdFactoryType idFactoryType)
|
||||
{
|
||||
_idFactoryType = idFactoryType;
|
||||
|
||||
switch (_idFactoryType)
|
||||
{
|
||||
case IdFactoryType.Default:
|
||||
{
|
||||
EntityIdTool = new EntityIdFactoryTool();
|
||||
RuntimeIdTool = new RuntimeIdFactoryTool();
|
||||
return;
|
||||
}
|
||||
case IdFactoryType.World:
|
||||
{
|
||||
EntityIdTool = new WorldEntityIdFactoryTool();
|
||||
RuntimeIdTool = new WorldRuntimeIdFactoryTool();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEntityIdFactory EntityIdFactory(uint sceneId, byte worldId)
|
||||
{
|
||||
switch (_idFactoryType)
|
||||
{
|
||||
case IdFactoryType.Default:
|
||||
{
|
||||
return new EntityIdFactory(sceneId);
|
||||
}
|
||||
case IdFactoryType.World:
|
||||
{
|
||||
return new WorldEntityIdFactory(sceneId, worldId);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static IRuntimeIdFactory RuntimeIdFactory(long epochNow, uint sceneId, byte worldId)
|
||||
{
|
||||
switch (_idFactoryType)
|
||||
{
|
||||
case IdFactoryType.Default:
|
||||
{
|
||||
return new RuntimeIdFactory(sceneId);
|
||||
}
|
||||
case IdFactoryType.World:
|
||||
{
|
||||
if (epochNow == 0)
|
||||
{
|
||||
epochNow = TimeHelper.Now;
|
||||
}
|
||||
|
||||
return new WorldRuntimeIdFactory(epochNow, sceneId, worldId);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static long EntityId(uint time, uint sceneId, byte wordId, uint sequence)
|
||||
{
|
||||
switch (_idFactoryType)
|
||||
{
|
||||
case IdFactoryType.Default:
|
||||
{
|
||||
return new EntityIdStruct(time, sceneId, sequence);
|
||||
}
|
||||
case IdFactoryType.World:
|
||||
{
|
||||
return new WorldEntityIdStruct(time, sceneId, wordId, sequence);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static long RuntimeId(uint time, uint sceneId, byte wordId, uint sequence)
|
||||
{
|
||||
switch (_idFactoryType)
|
||||
{
|
||||
case IdFactoryType.Default:
|
||||
{
|
||||
return new RuntimeIdStruct(time, sceneId, sequence);
|
||||
}
|
||||
case IdFactoryType.World:
|
||||
{
|
||||
return new WorldRuntimeIdStruct(time, sceneId, wordId, sequence);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Fantasy.IdFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// ID生成器规则
|
||||
/// </summary>
|
||||
public enum IdFactoryType
|
||||
{
|
||||
/// <summary>
|
||||
/// 空。
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// 默认生成器
|
||||
/// Scene最大为65535个。
|
||||
/// </summary>
|
||||
Default = 1,
|
||||
/// <summary>
|
||||
/// ID中包含World,使用这种方式可以不用管理合区的ID重复的问题。
|
||||
/// 但Scene的数量也会限制到255个。
|
||||
/// </summary>
|
||||
World = 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Fantasy.IdFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// EntityId生成器接口类
|
||||
/// </summary>
|
||||
public interface IEntityIdFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建一个新的Id
|
||||
/// </summary>
|
||||
public long Create { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RuntimeId生成器接口类
|
||||
/// </summary>
|
||||
public interface IRuntimeIdFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建一个新的Id
|
||||
/// </summary>
|
||||
public long Create { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Fantasy.IdFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Id扩展工具接口
|
||||
/// </summary>
|
||||
public interface IIdFactoryTool
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得创建时间
|
||||
/// </summary>
|
||||
/// <param name="entityId"></param>
|
||||
/// <returns></returns>
|
||||
public uint GetTime(ref long entityId);
|
||||
/// <summary>
|
||||
/// 获得SceneId
|
||||
/// </summary>
|
||||
/// <param name="entityId"></param>
|
||||
/// <returns></returns>
|
||||
public uint GetSceneId(ref long entityId);
|
||||
/// <summary>
|
||||
/// 获得WorldId
|
||||
/// </summary>
|
||||
/// <param name="entityId"></param>
|
||||
/// <returns></returns>
|
||||
public byte GetWorldId(ref long entityId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Fantasy.Helper;
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace Fantasy.IdFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示一个唯一实体的ID。
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct WorldEntityIdStruct
|
||||
{
|
||||
// EntityId:39 + 8 + 8 + 18 = 64
|
||||
// +-------------------+--------------------------+-----------------------+------------------------------------+
|
||||
// | time(30) 最大34年 | SceneId(8) 最多255个Scene | WordId(8) 最多255个世界 | sequence(18) 每秒每个进程能生产262143个
|
||||
// +-------------------+--------------------------+-----------------------+------------------------------------+
|
||||
public uint Time { get; private set; }
|
||||
public uint SceneId { get; private set; }
|
||||
public byte WordId { get; private set; }
|
||||
public uint Sequence { get; private set; }
|
||||
|
||||
public const uint MaskSequence = 0x3FFFF;
|
||||
public const uint MaskSceneId = 0xFF;
|
||||
public const uint MaskWordId = 0xFF;
|
||||
public const uint MaskTime = 0x3FFFFFFF;
|
||||
|
||||
/// <summary>
|
||||
/// WorldEntityIdStruct(如果超过下面参数的设定该ID会失效)。
|
||||
/// </summary>
|
||||
/// <param name="time">time不能超过1073741823</param>
|
||||
/// <param name="sceneId">sceneId不能超过255</param>
|
||||
/// <param name="wordId">wordId不能超过255</param>
|
||||
/// <param name="sequence">sequence不能超过262143</param>
|
||||
public WorldEntityIdStruct(uint time, uint sceneId, byte wordId, uint sequence)
|
||||
{
|
||||
// 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。
|
||||
Time = time;
|
||||
SceneId = sceneId;
|
||||
WordId = wordId;
|
||||
Sequence = sequence;
|
||||
}
|
||||
|
||||
public static implicit operator long(WorldEntityIdStruct entityIdStruct)
|
||||
{
|
||||
ulong result = 0;
|
||||
result |= entityIdStruct.Sequence;
|
||||
result |= (ulong)entityIdStruct.WordId << 18;
|
||||
result |= (ulong)(entityIdStruct.SceneId % (entityIdStruct.WordId * 1000)) << 26;
|
||||
result |= (ulong)entityIdStruct.Time << 34;
|
||||
return (long)result;
|
||||
}
|
||||
|
||||
public static implicit operator WorldEntityIdStruct(long entityId)
|
||||
{
|
||||
var result = (ulong) entityId;
|
||||
var entityIdStruct = new WorldEntityIdStruct
|
||||
{
|
||||
Sequence = (uint)(result & MaskSequence)
|
||||
};
|
||||
result >>= 18;
|
||||
entityIdStruct.WordId = (byte)(result & MaskWordId);
|
||||
result >>= 8;
|
||||
entityIdStruct.SceneId = (uint)(result & MaskSceneId) + (uint)entityIdStruct.WordId * 1000;
|
||||
result >>= 8;
|
||||
entityIdStruct.Time = (uint)(result & MaskTime);
|
||||
return entityIdStruct;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WorldEntityIdFactory : IEntityIdFactory
|
||||
{
|
||||
private readonly uint _sceneId;
|
||||
private readonly byte _worldId;
|
||||
|
||||
private uint _lastTime;
|
||||
private uint _lastSequence;
|
||||
private static readonly long Epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000;
|
||||
private static readonly long EpochThisYear = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000 - Epoch1970;
|
||||
|
||||
private WorldEntityIdFactory() { }
|
||||
|
||||
public WorldEntityIdFactory(uint sceneId, byte worldId)
|
||||
{
|
||||
switch (sceneId)
|
||||
{
|
||||
case > 255255:
|
||||
{
|
||||
throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255");
|
||||
}
|
||||
case < 1001:
|
||||
{
|
||||
throw new NotSupportedException($"sceneId:{sceneId} cannot be less than 1001");
|
||||
}
|
||||
default:
|
||||
{
|
||||
_sceneId = sceneId;
|
||||
_worldId = worldId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long Create
|
||||
{
|
||||
get
|
||||
{
|
||||
var time = (uint)((TimeHelper.Now - EpochThisYear) / 1000);
|
||||
|
||||
if (time > _lastTime)
|
||||
{
|
||||
_lastTime = time;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
else if (++_lastSequence > WorldEntityIdStruct.MaskSequence - 1)
|
||||
{
|
||||
_lastTime++;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
|
||||
return new WorldEntityIdStruct(time, _sceneId, _worldId, _lastSequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WorldEntityIdFactoryTool : IIdFactoryTool
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(ref long entityId)
|
||||
{
|
||||
var result = (ulong)entityId >> 34;
|
||||
return (uint)(result & WorldEntityIdStruct.MaskTime);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(ref long entityId)
|
||||
{
|
||||
var result = (ulong)entityId >> 18;
|
||||
var worldId = (uint)(result & WorldEntityIdStruct.MaskWordId) * 1000;
|
||||
result >>= 8;
|
||||
return (uint)(result & WorldEntityIdStruct.MaskSceneId) + worldId;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public byte GetWorldId(ref long entityId)
|
||||
{
|
||||
var result = (ulong)entityId >> 18;
|
||||
return (byte)(result & WorldEntityIdStruct.MaskWordId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Fantasy.Helper;
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
namespace Fantasy.IdFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示一个运行时的ID。
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct WorldRuntimeIdStruct
|
||||
{
|
||||
// RuntimeId:23 + 8 + 8 + 25 = 64
|
||||
// +-------------------+--------------------------+-----------------------+--------------------------------------+
|
||||
// | time(23) 最大60天 | SceneId(8) 最多255个Scene | WordId(8) 最多255个世界 | sequence(25) 每秒每个进程能生产33554431个
|
||||
// +-------------------+--------------------------+-----------------------+--------------------------------------+
|
||||
public uint Time { get; private set; }
|
||||
public uint SceneId { get; private set; }
|
||||
public byte WordId { get; private set; }
|
||||
public uint Sequence { get; private set; }
|
||||
|
||||
public const uint MaskSequence = 0x1FFFFFF;
|
||||
public const uint MaskSceneId = 0xFF;
|
||||
public const uint MaskWordId = 0xFF;
|
||||
public const uint MaskTime = 0x7FFFFF;
|
||||
|
||||
/// <summary>
|
||||
/// WorldRuntimeIdStruct(如果超过下面参数的设定该ID会失效)。
|
||||
/// </summary>
|
||||
/// <param name="time">time不能超过8388607</param>
|
||||
/// <param name="sceneId">sceneId不能超过255</param>
|
||||
/// <param name="wordId">wordId不能超过255</param>
|
||||
/// <param name="sequence">sequence不能超过33554431</param>
|
||||
public WorldRuntimeIdStruct(uint time, uint sceneId, byte wordId, uint sequence)
|
||||
{
|
||||
// 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。
|
||||
Time = time;
|
||||
SceneId = sceneId;
|
||||
WordId = wordId;
|
||||
Sequence = sequence;
|
||||
}
|
||||
|
||||
public static implicit operator long(WorldRuntimeIdStruct runtimeIdStruct)
|
||||
{
|
||||
ulong result = runtimeIdStruct.Sequence;
|
||||
result |= (ulong)runtimeIdStruct.WordId << 25;
|
||||
result |= (ulong)(runtimeIdStruct.SceneId % (runtimeIdStruct.WordId * 1000)) << 33;
|
||||
result |= (ulong)runtimeIdStruct.Time << 41;
|
||||
return (long)result;
|
||||
}
|
||||
|
||||
public static implicit operator WorldRuntimeIdStruct(long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId;
|
||||
var runtimeIdStruct = new WorldRuntimeIdStruct
|
||||
{
|
||||
Sequence = (uint)(result & MaskSequence)
|
||||
};
|
||||
result >>= 25;
|
||||
runtimeIdStruct.WordId = (byte)(result & MaskWordId);
|
||||
result >>= 8;
|
||||
runtimeIdStruct.SceneId = (uint)(result & MaskSceneId) + (uint)runtimeIdStruct.WordId * 1000;
|
||||
result >>= 8;
|
||||
runtimeIdStruct.Time = (uint)(result & MaskTime);
|
||||
return runtimeIdStruct;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WorldRuntimeIdFactory : IRuntimeIdFactory
|
||||
{
|
||||
private readonly uint _sceneId;
|
||||
private readonly byte _worldId;
|
||||
|
||||
private uint _lastTime;
|
||||
private uint _lastSequence;
|
||||
private readonly long _epochNow;
|
||||
private readonly long _epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000;
|
||||
|
||||
private WorldRuntimeIdFactory() { }
|
||||
|
||||
public WorldRuntimeIdFactory(uint sceneId, byte worldId) : this(TimeHelper.Now, sceneId, worldId) { }
|
||||
|
||||
public WorldRuntimeIdFactory(long epochNow, uint sceneId, byte worldId)
|
||||
{
|
||||
switch (sceneId)
|
||||
{
|
||||
case > 255255:
|
||||
{
|
||||
throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255");
|
||||
}
|
||||
case < 1001:
|
||||
{
|
||||
throw new NotSupportedException($"sceneId:{sceneId} cannot be less than 1001");
|
||||
}
|
||||
default:
|
||||
{
|
||||
_sceneId = sceneId;
|
||||
_worldId = worldId;
|
||||
_epochNow = epochNow - _epoch1970;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long Create
|
||||
{
|
||||
get
|
||||
{
|
||||
var time = (uint)((TimeHelper.Now - _epochNow) / 1000);
|
||||
|
||||
if (time > _lastTime)
|
||||
{
|
||||
_lastTime = time;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
else if (++_lastSequence > WorldRuntimeIdStruct.MaskSequence - 1)
|
||||
{
|
||||
_lastTime++;
|
||||
_lastSequence = 0;
|
||||
}
|
||||
|
||||
return new WorldRuntimeIdStruct(time, _sceneId, _worldId, _lastSequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WorldRuntimeIdFactoryTool : IIdFactoryTool
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetTime(ref long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId >> 41;
|
||||
return (uint)(result & WorldRuntimeIdStruct.MaskTime);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public uint GetSceneId(ref long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId >> 25;
|
||||
var worldId = (uint)(result & WorldRuntimeIdStruct.MaskWordId) * 1000;
|
||||
result >>= 8;
|
||||
return (uint)(result & WorldRuntimeIdStruct.MaskSceneId) + worldId;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public byte GetWorldId(ref long runtimeId)
|
||||
{
|
||||
var result = (ulong)runtimeId >> 25;
|
||||
return (byte)(result & WorldRuntimeIdStruct.MaskWordId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user