mysimulation/server/tso.files/HIT/Hot.cs
Tony Bark 8fec258215 Added FSO.Files for use with the API server
Don't ask me. FreeSO is the prime example of dependency hell.
2024-05-01 04:38:12 -04:00

236 lines
10 KiB
C#
Executable file

using System;
using System.Collections.Generic;
using System.IO;
namespace FSO.Files.HIT
{
/// <summary>
/// Enumeration constants.
/// </summary>
public struct EventMappingEquate
{
public string Label;
public int Value;
}
/// <summary>
/// This section assigns a sound ID to a number of subroutines
/// (exported or not) in the corresponding HIT file.
/// </summary>
public struct TrackData
{
//The syntax for TrackData is A = B, where A is the sound's File ID
//and B is the offset to the subroutine in the accompanying HIT file.
public long FileID;
public int SubRoutineOffset;
}
/// <summary>
/// HOT (short for HIT Options Table) is an ini format that defines
/// enumeration constants and track data for HIT binary files.
/// </summary>
public class Hot
{
private int m_Version;
private int m_LoadPriority;
private List<EventMappingEquate> m_EventMappingEquations = new List<EventMappingEquate>();
private List<TrackData> m_TrackDataList = new List<TrackData>();
public Dictionary<uint, Track> Tracks = new Dictionary<uint, Track>();
public Dictionary<uint, Patch> Patches = new Dictionary<uint, Patch>();
public Dictionary<uint, Hitlist> Hitlists = new Dictionary<uint, Hitlist>();
public Dictionary<uint, uint> TrackData = new Dictionary<uint, uint>();
public Dictionary<string, EVTEntry> Events = new Dictionary<string, EVTEntry>();
private Dictionary<string, int> EventMappingEquate = new Dictionary<string, int>();
public HSM AsmNames;
/// <summary>
/// Gets this Hot instance's list of EventMappingEquate instances.
/// </summary>
public List<EventMappingEquate> EventMappingEquations
{
get { return m_EventMappingEquations; }
}
/// <summary>
/// Gets this Hot instance's list of TrackData instances.
/// </summary>
public List<TrackData> TrackDataList
{
get { return m_TrackDataList; }
}
public Hot(byte[] FileData)
{
LoadFrom(FileData);
}
public void LoadFrom(byte[] FileData)
{
StreamReader Reader = new StreamReader(new MemoryStream(FileData));
HotReadMode ActiveState = HotReadMode.None;
while (!Reader.EndOfStream)
{
string CurrentLine = Reader.ReadLine().Trim().Replace("\r\n", "");
switch (CurrentLine)
{
case "[EventMappingEquate]":
ActiveState = HotReadMode.EventMappingEquate;
break;
case "[Options]":
ActiveState = HotReadMode.Options;
break;
case "[TrackData]":
ActiveState = HotReadMode.TrackData;
break;
case "[EventMapping]":
//equivalent to .evt file
//(name)=(eventMappingEquate as event type),(trackid),0,0,0,0
ActiveState = HotReadMode.EventMapping;
break;
case "[Track]":
//equivalent to a lot of track files
//(trackid)=0,(subroutine),(volume),(arguments),(duckingPriority),(controlGroup),(soundPressureLevel),@(hitlistID),(patchID)
//patch id is usually 0, in favor of single item hitlists
ActiveState = HotReadMode.Track;
break;
case "[Patch]":
//(patchid)=(name),(filenameInQuotes),(looped),(piano),0,0,0
ActiveState = HotReadMode.Patch;
break;
case "[GlobalHitList]":
//(hitlistid)=(hitlistString)
//note: many hitlists contain just one patch
ActiveState = HotReadMode.GlobalHitList;
break;
}
if (!CurrentLine.Contains("["))
{
if (!CurrentLine.Contains("]"))
{
if (CurrentLine != "")
{
string[] Params = CurrentLine.Split("=".ToCharArray());
//EventMappingEquate fields look like: kSndobPlay=1
switch (ActiveState)
{
case HotReadMode.EventMappingEquate:
EventMappingEquate EMappingEquate = new EventMappingEquate();
EMappingEquate.Label = Params[0];
EMappingEquate.Value = int.Parse(Params[1]);
EventMappingEquate[EMappingEquate.Label] = EMappingEquate.Value;
break;
//Options fields look like: Version=1
case HotReadMode.Options:
switch (Params[0])
{
case "Version":
m_Version = int.Parse(Params[1]);
break;
case "LoadPriority":
m_LoadPriority = int.Parse(Params[1]);
break;
}
break;
//TrackData fields look like: 0xb0f4=0x10
case HotReadMode.TrackData:
TrackData.Add(Convert.ToUInt32(Params[0], 16), Convert.ToUInt32(Params[1], 16));
break;
case HotReadMode.EventMapping:
var commaSplit = Params[1].Split(',');
Events[Params[0].ToLowerInvariant()] = new EVTEntry
{
Name = Params[0].ToLowerInvariant(),
EventType = (uint)ParseEME(commaSplit[0]),
TrackID = (commaSplit.Length>1)?(uint)ParseEME(commaSplit[1]):0
};
break;
case HotReadMode.Track:
var tid = uint.Parse(Params[0]);
var tcSplit = Params[1].Split(',');
var trk = new Track()
{
SubroutineID = 0,//(uint)HSMConst(tcSplit[1]),
Volume = (uint)ParseEME(tcSplit[2]),
ArgType = (HITArgs)ParseEME(tcSplit[3]),
DuckingPriority = (HITDuckingPriorities)ParseEME(tcSplit[4]),
ControlGroup = (HITControlGroups)ParseEME(tcSplit[5]),
HitlistID = (uint)HSMConst(tcSplit[7].Substring(1)), //cut out @
SoundID = (uint)ParseEME(tcSplit[8])
};
if (trk.HitlistID != 0 && TrackData.ContainsKey(trk.HitlistID)) trk.SubroutineID = TrackData[trk.HitlistID];
if (trk.SoundID != 0 && TrackData.ContainsKey(trk.SoundID)) trk.SubroutineID = TrackData[trk.SoundID];
Tracks[tid] = trk;
break;
case HotReadMode.Patch:
var pid = uint.Parse(Params[0]);
var patch = new Patch(Params[1]);
Patches[pid] = patch;
break;
case HotReadMode.GlobalHitList:
var hid = uint.Parse(Params[0]);
try
{
var hitlist = Hitlist.HitlistFromString(Params[1]);
Hitlists[hid] = hitlist;
} catch (Exception)
{
/*
* todo: saxophone seems to reference an hsm.
* 20016=sulsaxj_way_aa
* 20017=sulsaxk_way_solo
* 20018=sulsaxl_way_fin
* these labels are in the hsm but they have a different case...
*/
}
break;
}
}
}
}
}
}
private int HSMConst(string input)
{
int result = 0;
AsmNames?.Constants?.TryGetValue(input, out result);
return result;
}
private int ParseEME(string eme)
{
int result = 0;
if (int.TryParse(eme, out result)) return result;
EventMappingEquate.TryGetValue(eme, out result);
return result;
}
public Hot(string Filepath) : this(File.ReadAllBytes(Filepath))
{
}
public Hot(string Filepath, HSM myAsm)
{
AsmNames = myAsm;
LoadFrom(File.ReadAllBytes(Filepath));
}
}
public enum HotReadMode
{
None,
EventMappingEquate,
Options,
TrackData,
EventMapping,
Track,
Patch,
GlobalHitList
}
}