feat(headless): share immutable gameplay content
This commit is contained in:
parent
12b500d383
commit
9569dadb57
25 changed files with 1031 additions and 429 deletions
|
|
@ -17,15 +17,20 @@ internal readonly record struct HeadlessProcessContentSnapshot(
|
|||
|
||||
internal interface IHeadlessProcessContentFactory
|
||||
{
|
||||
(IDatReaderWriter Dats, IPreparedAssetSource Prepared) Open(
|
||||
HeadlessOpenedProcessContent Open(
|
||||
HeadlessContentDescriptor descriptor,
|
||||
Action<string> diagnostic);
|
||||
}
|
||||
|
||||
internal sealed record HeadlessOpenedProcessContent(
|
||||
IDatReaderWriter Dats,
|
||||
IPreparedAssetSource Prepared,
|
||||
MagicCatalog Magic);
|
||||
|
||||
internal sealed class ProductionHeadlessProcessContentFactory
|
||||
: IHeadlessProcessContentFactory
|
||||
{
|
||||
public (IDatReaderWriter Dats, IPreparedAssetSource Prepared) Open(
|
||||
public HeadlessOpenedProcessContent Open(
|
||||
HeadlessContentDescriptor descriptor,
|
||||
Action<string> diagnostic)
|
||||
{
|
||||
|
|
@ -36,18 +41,30 @@ internal sealed class ProductionHeadlessProcessContentFactory
|
|||
string preparedAssetPath =
|
||||
Path.GetFullPath(descriptor.PreparedAssetPath);
|
||||
IDatReaderWriter? dats = null;
|
||||
IPreparedAssetSource? prepared = null;
|
||||
try
|
||||
{
|
||||
dats = RuntimeDatCollectionFactory.OpenReadOnly(datDirectory);
|
||||
var prepared = new PakPreparedAssetSource(
|
||||
prepared = new PakPreparedAssetSource(
|
||||
preparedAssetPath,
|
||||
dats,
|
||||
diagnostic);
|
||||
return (dats, prepared);
|
||||
MagicCatalog magic = MagicCatalog.Load(dats);
|
||||
return new HeadlessOpenedProcessContent(
|
||||
dats,
|
||||
prepared,
|
||||
magic);
|
||||
}
|
||||
catch
|
||||
{
|
||||
dats?.Dispose();
|
||||
try
|
||||
{
|
||||
prepared?.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
dats?.Dispose();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
|
@ -62,8 +79,10 @@ internal sealed class ProductionHeadlessProcessContentFactory
|
|||
internal sealed class HeadlessProcessContentOwner : IDisposable
|
||||
{
|
||||
private readonly object _gate = new();
|
||||
private readonly MagicCatalog _magic;
|
||||
private IDatReaderWriter? _dats;
|
||||
private IPreparedAssetSource? _prepared;
|
||||
private SharedPreparedCollisionCache? _collision;
|
||||
private int _leaseCount;
|
||||
private bool _disposeRequested;
|
||||
private bool _disposed;
|
||||
|
|
@ -75,30 +94,41 @@ internal sealed class HeadlessProcessContentOwner : IDisposable
|
|||
{
|
||||
ArgumentNullException.ThrowIfNull(descriptor);
|
||||
ArgumentNullException.ThrowIfNull(diagnostic);
|
||||
(IDatReaderWriter dats, IPreparedAssetSource prepared) =
|
||||
HeadlessOpenedProcessContent? opened =
|
||||
(factory ?? new ProductionHeadlessProcessContentFactory())
|
||||
.Open(descriptor, diagnostic);
|
||||
_dats = dats
|
||||
?? throw new InvalidOperationException(
|
||||
"The headless content factory returned no DAT owner.");
|
||||
_prepared = prepared
|
||||
?? throw new InvalidOperationException(
|
||||
"The headless content factory returned no prepared source.");
|
||||
if (prepared is not IPreparedCollisionSource)
|
||||
if (opened is null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"The headless content factory returned no content owner.");
|
||||
}
|
||||
IDatReaderWriter? dats = opened.Dats;
|
||||
IPreparedAssetSource? prepared = opened.Prepared;
|
||||
MagicCatalog? magic = opened.Magic;
|
||||
bool incomplete =
|
||||
dats is null || prepared is null || magic is null;
|
||||
if (incomplete || prepared is not IPreparedCollisionSource)
|
||||
{
|
||||
try
|
||||
{
|
||||
prepared.Dispose();
|
||||
prepared?.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
dats.Dispose();
|
||||
dats?.Dispose();
|
||||
}
|
||||
_prepared = null;
|
||||
_dats = null;
|
||||
throw new NotSupportedException(
|
||||
"Headless production content must expose prepared collision.");
|
||||
throw !incomplete
|
||||
&& prepared is not IPreparedCollisionSource
|
||||
? new NotSupportedException(
|
||||
"Headless production content must expose prepared collision.")
|
||||
: new InvalidOperationException(
|
||||
"The headless content factory returned an incomplete owner.");
|
||||
}
|
||||
_dats = dats!;
|
||||
_prepared = prepared!;
|
||||
_magic = magic!;
|
||||
_collision = new SharedPreparedCollisionCache(
|
||||
(IPreparedCollisionSource)prepared!);
|
||||
}
|
||||
|
||||
internal HeadlessProcessContentLease AcquireLease(string sessionId)
|
||||
|
|
@ -117,7 +147,9 @@ internal sealed class HeadlessProcessContentOwner : IDisposable
|
|||
this,
|
||||
sessionId,
|
||||
_dats!,
|
||||
_prepared!);
|
||||
_prepared!,
|
||||
_collision!,
|
||||
_magic);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,6 +195,11 @@ internal sealed class HeadlessProcessContentOwner : IDisposable
|
|||
|
||||
private void DrainResources()
|
||||
{
|
||||
if (_collision is not null)
|
||||
{
|
||||
_collision.Dispose();
|
||||
_collision = null;
|
||||
}
|
||||
if (_prepared is not null)
|
||||
{
|
||||
_prepared.Dispose();
|
||||
|
|
@ -181,17 +218,23 @@ internal sealed class HeadlessProcessContentOwner : IDisposable
|
|||
private HeadlessProcessContentOwner? _owner;
|
||||
private readonly IDatReaderWriter _dats;
|
||||
private readonly IPreparedAssetSource _prepared;
|
||||
private readonly IPreparedCollisionSource _collision;
|
||||
private readonly MagicCatalog _magic;
|
||||
|
||||
internal HeadlessProcessContentLease(
|
||||
HeadlessProcessContentOwner owner,
|
||||
string sessionId,
|
||||
IDatReaderWriter dats,
|
||||
IPreparedAssetSource prepared)
|
||||
IPreparedAssetSource prepared,
|
||||
IPreparedCollisionSource collision,
|
||||
MagicCatalog magic)
|
||||
{
|
||||
_owner = owner;
|
||||
SessionId = sessionId;
|
||||
_dats = dats;
|
||||
_prepared = prepared;
|
||||
_collision = collision;
|
||||
_magic = magic;
|
||||
}
|
||||
|
||||
internal string SessionId { get; }
|
||||
|
|
@ -214,8 +257,23 @@ internal sealed class HeadlessProcessContentOwner : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
internal IPreparedCollisionSource PreparedCollision =>
|
||||
(IPreparedCollisionSource)PreparedAssets;
|
||||
internal IPreparedCollisionSource PreparedCollision
|
||||
{
|
||||
get
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_owner is null, this);
|
||||
return _collision;
|
||||
}
|
||||
}
|
||||
|
||||
internal MagicCatalog MagicCatalog
|
||||
{
|
||||
get
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_owner is null, this);
|
||||
return _magic;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue