major update
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Server;
|
||||
|
||||
public class RagonEntity
|
||||
{
|
||||
private static ushort _idGenerator = 100;
|
||||
public ushort Id { get; private set; }
|
||||
public ushort Type { get; private set; }
|
||||
public ushort StaticId { get; private set; }
|
||||
public ushort AttachId { get; private set; }
|
||||
public RagonRoomPlayer Owner { get; private set; }
|
||||
public RagonAuthority Authority { get; private set; }
|
||||
public RagonPayload Payload { get; private set; }
|
||||
public RagonEntityState State { get; private set; }
|
||||
|
||||
private readonly List<RagonEvent> _bufferedEvents;
|
||||
|
||||
public RagonEntity(RagonRoomPlayer owner, ushort type, ushort staticId, ushort attachId, RagonAuthority eventAuthority)
|
||||
{
|
||||
Owner = owner;
|
||||
StaticId = staticId;
|
||||
Type = type;
|
||||
AttachId = attachId;
|
||||
Id = _idGenerator++;
|
||||
Authority = eventAuthority;
|
||||
State = new RagonEntityState(this);
|
||||
Payload = new RagonPayload();
|
||||
|
||||
_bufferedEvents = new List<RagonEvent>();
|
||||
}
|
||||
|
||||
|
||||
public void SetOwner(RagonRoomPlayer owner)
|
||||
{
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
public void RestoreBufferedEvents(RagonRoomPlayer roomPlayer, RagonBuffer writer)
|
||||
{
|
||||
foreach (var evnt in _bufferedEvents)
|
||||
{
|
||||
writer.Clear();
|
||||
writer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT);
|
||||
writer.WriteUShort(evnt.EventCode);
|
||||
writer.WriteUShort(evnt.Invoker.Connection.Id);
|
||||
writer.WriteByte((byte)RagonReplicationMode.Server);
|
||||
writer.WriteUShort(Id);
|
||||
|
||||
evnt.Write(writer);
|
||||
|
||||
var sendData = writer.ToArray();
|
||||
roomPlayer.Connection.Reliable.Send(sendData);
|
||||
}
|
||||
}
|
||||
|
||||
public void Create()
|
||||
{
|
||||
var room = Owner.Room;
|
||||
var buffer = room.Writer;
|
||||
|
||||
buffer.Clear();
|
||||
buffer.WriteOperation(RagonOperation.CREATE_ENTITY);
|
||||
buffer.WriteUShort(AttachId);
|
||||
buffer.WriteUShort(Type);
|
||||
buffer.WriteUShort(Id);
|
||||
buffer.WriteUShort(Owner.Connection.Id);
|
||||
|
||||
Payload.Write(buffer);
|
||||
|
||||
var sendData = buffer.ToArray();
|
||||
foreach (var player in room.ReadyPlayersList)
|
||||
player.Connection.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
var room = Owner.Room;
|
||||
var buffer = room.Writer;
|
||||
|
||||
buffer.Clear();
|
||||
buffer.WriteOperation(RagonOperation.DESTROY_ENTITY);
|
||||
buffer.WriteUShort(Id);
|
||||
|
||||
Payload.Write(buffer);
|
||||
|
||||
var sendData = buffer.ToArray();
|
||||
foreach (var player in room.ReadyPlayersList)
|
||||
player.Connection.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
public void Snapshot(RagonBuffer buffer)
|
||||
{
|
||||
buffer.WriteUShort(Type);
|
||||
buffer.WriteUShort(Id);
|
||||
if (StaticId != 0)
|
||||
buffer.WriteUShort(StaticId);
|
||||
buffer.WriteUShort(Owner.Connection.Id);
|
||||
|
||||
buffer.WriteUShort(Payload.Size);
|
||||
Payload.Write(buffer);
|
||||
State.Snapshot(buffer);
|
||||
}
|
||||
|
||||
public void ReplicateEvent(
|
||||
RagonRoomPlayer caller,
|
||||
RagonEvent evnt,
|
||||
RagonReplicationMode eventMode,
|
||||
RagonRoomPlayer targetPlayer
|
||||
)
|
||||
{
|
||||
var room = Owner.Room;
|
||||
var buffer = room.Writer;
|
||||
|
||||
buffer.Clear();
|
||||
buffer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT);
|
||||
buffer.WriteUShort(evnt.EventCode);
|
||||
buffer.WriteUShort(caller.Connection.Id);
|
||||
buffer.WriteByte((byte)eventMode);
|
||||
buffer.WriteUShort(Id);
|
||||
|
||||
evnt.Write(buffer);
|
||||
|
||||
var sendData = buffer.ToArray();
|
||||
targetPlayer.Connection.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
public void ReplicateEvent(
|
||||
RagonRoomPlayer caller,
|
||||
RagonEvent evnt,
|
||||
RagonReplicationMode eventMode,
|
||||
RagonTarget targetMode
|
||||
)
|
||||
{
|
||||
if (Authority == RagonAuthority.OwnerOnly &&
|
||||
Owner.Connection.Id != caller.Connection.Id)
|
||||
{
|
||||
Console.WriteLine($"Player have not enough authority for event with Id {evnt.EventCode}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventMode == RagonReplicationMode.Buffered && targetMode != RagonTarget.Owner)
|
||||
{
|
||||
_bufferedEvents.Add(evnt);
|
||||
}
|
||||
|
||||
var room = Owner.Room;
|
||||
var buffer = room.Writer;
|
||||
|
||||
buffer.Clear();
|
||||
buffer.WriteOperation(RagonOperation.REPLICATE_ENTITY_EVENT);
|
||||
buffer.WriteUShort(evnt.EventCode);
|
||||
buffer.WriteUShort(caller.Connection.Id);
|
||||
buffer.WriteByte((byte)eventMode);
|
||||
buffer.WriteUShort(Id);
|
||||
|
||||
evnt.Write(buffer);
|
||||
|
||||
var sendData = buffer.ToArray();
|
||||
switch (targetMode)
|
||||
{
|
||||
case RagonTarget.Owner:
|
||||
{
|
||||
Owner.Connection.Reliable.Send(sendData);
|
||||
break;
|
||||
}
|
||||
case RagonTarget.ExceptOwner:
|
||||
{
|
||||
foreach (var roomPlayer in room.ReadyPlayersList)
|
||||
{
|
||||
if (roomPlayer.Connection.Id != Owner.Connection.Id)
|
||||
roomPlayer.Connection.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case RagonTarget.ExceptInvoker:
|
||||
{
|
||||
foreach (var roomPlayer in room.ReadyPlayersList)
|
||||
{
|
||||
if (roomPlayer.Connection.Id != caller.Connection.Id)
|
||||
roomPlayer.Connection.Reliable.Send(sendData);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case RagonTarget.All:
|
||||
{
|
||||
foreach (var roomPlayer in room.ReadyPlayersList)
|
||||
roomPlayer.Connection.Reliable.Send(sendData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Server;
|
||||
|
||||
public class RagonEntityState
|
||||
{
|
||||
private List<RagonProperty> _properties;
|
||||
private RagonEntity _entity;
|
||||
|
||||
public RagonEntityState(RagonEntity entity, int capacity = 10)
|
||||
{
|
||||
_entity = entity;
|
||||
_properties = new List<RagonProperty>(10);
|
||||
}
|
||||
|
||||
public void AddProperty(RagonProperty property)
|
||||
{
|
||||
_properties.Add(property);
|
||||
}
|
||||
|
||||
public void Write(RagonBuffer buffer)
|
||||
{
|
||||
buffer.WriteUShort(_entity.Id);
|
||||
foreach (var property in _properties)
|
||||
{
|
||||
if (property.IsDirty)
|
||||
{
|
||||
buffer.WriteBool(true);
|
||||
property.Write(buffer);
|
||||
property.Clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer.WriteBool(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(RagonBuffer buffer)
|
||||
{
|
||||
foreach (var property in _properties)
|
||||
{
|
||||
if (buffer.ReadBool())
|
||||
property.Read(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void Snapshot(RagonBuffer buffer)
|
||||
{
|
||||
foreach (var property in _properties)
|
||||
{
|
||||
var hasPayload = property.IsFixed || !property.IsFixed && property.Size > 0;
|
||||
if (hasPayload)
|
||||
{
|
||||
buffer.WriteBool(true);
|
||||
property.Write(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer.WriteBool(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Server;
|
||||
|
||||
public class RagonEvent
|
||||
{
|
||||
public RagonRoomPlayer Invoker { get; private set; }
|
||||
public ushort EventCode { get; private set; }
|
||||
public ushort Size => (ushort) _size;
|
||||
|
||||
private uint[] _data = new uint[128];
|
||||
private int _size = 0;
|
||||
|
||||
public RagonEvent(
|
||||
RagonRoomPlayer invoker,
|
||||
ushort eventCode
|
||||
)
|
||||
{
|
||||
Invoker = invoker;
|
||||
EventCode = eventCode;
|
||||
}
|
||||
|
||||
public void Read(RagonBuffer buffer)
|
||||
{
|
||||
var readOnlySpan = _data.AsSpan();
|
||||
_size = buffer.Capacity;
|
||||
buffer.ReadSpan(ref readOnlySpan, _size);
|
||||
}
|
||||
|
||||
public void Write(RagonBuffer buffer)
|
||||
{
|
||||
if (_size == 0) return;
|
||||
ReadOnlySpan<uint> readOnlySpan = _data.AsSpan();
|
||||
buffer.WriteSpan(ref readOnlySpan, _size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Server;
|
||||
|
||||
public class RagonPayload
|
||||
{
|
||||
private uint[] _data = new uint[128];
|
||||
private int _size = 0;
|
||||
|
||||
public ushort Size => (ushort) _size;
|
||||
|
||||
public void Read(RagonBuffer buffer)
|
||||
{
|
||||
var readOnlySpan = _data.AsSpan();
|
||||
|
||||
_size = buffer.Capacity;
|
||||
|
||||
buffer.ReadSpan(ref readOnlySpan, _size);
|
||||
}
|
||||
|
||||
public void Write(RagonBuffer buffer)
|
||||
{
|
||||
if (_size == 0) return;
|
||||
|
||||
ReadOnlySpan<uint> readOnlySpan = _data.AsSpan();
|
||||
|
||||
buffer.WriteSpan(ref readOnlySpan, _size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2023 Eduard Kargin <kargin.eduard@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
using System.ComponentModel;
|
||||
using Ragon.Protocol;
|
||||
|
||||
namespace Ragon.Server;
|
||||
|
||||
public class RagonProperty : RagonPayload
|
||||
{
|
||||
public int Size { get; set; }
|
||||
public bool IsDirty { get; private set; }
|
||||
public bool IsFixed { get; private set; }
|
||||
|
||||
private uint[] _data;
|
||||
|
||||
public RagonProperty(int size, bool isFixed)
|
||||
{
|
||||
Size = size;
|
||||
IsFixed = isFixed;
|
||||
IsDirty = false;
|
||||
|
||||
_data = new uint[128];
|
||||
}
|
||||
|
||||
public void Read(RagonBuffer buffer)
|
||||
{
|
||||
var readOnlySpan = _data.AsSpan();
|
||||
if (IsFixed)
|
||||
{
|
||||
buffer.ReadSpan(ref readOnlySpan, Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Size = (int) buffer.Read();
|
||||
buffer.ReadSpan(ref readOnlySpan, Size);
|
||||
}
|
||||
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Write(RagonBuffer buffer)
|
||||
{
|
||||
ReadOnlySpan<uint> readOnlySpan = _data.AsSpan();
|
||||
buffer.WriteSpan(ref readOnlySpan, Size);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
IsDirty = false;
|
||||
}
|
||||
|
||||
public void Dump()
|
||||
{
|
||||
Console.WriteLine( $"[{Size.ToString("00")}] {string.Join("", _data.Take(8).Reverse().Select(b => Convert.ToString(b, 2).PadLeft(32, '0')))}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user