Overwrite

Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
Unstable Kitsune
2023-11-28 23:20:26 -05:00
parent 3cd54811de
commit b918192e4e
11608 changed files with 2644205 additions and 47 deletions

371
Ultima/Sound.cs Normal file
View File

@@ -0,0 +1,371 @@
#region References
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
#endregion
namespace Ultima
{
public sealed class UOSound
{
public string Name;
public int ID;
public byte[] buffer;
public UOSound(string name, int id, byte[] buff)
{
Name = name;
ID = id;
buffer = buff;
}
};
public static class Sounds
{
private static Dictionary<int, int> m_Translations;
private static FileIndex m_FileIndex;
private static UOSound[] m_Cache;
private static bool[] m_Removed;
static Sounds()
{
Initialize();
}
/// <summary>
/// Reads Sounds and def
/// </summary>
public static void Initialize()
{
m_Cache = new UOSound[0xFFF];
m_Removed = new bool[0xFFF];
m_FileIndex = new FileIndex("soundidx.mul", "sound.mul", "soundLegacyMUL.uop", 0xFFF, 8, ".dat", -1, false);
var reg = new Regex(@"(\d{1,3}) \x7B(\d{1,3})\x7D (\d{1,3})", RegexOptions.Compiled);
m_Translations = new Dictionary<int, int>();
string line;
string path = Files.GetFilePath("Sound.def");
if (path == null)
{
return;
}
using (var reader = new StreamReader(path))
{
while ((line = reader.ReadLine()) != null)
{
if (((line = line.Trim()).Length != 0) && !line.StartsWith("#"))
{
Match match = reg.Match(line);
if (match.Success)
{
m_Translations.Add(int.Parse(match.Groups[1].Value), int.Parse(match.Groups[2].Value));
}
}
}
}
}
/// <summary>
/// Returns <see cref="UOSound" /> of ID
/// </summary>
/// <param name="soundID"></param>
/// <returns></returns>
public static UOSound GetSound(int soundID)
{
bool translated;
return GetSound(soundID, out translated);
}
/// <summary>
/// Returns <see cref="UOSound" /> of ID with bool translated in .def
/// </summary>
/// <param name="soundID"></param>
/// <param name="translated"></param>
/// <returns></returns>
public static UOSound GetSound(int soundID, out bool translated)
{
translated = false;
if (soundID < 0)
{
return null;
}
if (m_Cache[soundID] != null)
{
return m_Cache[soundID];
}
int length, extra;
bool patched;
Stream stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);
if ((m_FileIndex.Index[soundID].lookup < 0) || (length <= 0))
{
if (!m_Translations.TryGetValue(soundID, out soundID))
{
return null;
}
translated = true;
stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);
}
if (stream == null)
{
return null;
}
length -= 32;
int[] waveHeader = WaveHeader(length);
var stringBuffer = new byte[32];
var buffer = new byte[length];
stream.Read(stringBuffer, 0, 32);
stream.Read(buffer, 0, length);
stream.Close();
var resultBuffer = new byte[buffer.Length + (waveHeader.Length << 2)];
Buffer.BlockCopy(waveHeader, 0, resultBuffer, 0, (waveHeader.Length << 2));
Buffer.BlockCopy(buffer, 0, resultBuffer, (waveHeader.Length << 2), buffer.Length);
string str = Encoding.ASCII.GetString(stringBuffer);
// seems that the null terminator's not being properly recognized :/
if (str.IndexOf('\0') > 0)
{
str = str.Substring(0, str.IndexOf('\0'));
}
var sound = new UOSound(str, soundID, resultBuffer);
if (Files.CacheData)
{
if (!translated) // no .def definition
{
m_Cache[soundID] = sound;
}
}
return sound;
}
private static int[] WaveHeader(int length)
{
/* ====================
* = WAVE File layout =
* ====================
* char[4] = 'RIFF' \
* int - chunk size |- Riff Header
* char[4] = 'WAVE' /
* char[4] = 'fmt ' \
* int - chunk size |
* short - format |
* short - channels |
* int - samples p/s|- Format header
* int - avg bytes |
* short - align |
* short - bits p/s /
* char[4] - data \
* int - chunk size | - Data header
* short[..] - data /
* ====================
* */
return new[]
{0x46464952, (length + 36), 0x45564157, 0x20746D66, 0x10, 0x010001, 0x5622, 0xAC44, 0x100002, 0x61746164, length};
}
/// <summary>
/// Returns Soundname and tests if valid
/// </summary>
/// <param name="soundID"></param>
/// <returns></returns>
public static bool IsValidSound(int soundID, out string name)
{
name = "";
if (soundID < 0)
{
return false;
}
int length, extra;
bool patched;
Stream stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);
if ((m_FileIndex.Index[soundID].lookup < 0) || (length <= 0))
{
if (!m_Translations.TryGetValue(soundID, out soundID))
{
return false;
}
stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);
}
if (stream == null)
{
return false;
}
var stringBuffer = new byte[32];
stream.Read(stringBuffer, 0, 32);
stream.Close();
name = Encoding.ASCII.GetString(stringBuffer); // seems that the null terminator's not being properly recognized :/
if (name.IndexOf('\0') > 0)
{
name = name.Substring(0, name.IndexOf('\0'));
}
return true;
}
/// <summary>
/// Returns length of SoundID
/// </summary>
/// <param name="soundID"></param>
/// <returns></returns>
public static double GetSoundLength(int soundID)
{
if (soundID < 0)
{
return 0;
}
double len;
if (m_Cache[soundID] != null)
{
len = m_Cache[soundID].buffer.Length;
len -= 44; //wavheaderlength
}
else
{
int length, extra;
bool patched;
Stream stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);
if ((m_FileIndex.Index[soundID].lookup < 0) || (length <= 0))
{
if (!m_Translations.TryGetValue(soundID, out soundID))
{
return 0;
}
stream = m_FileIndex.Seek(soundID, out length, out extra, out patched);
}
if (stream == null)
{
return 0;
}
stream.Close();
length -= 32; //mulheaderlength
len = length;
}
len /= 0x5622; // Sample Rate
len /= 2;
return len;
}
public static void Add(int id, string name, string file)
{
using (var wav = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var resultBuffer = new byte[wav.Length];
wav.Seek(0, SeekOrigin.Begin);
wav.Read(resultBuffer, 0, (int)wav.Length);
m_Cache[id] = new UOSound(name, id, resultBuffer);
m_Removed[id] = false;
}
}
public static void Remove(int id)
{
m_Removed[id] = true;
m_Cache[id] = null;
}
public static void Save(string path)
{
string idx = Path.Combine(path, "soundidx.mul");
string mul = Path.Combine(path, "sound.mul");
int Headerlength = 44;
using (
FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write),
fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write))
{
using (BinaryWriter binidx = new BinaryWriter(fsidx), binmul = new BinaryWriter(fsmul))
{
for (int i = 0; i < m_Cache.Length; ++i)
{
UOSound sound = m_Cache[i];
if ((sound == null) && (!m_Removed[i]))
{
bool trans;
sound = GetSound(i, out trans);
if (!trans)
{
m_Cache[i] = sound;
}
else
{
sound = null;
}
}
if ((sound == null) || (m_Removed[i]))
{
binidx.Write(-1); // lookup
binidx.Write(-1); // length
binidx.Write(-1); // extra
}
else
{
binidx.Write((int)fsmul.Position); //lookup
var length = (int)fsmul.Position;
var b = new byte[32];
if (sound.Name != null)
{
byte[] bb = Encoding.Default.GetBytes(sound.Name);
if (bb.Length > 32)
{
Array.Resize(ref bb, 32);
}
bb.CopyTo(b, 0);
}
binmul.Write(b);
using (var m = new MemoryStream(sound.buffer))
{
m.Seek(Headerlength, SeekOrigin.Begin);
var resultBuffer = new byte[m.Length - Headerlength];
m.Read(resultBuffer, 0, (int)m.Length - Headerlength);
binmul.Write(resultBuffer);
}
length = (int)fsmul.Position - length;
binidx.Write(length);
binidx.Write(i + 1);
}
}
}
}
}
public static void SaveSoundListToCSV(string FileName)
{
using (
var Tex = new StreamWriter(
new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite), Encoding.GetEncoding(1252)))
{
Tex.WriteLine("ID;Name;Length");
string name = "";
for (int i = 1; i <= 0xFFF; ++i)
{
if (IsValidSound(i - 1, out name))
{
Tex.Write(String.Format("0x{0:X3}", i));
Tex.Write(String.Format(";{0}", name));
Tex.WriteLine(String.Format(";{0:f}", GetSoundLength(i - 1)));
}
}
}
}
}
}