Danro-Jump/Assets/Scripts/Runtime/Hardware/Com/Transports/ReflectionSerialComTransport.cs
Danil Iarosh 1f6884c5ac Build gameplay systems and service settings
Подробные изменения:
- Добавлены и доработаны модальные окна главного меню, сервисные настройки, шаблоны UI Toolkit и единый scene-flow сервис для переходов между сценами.
- Расширена gameplay-архитектура: сессия забега, HUD, спавн контента платформ, collectible-предметы, оборудование, хрупкие и движущиеся платформы.
- Добавлена база противников: типы спавна, патрулирование, процедурный спавнер, правила размещения через ScriptableObject-сложности и убийство врагов прыжком сверху.
- Исправлены смерть и respawn игрока, финальный GameOver, отскоки от врагов, пружин и boost-предметов, а также проход сквозь врагов при усиленном подъеме.
- Проведен рефакторинг взаимодействия систем: общий landing context, единые правила player-contact, NonLazy gameplay session, fail-fast installer и централизованный выбор точек спавна.
- Обновлены сцены, prefab-ассеты, difficulty stages, ресурсы главного меню, настройки проекта, roadmap и аппаратная COM-интеграция.
- Добавлены ассеты летучей мыши, врагов, collectibles, TextMesh Pro, ProjectContext и gameplay UI.

Проверки:
- dotnet build .\\Assembly-CSharp.csproj --no-restore
- Unity validation ключевых gameplay/UI/scene-flow скриптов
- Unity Console после force refresh без ошибок
2026-05-27 16:34:51 +03:00

219 lines
9.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Reflection;
using System.Text;
namespace DanroJump.Hardware.Com
{
/// <summary>
/// Создает COM-транспорт через reflection-обертку над System.IO.Ports.SerialPort.
/// </summary>
public sealed class ReflectionSerialComTransportFactory : IComTransportFactory
{
/// <summary>
/// Создает транспорт для указанного serial-порта.
/// </summary>
public IComTransport Create(SerialSettings settings)
{
return ReflectionSerialComTransport.Create(settings);
}
}
/// <summary>
/// Reflection-адаптер serial-порта, который изолирует проект от прямой ссылки на System.IO.Ports.
/// </summary>
internal sealed class ReflectionSerialComTransport : IComTransport
{
private const BindingFlags InstancePublicFlags = BindingFlags.Public | BindingFlags.Instance;
private static readonly Type SerialPortType = Type.GetType("System.IO.Ports.SerialPort, System");
private static readonly Type ParityType = Type.GetType("System.IO.Ports.Parity, System");
private static readonly Type StopBitsType = Type.GetType("System.IO.Ports.StopBits, System");
private static readonly PropertyInfo IsOpenProperty = SerialPortType?.GetProperty("IsOpen", InstancePublicFlags);
private static readonly PropertyInfo DataBitsProperty = SerialPortType?.GetProperty("DataBits", InstancePublicFlags);
private static readonly PropertyInfo ParityProperty = SerialPortType?.GetProperty("Parity", InstancePublicFlags);
private static readonly PropertyInfo StopBitsProperty = SerialPortType?.GetProperty("StopBits", InstancePublicFlags);
private static readonly PropertyInfo ReadTimeoutProperty = SerialPortType?.GetProperty("ReadTimeout", InstancePublicFlags);
private static readonly PropertyInfo WriteTimeoutProperty = SerialPortType?.GetProperty("WriteTimeout", InstancePublicFlags);
private static readonly PropertyInfo NewLineProperty = SerialPortType?.GetProperty("NewLine", InstancePublicFlags);
private static readonly PropertyInfo EncodingProperty = SerialPortType?.GetProperty("Encoding", InstancePublicFlags);
private static readonly PropertyInfo DtrEnableProperty = SerialPortType?.GetProperty("DtrEnable", InstancePublicFlags);
private static readonly PropertyInfo RtsEnableProperty = SerialPortType?.GetProperty("RtsEnable", InstancePublicFlags);
private static readonly MethodInfo OpenMethod = SerialPortType?.GetMethod("Open", InstancePublicFlags, null, Type.EmptyTypes, null);
private static readonly MethodInfo CloseMethod = SerialPortType?.GetMethod("Close", InstancePublicFlags, null, Type.EmptyTypes, null);
private static readonly MethodInfo DiscardInBufferMethod = SerialPortType?.GetMethod("DiscardInBuffer", InstancePublicFlags, null, Type.EmptyTypes, null);
private static readonly MethodInfo DiscardOutBufferMethod = SerialPortType?.GetMethod("DiscardOutBuffer", InstancePublicFlags, null, Type.EmptyTypes, null);
private static readonly MethodInfo ReadLineMethod = SerialPortType?.GetMethod("ReadLine", InstancePublicFlags, null, Type.EmptyTypes, null);
private static readonly MethodInfo WriteLineMethod = SerialPortType?.GetMethod("WriteLine", InstancePublicFlags, null, new[] { typeof(string) }, null);
private readonly object instance;
private ReflectionSerialComTransport(object instance)
{
this.instance = instance;
}
/// <summary>
/// Показывает, открыт ли underlying serial-порт.
/// </summary>
public bool IsOpen => GetBoolProperty(IsOpenProperty);
/// <summary>
/// Создает и настраивает экземпляр SerialPort через reflection.
/// </summary>
public static ReflectionSerialComTransport Create(SerialSettings settings)
{
if (SerialPortType == null)
{
throw new InvalidOperationException("System.IO.Ports.SerialPort is not available.");
}
EnsureRequiredMetadata();
object serialPort = Activator.CreateInstance(SerialPortType, settings.PortName, settings.BaudRate);
var transport = new ReflectionSerialComTransport(serialPort);
transport.SetProperty(DataBitsProperty, settings.DataBits);
transport.SetProperty(ParityProperty, ParseEnum(ParityType, settings.Parity.ToString()));
transport.SetProperty(StopBitsProperty, ParseEnum(StopBitsType, settings.StopBits.ToString()));
transport.SetProperty(ReadTimeoutProperty, settings.ReadTimeoutMs);
transport.SetProperty(WriteTimeoutProperty, settings.WriteTimeoutMs);
transport.SetProperty(NewLineProperty, "\n");
transport.SetProperty(EncodingProperty, Encoding.UTF8);
transport.SetProperty(DtrEnableProperty, true);
transport.SetProperty(RtsEnableProperty, true);
return transport;
}
/// <summary>
/// Открывает serial-порт.
/// </summary>
public void Open()
{
Invoke(OpenMethod);
}
/// <summary>
/// Закрывает serial-порт.
/// </summary>
public void Close()
{
Invoke(CloseMethod);
}
/// <summary>
/// Очищает входной буфер serial-порта.
/// </summary>
public void DiscardInBuffer()
{
Invoke(DiscardInBufferMethod);
}
/// <summary>
/// Очищает выходной буфер serial-порта.
/// </summary>
public void DiscardOutBuffer()
{
Invoke(DiscardOutBufferMethod);
}
/// <summary>
/// Читает одну строку из serial-порта.
/// </summary>
public string ReadLine()
{
return (string)Invoke(ReadLineMethod);
}
/// <summary>
/// Записывает одну строку в serial-порт.
/// </summary>
public void WriteLine(string value)
{
Invoke(WriteLineMethod, value);
}
/// <summary>
/// Освобождает underlying SerialPort, если он поддерживает IDisposable.
/// </summary>
public void Dispose()
{
if (instance is IDisposable disposable)
{
disposable.Dispose();
}
}
/// <summary>
/// Проверяет наличие всех reflection-членов заранее, чтобы ошибки были явными.
/// </summary>
private static void EnsureRequiredMetadata()
{
Require(DataBitsProperty, "DataBits");
Require(ParityProperty, "Parity");
Require(StopBitsProperty, "StopBits");
Require(ReadTimeoutProperty, "ReadTimeout");
Require(WriteTimeoutProperty, "WriteTimeout");
Require(NewLineProperty, "NewLine");
Require(EncodingProperty, "Encoding");
Require(DtrEnableProperty, "DtrEnable");
Require(RtsEnableProperty, "RtsEnable");
Require(IsOpenProperty, "IsOpen");
Require(OpenMethod, "Open()");
Require(CloseMethod, "Close()");
Require(DiscardInBufferMethod, "DiscardInBuffer()");
Require(DiscardOutBufferMethod, "DiscardOutBuffer()");
Require(ReadLineMethod, "ReadLine()");
Require(WriteLineMethod, "WriteLine(string)");
}
private static void Require(MemberInfo member, string memberName)
{
if (member == null)
{
throw new MissingMemberException(SerialPortType?.FullName ?? "System.IO.Ports.SerialPort", memberName);
}
}
/// <summary>
/// Читает bool-свойство SerialPort через заранее найденный PropertyInfo.
/// </summary>
private bool GetBoolProperty(PropertyInfo property)
{
return property.GetValue(instance) is bool value && value;
}
/// <summary>
/// Записывает свойство SerialPort через заранее найденный PropertyInfo.
/// </summary>
private void SetProperty(PropertyInfo property, object value)
{
property.SetValue(instance, value);
}
/// <summary>
/// Вызывает метод SerialPort через reflection и пробрасывает реальную inner-ошибку.
/// </summary>
private object Invoke(MethodInfo method, params object[] args)
{
try
{
return method.Invoke(instance, args);
}
catch (TargetInvocationException exception) when (exception.InnerException != null)
{
// Наружу пробрасываем реальную ошибку serial-порта, а не reflection-обертку.
throw exception.InnerException;
}
}
private static object ParseEnum(Type enumType, string value)
{
if (enumType == null)
{
throw new InvalidOperationException("System.IO.Ports enum metadata is not available.");
}
return Enum.Parse(enumType, value);
}
}
}