Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
valarnin committed Jan 8, 2024
1 parent 96dc818 commit 692eda5
Show file tree
Hide file tree
Showing 11 changed files with 1,107 additions and 0 deletions.
275 changes: 275 additions & 0 deletions ACTOBSPlugin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using Advanced_Combat_Tracker;
using OBSWebsocketDotNet;
using OBSWebsocketDotNet.Communication;

namespace ACTOBSPlugin
{
public class ACTOBSPlugin : IActPluginV1
{
private OBSWebsocket obs;

private Label pluginStatusText;
private TabPage pluginScreenSpace;
private LogLineEventDelegate LogLineDel;

private CombatToggleEventDelegate OnCombatEndDel;

private PluginConfig config = new PluginConfig();

// We work around concurrency issues here by just using `ToList` on these collections whenever iterating over them
// Because changes to the structure are only initialized on init and on the UI thread, we don't need to lock
private List<Regex> startRecordingRegexes = new List<Regex>();
private List<Regex> stopRecordingRegexes = new List<Regex>();
private ConfigPanel configPanel;
private string lastVidFile;

private string GetPluginDirectory()
{
var plugin = ActGlobals.oFormActMain.ActPlugins.Where(x => x.pluginObj == this).FirstOrDefault();
if (plugin != null)
{
return Path.GetDirectoryName(plugin.pluginFile.FullName);
}
else
{
throw new Exception("Could not find ourselves in the plugin list!");
}
}

private void TryConnect()
{
if (config.Enabled)
{
try
{
obs.ConnectAsync(config.IPPort, config.Password);
}
catch (Exception ex)
{
ActGlobals.oFormActMain.BeginInvoke((MethodInvoker)delegate
{
MessageBox.Show("Connect failed : " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
});
}
}
}

private void Disconnect()
{
obs.Disconnect();
}

private void Obs_Disconnected(object sender, ObsDisconnectionInfo e)
{
UpdateStatus();
Task.Delay(5000).ContinueWith(_ => {
TryConnect();
});
}

private void Obs_Connected(object sender, EventArgs e)
{
UpdateStatus();
}

public void DeInitPlugin()
{
ActGlobals.oFormActMain.OnCombatEnd -= OnCombatEndDel;
ActGlobals.oFormActMain.BeforeLogLineRead -= LogLineDel;
config.Save();
}

private void RebuildRegexes(bool start, bool stop)
{
if (start)
{
startRecordingRegexes.Clear();
foreach (var txtRegex in config.StartRecording)
{
try
{
startRecordingRegexes.Add(new Regex(txtRegex, RegexOptions.IgnoreCase | RegexOptions.Compiled));
}
catch (Exception e)
{
ActGlobals.oFormActMain.WriteExceptionLog(e, "Exception parsing regex " + txtRegex);
}
}
}
if (stop)
{
stopRecordingRegexes.Clear();
foreach (var txtRegex in config.StopRecording)
{
try
{
stopRecordingRegexes.Add(new Regex(txtRegex, RegexOptions.IgnoreCase | RegexOptions.Compiled));
}
catch (Exception e)
{
ActGlobals.oFormActMain.WriteExceptionLog(e, "Exception parsing regex " + txtRegex);
}
}
}
}

public void InitPlugin(TabPage pluginScreenSpace, Label pluginStatusText)
{
var dir = GetPluginDirectory();
AppDomain.CurrentDomain.Load(File.ReadAllBytes(Path.Combine(dir, "System.Reactive.dll")));
AppDomain.CurrentDomain.Load(File.ReadAllBytes(Path.Combine(dir, "System.Threading.Channels.dll")));
AppDomain.CurrentDomain.Load(File.ReadAllBytes(Path.Combine(dir, "System.Threading.Tasks.Extensions.dll")));
AppDomain.CurrentDomain.Load(File.ReadAllBytes(Path.Combine(dir, "Websocket.Client.dll")));
AppDomain.CurrentDomain.Load(File.ReadAllBytes(Path.Combine(dir, "obs-websocket-dotnet.dll")));

this.pluginStatusText = pluginStatusText;
pluginStatusText.Text = "Loading PluginConfig";
config.Load();
RebuildRegexes(true, true);
config.ConfigChanged += (_, args) => {
RebuildRegexes(args.StartRecordingChanged, args.StopRecordingChanged);
if (args.EnabledChanged)
{
if (config.Enabled)
{
TryConnect();
}
else
{
Disconnect();
}
}
};

pluginStatusText.Text = "Creating ConfigPanel";
this.pluginScreenSpace = pluginScreenSpace;
pluginScreenSpace.Text = "ACT OBS Plugin";
configPanel = new ConfigPanel(config);
pluginScreenSpace.Controls.Add(configPanel);
pluginStatusText.Text = "In InitPlugin()";

PrivateInit();
}

private void PrivateInit()
{
obs = new OBSWebsocket();
obs.Connected += Obs_Connected;
obs.Disconnected += Obs_Disconnected;
TryConnect();

LogLineDel = (bool isImport, LogLineEventArgs logInfo) =>
{
try
{
var line = logInfo.originalLogLine;
if (obs.IsConnected)
{
if (!obs.GetRecordStatus().IsRecording)
{
foreach (var re in startRecordingRegexes)
{
if (re.IsMatch(line))
{
obs.StartRecord();
UpdateStatus();
}
}
}
else
{
foreach (var re in stopRecordingRegexes)
{
if (re.IsMatch(line))
{
// Get this info before calling `StopRecord` because it could change due to delay in stopping recording process
var currentEnc = ActGlobals.oFormActMain.ActiveZone.ActiveEncounter;
var currentZone = ActGlobals.oFormActMain.ActiveZone.ZoneName;
var vidFile = obs.StopRecord();
if (config.AutoRename)
{
Task.Delay(5000).ContinueWith(_ =>
{
var encTitle = currentEnc.Title;
var baseFilename = Path.GetFileNameWithoutExtension(vidFile);
var zoneEnc = string.Join("_", (currentZone + "_" + encTitle).Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries)).TrimEnd('.');
var extension = Path.GetExtension(vidFile);
var renamedFile = Path.Combine(
Path.GetDirectoryName(vidFile),
baseFilename + "_" + zoneEnc + extension
);
File.Move(vidFile, renamedFile);
lastVidFile = renamedFile;
UpdateStatus();
});
}
else
{
UpdateStatus();
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.ToString());
}
};

OnCombatEndDel = (_, encounterInfo) =>
{
return;
};

ActGlobals.oFormActMain.OnCombatEnd += OnCombatEndDel;

ActGlobals.oFormActMain.BeforeLogLineRead += LogLineDel;
}

private void UpdateStatus()
{
var status = "";

if (obs.IsConnected)
{
status += "Connected, ";
if (obs.GetRecordStatus().IsRecording)
{
status += "Recording";
}
else
{
status += "Not Recording";
}
}
else
{
status += "Disconnected, recording status unknown";
}

if (ActGlobals.oFormActMain.InvokeRequired)
{
ActGlobals.oFormActMain.Invoke((Action)(() => {
configPanel.SetStatus(status);
configPanel.SetLastFile(lastVidFile);
}));
}
else
{
configPanel.SetStatus(status);
configPanel.SetLastFile(lastVidFile);
}
}
}
}
119 changes: 119 additions & 0 deletions ACTOBSPlugin.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{0AAE9AA1-B683-4461-9396-2AA0A819FEED}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ACTOBSPlugin</RootNamespace>
<AssemblyName>ACTOBSPlugin</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="Advanced Combat Tracker">
<HintPath>..\..\OverlayPlugin\Thirdparty\ACT\Advanced Combat Tracker.exe</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="obs-websocket-dotnet, Version=5.0.0.3, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\obs-websocket-dotnet.5.0.0.3\lib\netstandard2.0\obs-websocket-dotnet.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Reactive, Version=4.3.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
<HintPath>packages\System.Reactive.4.3.2\lib\net46\System.Reactive.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System.Threading.Channels, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Threading.Channels.4.7.0\lib\netstandard2.0\System.Threading.Channels.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System.Windows" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="Websocket.Client, Version=4.4.0.0, Culture=neutral, PublicKeyToken=ae648c6d12f59b1b, processorArchitecture=MSIL">
<HintPath>packages\Websocket.Client.4.4.43\lib\netstandard2.0\Websocket.Client.dll</HintPath>
</Reference>
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="ACTOBSPlugin.cs" />
<Compile Include="ConfigPanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="ConfigPanel.Designer.cs">
<DependentUpon>ConfigPanel.cs</DependentUpon>
</Compile>
<Compile Include="PluginConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="ConfigPanel.resx">
<DependentUpon>ConfigPanel.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Loading

0 comments on commit 692eda5

Please sign in to comment.