Split project

This commit is contained in:
h z
2024-06-29 06:35:23 +08:00
parent b26404abd2
commit 117835b503
45 changed files with 1972 additions and 26 deletions

196
Boards/BaseBoard.cs Normal file
View File

@@ -0,0 +1,196 @@
using Enigmos.Cables;
using Enigmos.Modules;
using Enigmos.Modules.ControllingModules;
using Enigmos.Modules.ProgrammableModules;
using Enigmos.Modules.TerminalModules;
using Enigmos.Ports.DataPorts;
using Godot;
using Nocturnis.DataStructures;
using Nocturnis.Enigmos.Boards;
using Nocturnis.Enigmos.Cables;
using Nocturnis.Enigmos.Modules;
using Nocturnis.Enigmos.Ports;
using Nocturnis.Inventories.Items;
using Nocturnis.Inventories.Items.Items;
using Nocturnis.UIElements;
using Nocturnis.UIElements.Layers;
using TabulaSmaragdina;
using TabulaSmaragdina.Controls;
namespace Enigmos.Boards;
public abstract partial class BaseBoard : Panel, IBaseBoard
{
public bool CableVisualMode { get; set; }
public bool LabelVisualMode { get; set; }
public HashSet<IBaseCable> FocusedCables { get; set; } = new();
public void SetCableVisualMode(bool mode)
{
CableVisualMode = mode;
foreach (BaseCable cable in GetChildren().OfType<BaseCable>())
cable.Modulate = Color.Color8(255, 255, 255, (Byte)(mode ? 20 : 255));
}
public void SetLabelVisualMode(bool mode)
{
LabelVisualMode = mode;
foreach (BaseModule module in GetChildren().OfType<BaseModule>())
if(module.HasLabel())
module.Label!.Visible = !mode;
}
public void AddCable(IBaseCable cable)
{
AddChild(cable.AsNode);
cable.Modulate = Color.Color8(255, 255, 255, (Byte)(CableVisualMode ? 20 : 255));
}
public IModuleManualLayer? ModuleManualLayer { get; set; }
public bool ManualOpened { get; set; }
protected HashSet<IBaseModule> Modules { get; set; } = new();
protected IEnumerable<ProgrammableModule> ProgrammableModules() =>
Modules
.OfType<ProgrammableModule>();
public IEnumerable<TerminalModule> TerminalModules() =>
Modules
.OfType<TerminalModule>()
.Union(ProgrammableModules().SelectMany(module => module.UnderlyingBoard.TerminalModules()));
protected HashSet<IBasePort> Ports => Modules.SelectMany(module => module.Ports).ToHashSet();
public IPanelViewer? PanelViewer { get; set; }
public Dictionary<IBasePort, IBaseCable> CablePairing { get; set; } = new();
public IBasePort? ConnectPending { get; set; }
public IBoardControlLayer? CircuitBoardControlLayer { get; set; }
public IModuleMovingLayer? ModuleMovingLayer { get; set; }
public virtual void Init()
{
CablePairing = new Dictionary<IBasePort, IBaseCable>();
Modules = new HashSet<IBaseModule>();
FocusedCables = new HashSet<IBaseCable>();
ConnectPending = null;
}
public override void _Ready()
{
base._Ready();
ModuleManualLayer = GetNode<IModuleManualLayer>("ModuleManualLayer");
ModuleMovingLayer = GetNode<IModuleMovingLayer>("ModuleMovingLayer");
ModuleMovingLayer.Board = this;
PanelViewer = GetNode<IPanelViewer>("PanelViewer");
CircuitBoardControlLayer = GetNode<IBoardControlLayer>("CircuitBoardControlLayer");
CircuitBoardControlLayer.Board = this;
}
protected virtual void AddModule(IBaseModule module, Vector2 pos)
{
module.Board = this;
AddChild(module.AsNode);
if (module is ICompositeModule compositeModule)
foreach (IBaseModule subModule in compositeModule.SubModules())
subModule.Board = this;
module.Position = pos;
Modules.Add(module);
}
public virtual void Reset()
{
foreach (IBaseModule module in Modules)
{
if (module is RootModule rootModule)
rootModule.ActionFinished = false;
if (module is ICompositeModule compositeModule)
{
foreach (IBaseModule subModule in compositeModule.SubModules())
{
foreach (DataOutPort port in subModule.Ports.OfType<DataOutPort>())
{
port.DataUpdated = false;
}
}
}
if (module is ProgrammableModule programmableModule)
{
programmableModule.UnderlyingBoard.Reset();
foreach (DataOutPort outPort in programmableModule.ExplicitPorts().OfType<DataOutPort>())
outPort.DataUpdated = false;
foreach (DataOutPort outPort in programmableModule.ImplicitPorts().OfType<DataOutPort>())
outPort.DataUpdated = false;
}
if (module is ControllingModule controllingModule)
controllingModule.Visited = false;
if (module is TerminalModule terminalModule)
terminalModule.Finished = false;
foreach (DataOutPort port in module.Ports.OfType<DataOutPort>())
port.DataUpdated = false;
}
}
public override bool _CanDropData(Vector2 atPosition, Variant data)
{
IVariantWithType vData = data.As<IVariantWithType>();
if (vData.TypeHint != "Module")
{
if(vData.TypeHint != "Item")
return false;
IBaseItem item = vData.UnderlyingData.As<IBaseItem>();
if (item is IBaseModuleItem moduleItem)
{
foreach (IBaseModule module in Modules)
if (GlobalProvider.UIProvider.Overlap(atPosition, moduleItem.ContentModule.Size, module.Position, module.Size))
return false;
return true;
}
return false;
}
BaseModule? moduleData = vData.UnderlyingData.As<BaseModule?>();
if (moduleData == null)
return false;
Vector2 pos = atPosition - moduleData.PivotOffset;
foreach (IBaseModule module in Modules)
{
if(module == moduleData)
continue;
if (GlobalProvider.UIProvider.Overlap(pos, moduleData.Size, module.Position, module.Size))
return false;
}
return true;
}
public override void _DropData(Vector2 atPosition, Variant data)
{
IVariantWithType vData = data.As<IVariantWithType>();
if(vData.TypeHint == "Module")
{
BaseModule vModule = vData.UnderlyingData.As<BaseModule>();
vModule.Position = atPosition - vModule.PivotOffset;
vModule.UpdateCables();
}
else
{
IBaseModuleItem moduleItem = vData.UnderlyingData.As<IBaseModuleItem>();
AddModule(moduleItem.ContentModule, atPosition);
ItemDraggingControl.Instance.DraggingFrom!.Item = null;
}
}
protected T GetModule<T>(NodePath path) where T : BaseModule
{
T res = GetNode<T>(path);
res.Init();
Modules.Add(res);
res.Board = this;
return res;
}
}

View File

@@ -1,6 +0,0 @@
namespace Enigmos.Boards;
public interface IBaseBoard
{
}

24
Cables/BaseCable.cs Normal file
View File

@@ -0,0 +1,24 @@
using Godot;
using Nocturnis.Enigmos.Cables;
using Nocturnis.Enigmos.Ports;
namespace Enigmos.Cables;
public abstract partial class BaseCable : Line2D, IBaseCable
{
protected Line2D InFill { get; set; }
public IBasePort PortFrom { get; set; }
public IBasePort PortTo { get; set; }
public void Init()
{
InFill = GetNode<Line2D>("InFill");
}
/// <summary>
/// Update points of line
/// </summary>
public abstract void LineUpdate();
public Node AsNode => this;
}

View File

@@ -10,4 +10,10 @@
<PackageReference Include="GodotSharp" Version="4.3.0-beta.2" /> <PackageReference Include="GodotSharp" Version="4.3.0-beta.2" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Nocturnis\Nocturnis.csproj" />
<ProjectReference Include="..\TabulaSmaragdina\TabulaSmaragdina.csproj" />
<ProjectReference Include="..\VirtualChemistry\VirtualChemistry.csproj" />
</ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,6 @@
namespace Enigmos.Exceptions;
public class ModuleExecutionTimeout : Exception
{
public static readonly ModuleExecutionTimeout Exception = new ModuleExecutionTimeout();
}

View File

@@ -0,0 +1,45 @@
using Enigmos.Modules.Extensions;
using Godot;
using Nocturnis.Communicators;
using Nocturnis.Enigmos.ModuleManuals;
using Nocturnis.Enigmos.Modules;
namespace Enigmos.Manual;
public partial class CommunicatorPairTab : Panel, IModuleManualTab
{
private bool InitFlag { get; set; }
public string FullName() => "Pair";
public void Init(ICommunicateModule module)
{
Module = module;
InitFlag = true;
}
public ICommunicateModule Module { get; set; }
private OptionButton CommunicatorOptions { get; set; }
public override void _Ready()
{
if (!InitFlag)
throw new Exception("TODO - NEED INIT FIRST");
CommunicatorOptions = GetNode<OptionButton>("CommunicatorOptions");
IBaseCommunicator[] options = Module.CompatibleCommunicators();
for(int idx = 0; idx < options.Length; idx ++ )
{
CommunicatorOptions.AddIconItem
(
options[idx].IconTexture,
$"{options[idx].CustomName} " + (options[idx].Paired ? "(Already Paired)" : ""),
idx
);
}
Name = "Pair";
base._Ready();
}
private void SelectHandler(int idx)
{
Module.Pair(Module.CompatibleCommunicators()[idx]);
}
}

27
Manual/ErrorHandlerTab.cs Normal file
View File

@@ -0,0 +1,27 @@
using Godot;
using Nocturnis.Enigmos.ModuleManuals;
using Nocturnis.Enigmos.Modules;
namespace Enigmos.Manual;
public partial class ErrorHandlerTab : Panel, IModuleManualTab
{
public string FullName() => "Error Handling";
private bool InitFlag { get; set; }
private OptionButton Options { get; set; }
public void Init(IErrorHandlerModule module)
{
Module = module;
Options = GetNode<OptionButton>("Options");
Options.Clear();
for (int i = 0; i < module.HandlingOptions().Length; i++)
Options.AddItem(module.HandlingOptions()[i], i);
InitFlag = true;
}
private IErrorHandlerModule Module { get; set; }
private void SelectHandle(int idx) => Module.SelectedOption = idx;
}

View File

@@ -0,0 +1,38 @@
using Godot;
using Nocturnis.DataStructures.ConfigurableParameters;
namespace Enigmos.Manual;
public partial class ModuleBoolValueParameterSetter : ModuleParameterSetter
{
private CheckButton ToggleSetter { get; set; }
private Label TrueLabel { get; set; }
private Label FalseLabel { get; set; }
public void Init(IBoolParameter parameter)
{
UnderlyingParameter = parameter;
InitFlag = true;
}
public new IBoolParameter UnderlyingParameter
{
get => (base.UnderlyingParameter as IBoolParameter)!;
set => base.UnderlyingParameter = value;
}
public override void _Ready()
{
if (!InitFlag)
throw new Exception("TODO - INIT NEED");
ToggleSetter = GetNode<CheckButton>("ToggleSetter");
TrueLabel = GetNode<Label>("TrueLabel");
FalseLabel = GetNode<Label>("FalseLabel");
ToggleSetter.ButtonPressed = UnderlyingParameter.ParameterValue;
TrueLabel.Text = UnderlyingParameter.TrueDescription;
FalseLabel.Text = UnderlyingParameter.FalseDescription;
base._Ready();
}
private void ToggleHandler(bool val) => UnderlyingParameter.ParameterValue = val;
}

View File

@@ -0,0 +1,42 @@
using Godot;
using Nocturnis.DataStructures.ConfigurableParameters;
namespace Enigmos.Manual;
public partial class ModuleCharValueParameterSetter : ModuleParameterSetter
{
private LineEdit CharInput { get; set; }
private Button Apply { get; set; }
private Label ExtraInformation { get; set; }
public void Init(ICharParameter parameter)
{
UnderlyingParameter = parameter;
InitFlag = true;
}
public new ICharParameter UnderlyingParameter
{
get => (base.UnderlyingParameter as ICharParameter)!;
set => base.UnderlyingParameter = value;
}
public override void _Ready()
{
if (!InitFlag)
throw new Exception("TODO - INIT NEED");
Description = GetNode<Label>("Description");
Apply = GetNode<Button>("Apply");
CharInput = GetNode<LineEdit>("CharInput");
ExtraInformation = GetNode<Label>("ExtraInformation");
Description.Text = UnderlyingParameter.ParameterName;
CharInput.Text = UnderlyingParameter.ParameterValue.ToString();
base._Ready();
}
private void ApplyChange()
{
UnderlyingParameter.ParameterValue = CharInput.Text[0];
}
}

View File

@@ -0,0 +1,46 @@
using Godot;
using Nocturnis.DataStructures.ConfigurableParameters;
namespace Enigmos.Manual;
public partial class ModuleKeyValueParameterSetter : ModuleParameterSetter
{
public new IKeyParameter UnderlyingParameter
{
get => (base.UnderlyingParameter as IKeyParameter)!;
set => base.UnderlyingParameter = value;
}
private Button Binding { get; set; }
private bool ReadyToBind { get; set; }
public void Init(IKeyParameter parameter)
{
UnderlyingParameter = parameter;
ReadyToBind = false;
}
public override void _Ready()
{
Binding = GetNode<Button>("Binding");
}
private void StartBind()
{
Binding.Text = "Press a Key";
InputMap.ActionEraseEvents(UnderlyingParameter.ParameterValue);
ReadyToBind = true;
}
public override void _Input(InputEvent @event)
{
if (ReadyToBind && @event is InputEventKey keyEvent)
{
InputMap.ActionAddEvent(UnderlyingParameter.ParameterValue, keyEvent);
Binding.Text = keyEvent.AsTextKeyLabel();
ReadyToBind = false;
}
base._Input(@event);
}
}

113
Manual/ModuleManual.cs Normal file
View File

@@ -0,0 +1,113 @@
using Enigmos.Modules.ProgrammableModules;
using Godot;
using Nocturnis.Enigmos.ModuleManuals;
using Nocturnis.Enigmos.Modules;
using TabulaSmaragdina;
namespace Enigmos.Manual;
public partial class ModuleManual : Panel
{
private bool InitFlag { get; set; }
public void Init(IBaseModule module)
{
Module = module;
InitFlag = true;
}
private Label ModuleDescriptionTitle { get; set; }
private RichTextLabel ModuleDescription { get; set; }
private Label ModuleConfigurationTitle { get; set; }
private TextureButton Close { get; set; }
private TabContainer ConfigurationTabs { get; set; }
private IBaseModule Module { get; set; }
private List<IModuleManualTab> Tabs { get; set; }
private LineEdit LabelString { get; set; }
public override void _Ready()
{
if(!InitFlag)
throw new Exception("TODO - NEED INIT");
ModuleDescriptionTitle = GetNode<Label>("ModuleDescriptionTitle");
ModuleDescription = GetNode<RichTextLabel>("ModuleDescription");
ModuleConfigurationTitle = GetNode<Label>("ModuleConfigurationTitle");
Close = GetNode<TextureButton>("Close");
ConfigurationTabs = GetNode<TabContainer>("ConfigurationTabs");
ModuleDescription.Text = Module.GetDescription;
LabelString = GetNode<LineEdit>("LabelString");
LabelString.Text = Module.LabelString;
Tabs = new List<IModuleManualTab>();
PortMaintenanceTab mainTab = GlobalProvider.SceneProvider
.AssetMapper<PortMaintenanceTab>()
.Instantiate<PortMaintenanceTab>();
mainTab.Init(Module);
Tabs.Add(mainTab);
ConfigurationTabs.AddChild(mainTab);
if (Module is IPolymorphismModule polyModule)
{
ModulePolymorphismTab polyTab = GlobalProvider.SceneProvider
.AssetMapper<ModulePolymorphismTab>()
.Instantiate<ModulePolymorphismTab>();
polyTab.Init(polyModule);
Tabs.Add(polyTab);
ConfigurationTabs.AddChild(polyTab);
}
if (Module is IParameterizedModule paraModule)
{
ModuleParameterTab paraTab = GlobalProvider.SceneProvider
.AssetMapper<ModuleParameterTab>()
.Instantiate<ModuleParameterTab>();
paraTab.Init(paraModule);
Tabs.Add(paraTab);
ConfigurationTabs.AddChild(paraTab);
}
if (Module is ICommunicateModule comModule)
{
CommunicatorPairTab pairTab = GlobalProvider.SceneProvider
.AssetMapper<CommunicatorPairTab>()
.Instantiate<CommunicatorPairTab>();
pairTab.Init(comModule);
Tabs.Add(pairTab);
ConfigurationTabs.AddChild(pairTab);
}
if (Module is ProgrammableModule programmableModule)
{
ProgrammableModuleSettingTab progTab =GlobalProvider.SceneProvider
.AssetMapper<ProgrammableModuleSettingTab>()
.Instantiate<ProgrammableModuleSettingTab>();
progTab.Init(programmableModule);
Tabs.Add(progTab);
ConfigurationTabs.AddChild(progTab);
}
if (Module is IErrorHandlerModule errorHandlerModule)
{
ErrorHandlerTab errTab = GlobalProvider.SceneProvider
.AssetMapper<ErrorHandlerTab>()
.Instantiate<ErrorHandlerTab>();
errTab.Init(errorHandlerModule);
Tabs.Add(errTab);
ConfigurationTabs.AddChild(errTab);
}
base._Ready();
}
private void ShowTabTooltip(int idx) => ModuleConfigurationTitle.Text = Tabs[idx].FullName();
private void CloseManual()
{
GetParent().RemoveChild(this);
Module.Board.ManualOpened = false;
}
private void SetLabel(string label)
{
Module.Label.Text = label;
Module.LabelString = label;
}
}

View File

@@ -0,0 +1,19 @@
using Godot;
using Nocturnis.DataStructures.ConfigurableParameters;
namespace Enigmos.Manual;
public abstract partial class ModuleParameterSetter : Control
{
protected bool InitFlag { get; set; }
public IConfigurableParameter UnderlyingParameter { get; set; }
protected Label Description { get; set; }
public override void _Ready()
{
if (!InitFlag)
throw new Exception("TODO - NEED INIT");
Description = GetNode<Label>("Description");
Description.Text = UnderlyingParameter.ParameterName;
base._Ready();
}
}

View File

@@ -0,0 +1,73 @@
using Godot;
using Nocturnis.DataStructures.ConfigurableParameters;
using Nocturnis.Enigmos.ModuleManuals;
using Nocturnis.Enigmos.Modules;
using TabulaSmaragdina;
namespace Enigmos.Manual;
public partial class ModuleParameterTab : Panel, IModuleManualTab
{
public string FullName() => "Parameter";
private bool InitFlag { get; set; }
public void Init(IParameterizedModule module)
{
Module = module;
InitFlag = true;
}
public IParameterizedModule Module { get; set; }
private static readonly PackedScene RealParameterSetterScene =
GlobalProvider.SceneProvider.AssetMapper<ModuleRealValueParameterSetter>();
private static readonly PackedScene BoolParameterSetterScene =
GlobalProvider.SceneProvider.AssetMapper<ModuleBoolValueParameterSetter>();
private VBoxContainer Parameters { get; set; }
public override void _Ready()
{
if (!InitFlag)
throw new Exception("TODO - NEED INIT FIRST");
Parameters = GetNode<VBoxContainer>("ScrolledItems/Parameters");
foreach (IConfigurableParameter parameter in Module.ConfigurableParameters)
{
if(parameter is IDoubleParameter doubleParameter)
{
ModuleRealValueParameterSetter setter =
RealParameterSetterScene.Instantiate<ModuleRealValueParameterSetter>();
setter.Init(doubleParameter);
Parameters.AddChild(setter);
}
else if (parameter is IBoolParameter boolParameter)
{
ModuleBoolValueParameterSetter setter =
BoolParameterSetterScene.Instantiate<ModuleBoolValueParameterSetter>();
setter.Init(boolParameter);
Parameters.AddChild(setter);
}
else if (parameter is ICharParameter charParameter)
{
ModuleCharValueParameterSetter setter =
GlobalProvider.SceneProvider
.AssetMapper<ModuleCharValueParameterSetter>()
.Instantiate<ModuleCharValueParameterSetter>();
setter.Init(charParameter);
Parameters.AddChild(setter);
}
else if (parameter is IKeyParameter keyParameter)
{
ModuleKeyValueParameterSetter setter =
GlobalProvider.SceneProvider
.AssetMapper<ModuleKeyValueParameterSetter>()
.Instantiate<ModuleKeyValueParameterSetter>();
setter.Init(keyParameter);
Parameters.AddChild(setter);
}
}
Name = "Para";
base._Ready();
}
}

View File

@@ -0,0 +1,40 @@
using Godot;
using Nocturnis.DataStructures;
using Nocturnis.Enigmos.ModuleManuals;
using Nocturnis.Enigmos.Modules;
using TabulaSmaragdina;
namespace Enigmos.Manual;
public partial class ModulePolymorphismTab : Panel, IModuleManualTab
{
private bool InitFlag { get; set; }
public void Init(IPolymorphismModule module)
{
Module = module;
InitFlag = true;
}
public string FullName() => "Polymorphism";
private static readonly PackedScene PortTypeSelectorScene =
GlobalProvider.SceneProvider.AssetMapper<PortTypeSelector>();
public IPolymorphismModule Module { get; set; }
private VBoxContainer PortGroups { get; set; }
public override void _Ready()
{
if (!InitFlag)
throw new Exception("TODO - INIT REQUIRED");
PortGroups = GetNode<VBoxContainer>("ScrolledItems/PortGroups");
foreach (IDataPortGroup group in Module.ConfigurablePortGroups)
{
PortTypeSelector selector = PortTypeSelectorScene.Instantiate<PortTypeSelector>();
selector.Init(group);
PortGroups.AddChild(selector);
}
Name = "Poly";
base._Ready();
}
}

View File

@@ -0,0 +1,94 @@
using Godot;
using Nocturnis.DataStructures.ConfigurableParameters;
namespace Enigmos.Manual;
public partial class ModuleRealValueParameterSetter : ModuleParameterSetter
{
public void Init(IDoubleParameter parameter)
{
UnderlyingParameter = parameter;
InitFlag = true;
}
/// <summary>
/// Underlying Parameter must be set before ready
/// </summary>
public new IDoubleParameter UnderlyingParameter
{
get => (base.UnderlyingParameter as IDoubleParameter)!;
set => base.UnderlyingParameter = value;
}
private HSlider SliderSetter { get; set; }
private SpinBox SpinSetter { get; set; }
private double MinValue
{
get => SliderSetter.MinValue;
set
{
SliderSetter.MinValue = value;
SpinSetter.MinValue = value;
}
}
private double MaxValue
{
get => SliderSetter.MaxValue;
set
{
SliderSetter.MaxValue = value;
SpinSetter.MaxValue = value;
}
}
private double Step
{
get => SliderSetter.Step;
set
{
SliderSetter.Step = value;
SpinSetter.Step = value;
}
}
private Label MaxLabel { get; set; }
private Label MinLabel { get; set; }
private double Value
{
get => SliderSetter.Value;
set
{
SliderSetter.Value = value;
SpinSetter.Value = value;
}
}
public override void _Ready()
{
if (!InitFlag)
throw new Exception("TODO - NEED INIT");
SliderSetter = GetNode<HSlider>("SliderSetter");
SpinSetter = GetNode<SpinBox>("SpinSetter");
MaxLabel = GetNode<Label>("MaxLabel");
MinLabel = GetNode<Label>("MinLabel");
MinValue = UnderlyingParameter.MinValue;
MaxValue = UnderlyingParameter.MaxValue;
Step = UnderlyingParameter.Step;
Value = UnderlyingParameter.ParameterValue;
MaxLabel.Text = $"{MaxValue:F3}";
MinLabel.Text = $"{MinValue:F3}";
base._Ready();
}
private void SpinValueUpdateHandler(double val)
{
if (!SliderSetter.Value.Equals(val))
SliderSetter.Value = val;
UnderlyingParameter.ParameterValue = val;
}
private void SliderValueUpdateHandler(double val)
{
if (!SpinSetter.Value.Equals(val))
SpinSetter.Value = val;
UnderlyingParameter.ParameterValue = val;
}
}

48
Manual/PortFixer.cs Normal file
View File

@@ -0,0 +1,48 @@
using Godot;
using Nocturnis.Enigmos.Ports;
using Nocturnis.Inventories.ItemSlots.ItemSlots;
namespace Enigmos.Manual;
public partial class PortFixer : Control
{
private bool InitFlag { get; set; }
public void Init(IBasePort port)
{
RelatedPort = port;
InitFlag = true;
}
private IBasePort RelatedPort { get; set; }
private IChemicalItemSlot MaterialSlot { get; set; }
public Button FixPort { get; set; }
private Label PortLabel { get; set; }
private Label QualityLabel { get; set; }
private Label ConditionLabel { get; set; }
public override void _Ready()
{
if (!InitFlag)
throw new Exception("TODO - NOT INIT");
MaterialSlot = GetNode<IChemicalItemSlot>("MaterialSlot");
PortLabel = GetNode<Label>("PortLabel");
FixPort = GetNode<Button>("FixPort");
ConditionLabel = GetNode<Label>("ConditionLabel");
QualityLabel = GetNode<Label>("QualityLabel");
base._Ready();
}
private void UpdateInformation()
{
PortLabel.Text = $"Port : {RelatedPort?.Name}";
QualityLabel.Text = $"Quality : {RelatedPort?.Quality}";
ConditionLabel.Text = $"Condition : {RelatedPort?.Condition} / 100";
}
private void Fix() => RelatedPort.FixWith(MaterialSlot.Item);
public override void _Process(double delta)
{
UpdateInformation();
base._Process(delta);
}
}

View File

@@ -0,0 +1,72 @@
using Enigmos.Modules.ProgrammableModules;
using Enigmos.Ports;
using Godot;
using Nocturnis.Enigmos.ModuleManuals;
using Nocturnis.Enigmos.Modules;
using Nocturnis.Enigmos.Ports;
using TabulaSmaragdina;
namespace Enigmos.Manual;
public partial class PortMaintenanceTab : Panel, IModuleManualTab
{
private bool InitFlag { get; set; }
public void Init(IBaseModule module)
{
Module = module;
InitFlag = true;
}
public string FullName() => "Maintenance";
private static readonly PackedScene PortFixerScene = GlobalProvider.SceneProvider.AssetMapper<PortFixer>();
/// <summary>
/// Should Be Assigned Before This Tab Been Added As Child To Tab Container
/// </summary>
public IBaseModule Module { get; set; }
private VBoxContainer Ports { get; set; }
public override void _Ready()
{
if (!InitFlag)
throw new Exception("TODO - NEED INIT");
Ports = GetNode<VBoxContainer>("ScrolledItems/Ports");
foreach (IBasePort port in Module.Ports)
{
PortFixer fixer = PortFixerScene.Instantiate<PortFixer>();
fixer.Init(port);
Ports.AddChild(fixer);
}
if (Module is ProgrammableModule programmableModule)
{
HashSet<string> used = new HashSet<string>();
foreach (BasePort port in programmableModule.ExplicitPorts())
{
int i = 0;
while (used.Contains("Exterior" + port.Name + $"#{i}"))
i++;
used.Add("Exterior" + port.Name + $"#{i}");
port.Name = "Exterior" + port.Name + $"#{i}";
PortFixer fixer = PortFixerScene.Instantiate<PortFixer>();
fixer.Init(port);
Ports.AddChild(fixer);
}
foreach (BasePort port in programmableModule.ImplicitPorts())
{
string baseName = port.Name.ToString().Replace("Empty", "Interior");
int i = 0;
while (used.Contains(baseName + $"#{i}"))
i++;
used.Add(baseName + $"#{i}");
port.Name = baseName + $"#{i}";
PortFixer fixer = PortFixerScene.Instantiate<PortFixer>();
fixer.Init(port);
Ports.AddChild(fixer);
}
}
Name = "Main";
base._Ready();
}
}

View File

@@ -0,0 +1,41 @@
using Godot;
using Nocturnis.DataStructures;
using TabulaSmaragdina;
namespace Enigmos.Manual;
public partial class PortTypeSelector : Control
{
private bool InitFlag { get; set; }
public void Init(IDataPortGroup group)
{
UnderlyingGroup = group;
InitFlag = true;
}
/// <summary>
/// Underlying Group must be set before _Ready
/// </summary>
public IDataPortGroup UnderlyingGroup { get; set; }
private Label Description { get; set; }
private OptionButton TypeOptions { get; set; }
public override void _Ready()
{
if (!InitFlag)
throw new Exception("TODO - NEED INIT");
Description = GetNode<Label>("Description");
TypeOptions = GetNode<OptionButton>("TypeOptions");
TypeOptions.Clear();
for (int idx = 0; idx < UnderlyingGroup.TypeOptions.Length; idx++)
TypeOptions.AddIconItem(GlobalProvider.EnigmosProvider.DataPortTypeMap[UnderlyingGroup.TypeOptions[idx]], "", idx);
Description.Text = UnderlyingGroup.Description;
TypeOptions.Select(Array.IndexOf(UnderlyingGroup.TypeOptions, UnderlyingGroup.SelectedType));
}
private void SetType(int index)
{
UnderlyingGroup.SelectedType = UnderlyingGroup.TypeOptions[index];
UnderlyingGroup.Inference();
}
}

View File

@@ -0,0 +1,32 @@
using Enigmos.Modules.ProgrammableModules;
using Godot;
using Nocturnis.Enigmos.ModuleManuals;
using TabulaSmaragdina;
namespace Enigmos.Manual;
public partial class ProgrammableModuleSettingTab : Panel, IModuleManualTab
{
private ProgrammableModule Module { get; set; }
private Button EditModule { get; set; }
public void Init(ProgrammableModule module)
{
Module = module;
}
public override void _Ready()
{
EditModule = GetNode<Button>("EditModule");
Name = "Prog";
base._Ready();
}
public string FullName() => "Programmable";
private void EnterProgrammableBoard()
{
GlobalProvider.SceneProvider.RootScene.ChangeScene(Module.UnderlyingBoard);
}
}

162
Modules/BaseModule.cs Normal file
View File

@@ -0,0 +1,162 @@
using Enigmos.Exceptions;
using Enigmos.Manual;
using Enigmos.Modules.ControllingModules;
using Enigmos.Ports;
using Godot;
using Nocturnis.DataStructures;
using Nocturnis.Enigmos.Boards;
using Nocturnis.Enigmos.Cables;
using Nocturnis.Enigmos.Modules;
using Nocturnis.Enigmos.Ports;
using Nocturnis.UIElements;
using TabulaSmaragdina;
namespace Enigmos.Modules;
public abstract partial class BaseModule : TextureRect, IBaseModule
{
private static readonly Font GnuUni = ResourceLoader.Load<Font>("res://Resources/Fonts/GnuUnifontFull-Pm9P.ttf");
[Export] private int PresetPortQuality { get; set; }
[Export] private int PresetPortCondition { get; set; }
[Export] protected bool UsingPreset { get; set; }
[Export] public IPresetModuleConnection[] PresetConnections { get; set; }
[Export] public string LabelString { get; set; } = "";
public virtual Vector2 PositionToBoard => Position;
protected virtual bool Draggable() => true;
protected virtual bool HasManual() => true;
public bool HasLabel() => HasManual();
public virtual IEnumerable<IBasePort> Ports => Array.Empty<BasePort>();
public IBaseBoard? Board { get; set; }
private ModuleManual? Manual { get; set; }
public ISimpleLabel? Label { get; set; }
public Node AsNode => this;
public virtual void PresetValueInit()
{
foreach (IBasePort port in Ports)
{
port.Condition = PresetPortCondition;
port.Quality = PresetPortQuality;
}
}
public virtual void Init()
{
if (HasLabel())
{
Label = GlobalProvider.SceneProvider
.AssetMapper<ISimpleLabel>()
.Instantiate<ISimpleLabel>();
Label.Position = new Vector2(0, -25);
Label.Text = LabelString;
AddChild(Label.AsNode);
}
}
/// <summary>
/// Used to determine result of fixing a port with given material
/// </summary>
public virtual double MaintenanceAlpha => 0d;
/// <summary>
/// Used to determine result of fixing a port with given material
/// </summary>
public virtual double MaintenanceBeta => 0d;
public virtual string GetDescription => "";
public virtual void UpdateCables()
{
foreach (IBasePort port in Ports)
{
if(!Board!.CablePairing.ContainsKey(port))
continue;
Board.CablePairing[port].LineUpdate();
}
}
protected virtual void PostInit()
{
foreach (IBasePort port in Ports)
port.Module = this;
if(UsingPreset)
PresetValueInit();
}
protected virtual void TimeoutCheck(RootModule root)
{
if (root.Timer.ElapsedMilliseconds < 25) return;
root.Timer.Stop();
throw ModuleExecutionTimeout.Exception;
}
protected virtual void TimeoutHandler(ModuleExecutionTimeout timeout) => throw timeout;
public override Variant _GetDragData(Vector2 atPosition)
{
if (!Draggable())
return default;
Board!.ModuleMovingLayer.DraggingModule = this;
Board!.ModuleMovingLayer.MouseOffset = GetLocalMousePosition();
return GlobalProvider.DataStructureProvider.NewVariantWithType("Module", this);
}
protected T GetPort<T>(string path) where T : BasePort
{
T res = GetNode<T>(path);
res.Init();
return res;
}
public override void _Input(InputEvent @event)
{
if (@event is InputEventMouseButton eventMouseButton)
{
Vector2 mousePosition = GetLocalMousePosition();
if(mousePosition.X > 0 && mousePosition.X < Size.X && mousePosition.Y > 0 && mousePosition.Y < Size.Y)
{
if (eventMouseButton.ButtonIndex == MouseButton.Right && eventMouseButton.Pressed)
{
if (!HasManual())
return;
if (Board.ManualOpened)
return;
if (Manual == null)
{
Manual = GlobalProvider.SceneProvider
.AssetMapper<ModuleManual>()
.Instantiate<ModuleManual>();
Manual.Init(this);
}
Board.ModuleManualLayer.AddChild(Manual);
Manual.Position = Board.ModuleManualLayer.ManualPosition.Position - Manual.Size / 2;
Board.ManualOpened = true;
return;
}
if (eventMouseButton.ButtonIndex == MouseButton.Left && eventMouseButton.Pressed)
{
if (Board!.CableVisualMode)
{
foreach (IBaseCable cable in Board.FocusedCables)
cable.Modulate = Color.Color8(255, 255, 255, 20);
Board.FocusedCables = Ports
.Where(Board.CablePairing.ContainsKey)
.Select(p => Board.CablePairing[p])
.ToHashSet();
if (this is ICompositeModule thisCompositeModule)
foreach (IBasePort port in thisCompositeModule.SubModules().SelectMany(module => module.Ports).Where(Board.CablePairing.ContainsKey))
Board.FocusedCables.Add(Board.CablePairing[port]);
foreach (IBaseCable cable in Board.FocusedCables)
cable.Modulate = Color.Color8(255, 255, 255, 255);
}
}
}
}
base._Input(@event);
}
}

View File

@@ -0,0 +1,25 @@
using Enigmos.Modules.ControllingModules;
using Enigmos.Ports;
using Enigmos.Ports.DataPorts;
using Nocturnis.DataStructures;
namespace Enigmos.Modules.ComputationalModules;
public abstract partial class BinaryComputationalModule : ComputationalModule
{
protected DataInPort Input1 { get; set; }
protected DataInPort Input2 { get; set; }
public override IEnumerable<BasePort> Ports => new[] { Input1, Input2 };
public override void Init()
{
base.Init();
Input1 = GetPort<DataInPort>("Input1");
Input2 = GetPort<DataInPort>("Input2");
}
protected abstract void Compute(IDataPackage input1, IDataPackage input2);
protected override void Compute(RootModule root) => Compute(Input1.GetData(root), Input2.GetData(root));
}

View File

@@ -0,0 +1,31 @@
using Enigmos.Exceptions;
using Enigmos.Modules.ControllingModules;
using Enigmos.Ports.DataPorts;
namespace Enigmos.Modules.ComputationalModules;
public abstract partial class ComputationalModule : BaseModule
{
protected override void TimeoutHandler(ModuleExecutionTimeout timeout)
{
foreach (DataOutPort port in Ports.OfType<DataOutPort>())
port.DataUpdated = false;
base.TimeoutHandler(timeout);
}
protected abstract void Compute(RootModule root);
public void ComputeWithTimeoutHandle(RootModule root)
{
foreach (DataOutPort port in Ports.OfType<DataOutPort>())
port.DataUpdated = true;
try
{
Compute(root);
}
catch (ModuleExecutionTimeout timeOut)
{
TimeoutHandler(timeOut);
}
TimeoutCheck(root);
}
}

View File

@@ -0,0 +1,8 @@
using Enigmos.Ports;
namespace Enigmos.Modules.ComputationalModules;
public abstract partial class NullaryComputationalModule : ComputationalModule
{
public override IEnumerable<BasePort> Ports => Array.Empty<BasePort>();
}

View File

@@ -0,0 +1,29 @@
using Enigmos.Modules.ControllingModules;
using Enigmos.Ports;
using Enigmos.Ports.DataPorts;
using Nocturnis.DataStructures;
namespace Enigmos.Modules.ComputationalModules;
public abstract partial class QuaternaryComputationalModule : ComputationalModule
{
protected DataInPort Input1 { get; set; }
protected DataInPort Input2 { get; set; }
protected DataInPort Input3 { get; set; }
protected DataInPort Input4 { get; set; }
public override IEnumerable<BasePort> Ports => new[] { Input1, Input2, Input3, Input4 };
public override void Init()
{
base.Init();
Input1 = GetPort<DataInPort>("Input1");
Input2 = GetPort<DataInPort>("Input2");
Input3 = GetPort<DataInPort>("Input3");
Input4 = GetPort<DataInPort>("Input4");
}
protected abstract void Compute(IDataPackage input1, IDataPackage input2, IDataPackage input3, IDataPackage input4);
protected override void Compute(RootModule root) =>
Compute(Input1.GetData(root), Input2.GetData(root), Input3.GetData(root), Input4.GetData(root));
}

View File

@@ -0,0 +1,26 @@
using Enigmos.Modules.ControllingModules;
using Enigmos.Ports;
using Enigmos.Ports.DataPorts;
using Nocturnis.DataStructures;
namespace Enigmos.Modules.ComputationalModules;
public abstract partial class TernaryComputationalModule : ComputationalModule
{
protected DataInPort Input1 { get; set; }
protected DataInPort Input2 { get; set; }
protected DataInPort Input3 { get; set; }
public override IEnumerable<BasePort> Ports => new[] { Input1, Input2, Input3 };
public override void Init()
{
base.Init();
Input1 = GetPort<DataInPort>("Input1");
Input2 = GetPort<DataInPort>("Input2");
Input3 = GetPort<DataInPort>("Input3");
}
protected abstract void Compute(IDataPackage input1, IDataPackage input2, IDataPackage input3);
protected override void Compute(RootModule root) =>
Compute(Input1.GetData(root), Input2.GetData(root), Input3.GetData(root));
}

View File

@@ -0,0 +1,20 @@
using Enigmos.Modules.ControllingModules;
using Enigmos.Ports;
using Enigmos.Ports.DataPorts;
using Nocturnis.DataStructures;
namespace Enigmos.Modules.ComputationalModules;
public abstract partial class UnaryComputationalModule : ComputationalModule
{
protected DataInPort Input1 { get; set; }
public override IEnumerable<BasePort> Ports => new[] { Input1 };
public override void Init()
{
base.Init();
Input1 = GetPort<DataInPort>("Input1");
}
protected abstract void Compute(IDataPackage input1);
protected override void Compute(RootModule root) => Compute(Input1.GetData(root));
}

View File

@@ -0,0 +1,12 @@
namespace Enigmos.Modules.ControllingModules.ActionModules;
public abstract partial class ActionModule : ControllingModule
{
protected abstract void Execute(RootModule root);
protected override void Route(RootModule root)
{
if(!root.ActionFinished)
Execute(root);
root.ActionFinished = true;
}
}

View File

@@ -0,0 +1,34 @@
using Enigmos.Ports;
using Enigmos.Ports.DataPorts;
using Enigmos.Ports.SignalPorts;
using TabulaSmaragdina.Constants;
namespace Enigmos.Modules.ControllingModules.ActionModules;
public partial class AttackActionModule : ActionModule
{
private SignalInPort SignalIn1 { get; set; }
private SignalInPort SignalIn2 { get; set; }
private SignalInPort SignalIn3 { get; set; }
private SignalInPort SignalIn4 { get; set; }
private DataInPort Input1 { get; set; }
public override IEnumerable<BasePort> Ports =>
new BasePort[] { SignalIn1, SignalIn2, SignalIn3, SignalIn4, Input1 };
public override void Init()
{
base.Init();
SignalIn1 = GetNode<SignalInPort>("SignalIn1");
SignalIn2 = GetNode<SignalInPort>("SignalIn2");
SignalIn3 = GetNode<SignalInPort>("SignalIn3");
SignalIn4 = GetNode<SignalInPort>("SignalIn4");
Input1 = GetNode<DataInPort>("Input1");
Input1.SetDataType(EnigmosConstant.DataPortTypes.R2);
PostInit();
}
protected override void Execute(RootModule root) =>
root.ManagedBy.Action.Attack(Input1.GetData(root).R2);
}

View File

@@ -0,0 +1,41 @@
using Enigmos.Ports;
using Enigmos.Ports.DataPorts;
using Enigmos.Ports.SignalPorts;
using Skeleton.Algebra;
using Skeleton.Algebra.DimensionProviders;
using TabulaSmaragdina.Constants;
namespace Enigmos.Modules.ControllingModules.ActionModules;
using R2 = CategoryOf<IDim2>.OnField<double>.FVector;
public partial class MoveActionModule : ActionModule
{
private DataInPort Input1 { get; set; }
private SignalInPort SignalIn1 { get; set; }
private SignalInPort SignalIn2 { get; set; }
private SignalInPort SignalIn3 { get; set; }
private SignalInPort SignalIn4 { get; set; }
public override IEnumerable<BasePort> Ports => new BasePort[] { Input1, SignalIn1, SignalIn2, SignalIn3, SignalIn4 };
public override void Init()
{
base.Init();
Input1 = GetPort<DataInPort>("Input1");
SignalIn1 = GetPort<SignalInPort>("SignalIn1");
SignalIn2 = GetPort<SignalInPort>("SignalIn2");
SignalIn3 = GetPort<SignalInPort>("SignalIn3");
SignalIn4 = GetPort<SignalInPort>("SignalIn4");
Input1.SetDataType(EnigmosConstant.DataPortTypes.R2);
PostInit();
}
public override string GetDescription => "";
protected override void Execute(RootModule root)
{
R2 direction = Input1.GetData(root).R2;
root.ManagedBy.Action.Move(direction);
}
}

View File

@@ -0,0 +1,30 @@
using Enigmos.Exceptions;
namespace Enigmos.Modules.ControllingModules;
public abstract partial class ControllingModule : BaseModule
{
protected abstract void Route(RootModule root);
public bool Visited { get; set; }
protected override void TimeoutHandler(ModuleExecutionTimeout timeout)
{
Visited = false;
base.TimeoutHandler(timeout);
}
public void RouteWithTimeoutHandle(RootModule root)
{
if (Visited)
return;
TimeoutCheck(root);
try
{
Route(root);
}
catch (ModuleExecutionTimeout timeOut)
{
TimeoutHandler(timeOut);
}
}
}

View File

@@ -0,0 +1,34 @@
using System.Diagnostics;
using Enigmos.Ports;
using Enigmos.Ports.SignalPorts;
using Nocturnis.Creatures;
namespace Enigmos.Modules.ControllingModules;
public partial class RootModule : ControllingModule
{
public bool ActionFinished { get; set; }
public IBaseCreature ManagedBy { get; set; }
protected override bool Draggable() => false;
private SignalOutPort SignalOut1 { get; set; }
public override IEnumerable<BasePort> Ports => new[] { SignalOut1 };
public Stopwatch Timer { get; set; }
public override void Init()
{
base.Init();
ActionFinished = true;
SignalOut1 = GetPort<SignalOutPort>("SignalOut1");
PostInit();
}
protected override void Route(RootModule r)
{
if(!SignalOut1.Connected)
{
ActionFinished = true;
return;
}
Visited = true;
SignalOut1.ConnectedPort.Module.RouteWithTimeoutHandle(this);
}
}

View File

@@ -0,0 +1,47 @@
using Enigmos.Ports;
using Enigmos.Ports.DataPorts;
using Enigmos.Ports.SignalPorts;
using Nocturnis.DataStructures.ConfigurableParameters;
using Nocturnis.Enigmos.Modules;
using TabulaSmaragdina;
using TabulaSmaragdina.Constants;
namespace Enigmos.Modules.ControllingModules;
public partial class SinglePoleDoubleThrowSwitchModule : ControllingModule, IParameterizedModule
{
private DataInPort ControlInput { get; set; }
private SignalInPort SignalIn { get; set; }
private SignalOutPort SignalOut1 { get; set; }
private SignalOutPort SignalOut2 { get; set; }
public HashSet<IConfigurableParameter> ConfigurableParameters { get; set; }
private IBoolParameter LeftPortForTrue { get; set; }
public override IEnumerable<BasePort> Ports => new BasePort[] { SignalIn, SignalOut1, SignalOut2, ControlInput };
public override void Init()
{
base.Init();
SignalIn = GetPort<SignalInPort>("SignalIn");
SignalOut1 = GetPort<SignalOutPort>("SignalOut1");
SignalOut2 = GetPort<SignalOutPort>("SignalOut2");
ControlInput = GetPort<DataInPort>("ControlInput");
LeftPortForTrue =
GlobalProvider.DataStructureProvider.NewBoolParameter("Redirect to:", "Left", "Right", true);
ControlInput.SetDataType(EnigmosConstant.DataPortTypes.Bit);
ConfigurableParameters = new HashSet<IConfigurableParameter> { LeftPortForTrue };
PostInit();
}
protected override void Route(RootModule root)
{
Visited = true;
SignalOutPort selectedPort = (LeftPortForTrue.ParameterValue && ControlInput.GetData(root).Bit)
? SignalOut1
: SignalOut2;
if (selectedPort.Connected)
selectedPort.ConnectedPort.Module.RouteWithTimeoutHandle(root);
else
root.ActionFinished = true;
}
}

View File

@@ -0,0 +1,35 @@
using Enigmos.Ports;
using Enigmos.Ports.DataPorts;
using Enigmos.Ports.SignalPorts;
using TabulaSmaragdina.Constants;
namespace Enigmos.Modules.ControllingModules;
public partial class SinglePoleSingleThrowSwitchModule : ControllingModule
{
private SignalInPort SignalIn { get; set; }
private SignalOutPort SignalOut { get; set; }
private DataInPort ControlInput { get; set; }
public override IEnumerable<BasePort> Ports => new BasePort[] { SignalIn, SignalOut, ControlInput };
public override void Init()
{
base.Init();
SignalIn = GetPort<SignalInPort>("SignalIn");
SignalOut = GetPort<SignalOutPort>("SignalOut");
ControlInput = GetPort<DataInPort>("ControlInput");
ControlInput.SetDataType(EnigmosConstant.DataPortTypes.Bit);
PostInit();
}
protected override void Route(RootModule root)
{
Visited = true;
if (ControlInput.GetData(root).Bit && SignalOut.Connected)
SignalOut.ConnectedPort.Module.RouteWithTimeoutHandle(root);
else
root.ActionFinished = true;
}
}

View File

@@ -0,0 +1,64 @@
using Nocturnis.Communicators;
using Nocturnis.Enigmos.Modules;
using TabulaSmaragdina;
using TabulaSmaragdina.Constants;
using TabulaSmaragdina.Controls;
namespace Enigmos.Modules.Extensions;
public static class CommunicateModuleExtension
{
public static bool Paired(this ICommunicateModule module) => module.PairedCommunicator != null;
/// <summary>
/// Determine if the module can be paired with given communicator
/// </summary>
public static bool IsMatch(this ICommunicateModule module, IBaseCommunicator communicator) =>
module.CommunicationDataType == communicator.CommunicationDataType &&
GlobalProvider.EnigmosProvider.CommunicationDirectionCompatible(
module.CommunicationDirection,
communicator.CommunicationDirection
);
/// <summary>
/// Pair the module with given communicator
/// </summary>
public static void Pair(this ICommunicateModule module, IBaseCommunicator communicator)
{
if(module.Paired())
module.Unpair();
module.PairedCommunicator = communicator;
communicator.PairedModule = module;
}
/// <summary>
/// Unpair the module with its paired communicator
/// </summary>
public static void Unpair(this ICommunicateModule module)
{
if (!module.Paired())
return;
module.PairedCommunicator.PairedModule = null;
module.PairedCommunicator = null;
}
public static void SendData(this ICommunicateModule module)
{
if (!module.Paired() || module.CommunicationDirection == EnigmosConstant.CommunicationDirections.Receive)
return;
module.PairedCommunicator.DataBuffer.Assign(module.DataBuffer, module.CommunicationDataType);
}
public static void ReceiveData(this ICommunicateModule module)
{
if (!module.Paired() || module.CommunicationDirection == EnigmosConstant.CommunicationDirections.Send)
return;
module.DataBuffer.Assign(module.PairedCommunicator.DataBuffer, module.CommunicationDataType);
}
public static IBaseCommunicator[] CompatibleCommunicators(this ICommunicateModule module) =>
CreatureControl.Instance.CurrentCharacter!.DashboardTab.AllCommunicators
.Where(module.IsMatch)
.ToArray();
}

View File

@@ -1,9 +0,0 @@
namespace Enigmos.Modules;
using Godot;
public interface IBaseModule
{
Vector2 Size { get; set; }
Vector2 Position { get; set; }
Vector2 PositionToBoard { get; }
bool Draggable { get; }
}

View File

@@ -0,0 +1,34 @@
using Enigmos.Boards;
using Enigmos.Ports;
using Nocturnis.Enigmos.Modules;
using TabulaSmaragdina;
namespace Enigmos.Modules.ProgrammableModules;
public abstract partial class ProgrammableModule : BaseModule, ICompositeModule, IProgrammableModule
{
public BaseBoard UnderlyingBoard { get; set; }
public abstract IBaseModule[] SubModules();
public void EnterProgrammableBoard() => GlobalProvider.SceneProvider.RootScene.ChangeScene(UnderlyingBoard);
public abstract IEnumerable<BasePort> ExplicitPorts();
public abstract IEnumerable<BasePort> ImplicitPorts();
public override void UpdateCables()
{
foreach (BasePort port in ExplicitPorts())
{
if(!Board.CablePairing.ContainsKey(port) )
continue;
Board.CablePairing[port].LineUpdate();
}
base.UpdateCables();
}
protected T GetModule<T>(string path) where T : BaseModule, IInterlayerModule
{
T res = GetNode<T>(path);
res.Init();
res.ParentModule = this;
res.Board = Board;
return res;
}
}

View File

@@ -0,0 +1,36 @@
using Enigmos.Exceptions;
using Enigmos.Modules.ControllingModules;
using Enigmos.Ports.DataPorts;
namespace Enigmos.Modules.TerminalModules;
public abstract partial class TerminalModule : BaseModule
{
public bool Finished { get; set; }
protected virtual void Consume(RootModule root)
{
foreach (DataInPort port in Ports.OfType<DataInPort>())
port.GetData(root);
Finished = true;
}
public void ConsumeWithTimeoutHandle(RootModule root)
{
try
{
Finished = true;
Consume(root);
}
catch (ModuleExecutionTimeout timeout)
{
TimeoutHandler(timeout);
}
}
protected override void TimeoutHandler(ModuleExecutionTimeout timeout)
{
Finished = false;
base.TimeoutHandler(timeout);
}
}

107
Ports/BasePort.cs Normal file
View File

@@ -0,0 +1,107 @@
using Enigmos.Cables;
using Godot;
using Nocturnis.Enigmos.Cables;
using Nocturnis.Enigmos.Modules;
using Nocturnis.Enigmos.Ports;
using Nocturnis.Inventories.Items.Items;
using VirtualChemistry.Chemistry.Mixtures.Implements;
namespace Enigmos.Ports;
public abstract partial class BasePort : TextureButton, IBasePort
{
public virtual Vector2 PositionToBoard() => Position + PivotOffset + Module?.PositionToBoard ?? Vector2.Zero;
/// <summary>
/// When Condition is Equal to 0, Port is Disabled
/// </summary>
public int Condition { get; set; }
/// <summary>
/// Each time the port is used, there is 1/Quality chance to damage the Condition
/// </summary>
public int Quality { get; set; }
/// <summary>
/// Increase Condition
/// Modify Quality base on property of material
/// </summary>
public void FixWith(IBaseChemicalItem c)
{
if (c.ContentMaterial.Amount == 0)
return;
HeterogeneousMixture material = c.ContentMaterial;
double s = 1; //material.LayerOrder.Last.Value.CayleyValue();
double u = 1;//material.LayerOrder.Last.Value.EuclidValue();
double usedAmount = Math.Min(1d, material.LayerOrder.Last.Value.Amount);
double dCond = usedAmount * (Module.MaintenanceAlpha * s - Module.MaintenanceBeta * u);
double dQuality = usedAmount * (Math.Pow(Module.MaintenanceBeta, 2) * s - Module.MaintenanceAlpha * u);
c.ConsumeFromBottom(usedAmount);
Condition = Mathf.FloorToInt(Math.Max(0, Math.Min(100, Condition + dCond)));
Quality = Mathf.FloorToInt(Math.Max(0, Math.Min(20000, Quality + dQuality)));
}
public IBaseModule? Module { get; set; }
public abstract bool IsMatch(IBasePort oth);
public IBasePort? ConnectedPort { get; set; }
public bool Connected => ConnectedPort != null;
/// <summary>
/// Try to Connect two Ports
/// if this port is Connected already, it will disconnect first
/// </summary>
public void Connect()
{
if(Connected)
Disconnect();
if (Module.Board.ConnectPending == null)
{
SetStatusPending();
Module.Board.ConnectPending = this;
return;
}
if (Module.Board.ConnectPending.IsMatch(this))
{
ConnectedPort = Module.Board.ConnectPending;
Module.Board.ConnectPending.ConnectedPort = this;
BaseCable cable = MakeCable(Module.Board.ConnectPending);
Module.Board.CablePairing[this] = cable;
Module.Board.CablePairing[Module.Board.ConnectPending] = cable;
Module.Board.AddCable(cable);
cable.LineUpdate();
SetStatusConnected();
Module.Board.ConnectPending.SetStatusConnected();
Module.Board.ConnectPending = null;
return;
}
Module.Board.ConnectPending.SetStatusNormal();
Module.Board.ConnectPending = null;
}
protected virtual void Disconnect()
{
if (!Connected)
return;
IBaseCable cable = Module.Board.CablePairing[this];
Module.Board.CablePairing.Remove(ConnectedPort);
Module.Board.FocusedCables.Remove(Module.Board.CablePairing[this]);
Module.Board.CablePairing.Remove(this);
cable.Free();
ConnectedPort.SetStatusNormal();
ConnectedPort.ConnectedPort = null;
SetStatusNormal();
ConnectedPort = null;
}
public abstract void SetStatusPending();
public abstract void SetStatusConnected();
public abstract void SetStatusNormal();
/// <summary>
/// Determine whether this port can be connected with given port
/// </summary>
public abstract BaseCable MakeCable(IBasePort other);
public virtual void Init()
{
}
}

View File

@@ -0,0 +1,37 @@
using Enigmos.Cables;
using Enigmos.Modules.ControllingModules;
using Nocturnis.DataStructures;
using Nocturnis.Enigmos.Ports;
using TabulaSmaragdina;
namespace Enigmos.Ports.DataPorts;
public partial class DataInPort : DataPort, IDataInPort
{
public new DataOutPort ConnectedPort
{
get => base.ConnectedPort as DataOutPort;
set => base.ConnectedPort = value;
}
public override bool IsMatch(IBasePort other) =>
other is DataOutPort dataOut &&
GlobalProvider.EnigmosProvider.DataPortTypeCompatible(DataType, dataOut.DataType);
public IDataPackage GetData(RootModule root)
{
if (!Connected)
return GlobalProvider.DataStructureProvider.DefaultDataPackage;
if(!ConnectedPort.DataUpdated)
ConnectedPort.DataUpdateRequest(root);
return ConnectedPort.ResultData;
}
public override BaseCable MakeCable(IBasePort other)
{
BaseCable res = base.MakeCable(other);
res.PortFrom = this;
res.PortTo = other;
return res;
}
}

View File

@@ -0,0 +1,46 @@
using Enigmos.Cables;
using Enigmos.Modules.ComputationalModules;
using Enigmos.Modules.ControllingModules;
using Nocturnis.DataStructures;
using Nocturnis.Enigmos.Ports;
using TabulaSmaragdina;
namespace Enigmos.Ports.DataPorts;
public partial class DataOutPort : DataPort, IDataOutPort
{
public bool DataUpdated { get; set; }
public new ComputationalModule Module
{
get => base.Module as ComputationalModule;
set => base.Module = value;
}
public void DataUpdateRequest(RootModule root) => Module.ComputeWithTimeoutHandle(root);
public DataOutPort()
{
DataUpdated = false;
ResultData = GlobalProvider.DataStructureProvider.NewDataPackage();
}
public new DataInPort ConnectedPort
{
get => base.ConnectedPort as DataInPort;
set => base.ConnectedPort = value;
}
public override bool IsMatch(IBasePort other) =>
other is DataInPort inPort &&
GlobalProvider.EnigmosProvider.DataPortTypeCompatible(inPort.DataType, DataType);
public IDataPackage ResultData { get; set; }
public override BaseCable MakeCable(IBasePort other)
{
BaseCable res = base.MakeCable(other);
res.PortFrom = other;
res.PortTo = this;
return res;
}
}

View File

@@ -0,0 +1,54 @@
using Enigmos.Cables;
using Godot;
using Nocturnis.Enigmos.Ports;
using TabulaSmaragdina;
namespace Enigmos.Ports.DataPorts;
public abstract partial class DataPort : BasePort, IDataPort
{
public new DataPort ConnectedPort
{
get => base.ConnectedPort as DataPort;
set => base.ConnectedPort = value;
}
protected Sprite2D DataTypeTexture { get; set; }
public StringName DataType { get; set; }
public override void Init()
{
Console.WriteLine("XY");
DataTypeTexture = GetNode<Sprite2D>("DataTypeTexture");
DataTypeTexture.Visible = false;
base.Init();
}
public void SetDataType(StringName val)
{
if(Connected && val != ConnectedPort.DataType)
Disconnect();
DataType = val;
DataTypeTexture.Texture = GlobalProvider.EnigmosProvider.DataPortTypeMap[val];
}
private void MouseEnterHandler() => DataTypeTexture.Visible = true;
private void MouseExitHandler() => DataTypeTexture.Visible = false;
public override BaseCable MakeCable(IBasePort other)
{
BaseCable res = GlobalProvider.EnigmosProvider.DataCableScene.Instantiate<BaseCable>();
res.Init();
return res;
}
public override void SetStatusNormal() =>
TextureNormal = GlobalProvider.EnigmosProvider.DataPortStatusNormal;
public override void SetStatusPending() =>
TextureNormal = GlobalProvider.EnigmosProvider.DataPortStatusPending;
public override void SetStatusConnected() =>
TextureNormal = GlobalProvider.EnigmosProvider.DataPortStatusConnected;
}

View File

@@ -1,11 +0,0 @@
using Godot;
namespace Enigmos.Ports;
public interface IBasePort
{
Vector2 PositionToBoard();
int Condition { get; set; }
int Quality { get; set; }
}

View File

@@ -0,0 +1,29 @@
using Enigmos.Cables;
using Enigmos.Modules.ControllingModules;
using Nocturnis.Enigmos.Ports;
namespace Enigmos.Ports.SignalPorts;
public partial class SignalInPort : SignalPort, ISignalInPort
{
public new ControllingModule Module
{
get => base.Module as ControllingModule;
set => base.Module = value;
}
public new SignalOutPort ConnectedPort
{
get => base.ConnectedPort as SignalOutPort;
set => base.ConnectedPort = value;
}
public override bool IsMatch(IBasePort other) => other is SignalOutPort;
public override BaseCable MakeCable(IBasePort other)
{
BaseCable res = base.MakeCable(other);
res.PortFrom = this;
res.PortTo = other;
return res;
}
}

View File

@@ -0,0 +1,31 @@
using Enigmos.Cables;
using Enigmos.Modules.ControllingModules;
using Nocturnis.Enigmos.Ports;
namespace Enigmos.Ports.SignalPorts;
public partial class SignalOutPort : SignalPort, ISignalOutPort
{
public new ControllingModule Module
{
get => base.Module as ControllingModule;
set => base.Module = value;
}
public new SignalInPort ConnectedPort
{
get => base.ConnectedPort as SignalInPort;
set => base.ConnectedPort = value;
}
public override bool IsMatch(IBasePort other) => other is SignalInPort;
public override BaseCable MakeCable(IBasePort other)
{
BaseCable res = base.MakeCable(other);
res.PortFrom = other;
res.PortTo = this;
return res;
}
}

View File

@@ -0,0 +1,38 @@
using Enigmos.Cables;
using Godot;
using Nocturnis.Enigmos.Ports;
using TabulaSmaragdina;
namespace Enigmos.Ports.SignalPorts;
public abstract partial class SignalPort : BasePort, ISignalInPort
{
protected AnimatedSprite2D SignalDirection { get; set; }
public override void Init()
{
base.Init();
SignalDirection = GetNode<AnimatedSprite2D>("SignalDirection");
SignalDirection.Visible = false;
}
private void MouseEnteredHandler() => SignalDirection.Visible = true;
private void MouseExitedHandler() => SignalDirection.Visible = false;
public override void SetStatusConnected() =>
TextureNormal = GlobalProvider.EnigmosProvider.SignalPortStatusConnected;
public override void SetStatusNormal() =>
TextureNormal = GlobalProvider.EnigmosProvider.SignalPortStatusNormal;
public override void SetStatusPending() =>
TextureNormal = GlobalProvider.EnigmosProvider.SignalPortStatusPending;
public override BaseCable MakeCable(IBasePort other)
{
BaseCable res = GlobalProvider.EnigmosProvider.SignalCableScene.Instantiate<BaseCable>();
res.Init();
return res;
}
}