mirror of
https://github.com/simtactics/mysimulation.git
synced 2025-03-15 23:01:21 +00:00
237 lines
10 KiB
C#
237 lines
10 KiB
C#
|
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
|
|||
|
}
|
|||
|
}
|