Skip to content

Commit

Permalink
- Fixed a bug in serialization system (core of load and save state sy…
Browse files Browse the repository at this point in the history
…stem) where some player animations become invisible after loading a state.

- Fixed the terrible noise caused by sounds with stop and loop positions not aligned with its wave format block align size.

- Fixed Jedi Sigma introduction animation.
  • Loading branch information
sharivan committed Apr 26, 2023
1 parent bd4aa46 commit 5d676b1
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 46 deletions.
64 changes: 60 additions & 4 deletions XSharp/Engine/BaseEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public static void Dispose()
private List<Vector> cameraConstraints;

protected bool frameAdvance;
protected long frameAdvanceStartTime;
protected bool recording;
protected bool playbacking;

Expand Down Expand Up @@ -1469,8 +1470,22 @@ private void OnSpawningBlackScreenComplete()
FadingOSTLevel = 0;
soundChannels[3].Volume = 0.5f;

if (romLoaded && mmx.Type == 0 && mmx.Level == 8)
PlayOST("Chill Penguin", 83, 50.152);
if (romLoaded)
{
if (mmx.Type == 0)
{
switch (mmx.Level)
{
case 8:
PlayOST("Chill Penguin", 83, 50.152);
break;

case 12:
PlayOST("Sigma Stage", 9.285, 4.677);
break;
}
}
}

FadingControl.Reset();
FadingControl.Start(Color.Black, 26, FadingFlags.COLORS, FadingFlags.COLORS, StartReadyHUD);
Expand Down Expand Up @@ -1543,6 +1558,11 @@ private Keys HandleInput(out bool nextFrame)
wasPressingNextFrame = true;
frameAdvance = true;
nextFrame = true;
frameAdvanceStartTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
}
else if (DateTimeOffset.Now.ToUnixTimeMilliseconds() - frameAdvanceStartTime >= 1000)
{
nextFrame = true;
}
}
else
Expand Down Expand Up @@ -2442,8 +2462,19 @@ public void LoadLevel(ushort level, ushort checkpoint = 0)
CurrentCheckpoint = checkpoints[mmx.Point];
CameraConstraintsBox = CurrentCheckpoint.Hitbox;

if (mmx.Type == 0 && mmx.Level == 8)
PrecacheSound("Chill Penguin", @"OST\X1\12 - Chill Penguin.mp3");
if (mmx.Type == 0)
{
switch (mmx.Level)
{
case 8:
PrecacheSound("Chill Penguin", @"OST\X1\12 - Chill Penguin.mp3");
break;

case 12:
PrecacheSound("Sigma Stage", @"OST\X1\27 - Sigma Intro 2.mp3");
break;
}
}
}
else
{
Expand Down Expand Up @@ -5855,11 +5886,36 @@ public void PlayBossIntroOST()
PlayOST("Boss Intro", 13, 6.328125);
}

public void PlaySigmaBossIntroOST()
{
PlayOST("Sigma Boss Intro", 16.418, 8.226);
}

public void PlayBossBatleOST()
{
PlayOST("Boss Battle", 57, 28.798);
}

public void PlaySigmaBossBatleOST()
{
PlayOST("Sigma Boss Battle", 55.348, 0.023);
}

public void PlayJediSigmaBatleOST()
{
PlayOST("Jedi Sigma Battle", 35.020, 17.339);
}

public void PlayWolfSigmaIntroIntroOST()
{
PlayOST("Wolf Sigma Intro");
}

public void PlayWolfSigmaBatleOST()
{
PlayOST("Boss Battle", 105.582, 52.020);
}

public void PlayVictorySound()
{
PlayOST("Boss Defeated");
Expand Down
2 changes: 1 addition & 1 deletion XSharp/Engine/Consts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,6 @@ public class Consts
public const string ROM_NAME = "ShittyDash.mmx";
public static readonly bool SKIP_MENU = false;
public static readonly bool SKIP_INTRO = false;
public const int INITIAL_LEVEL = 8;
public const int INITIAL_LEVEL = 12;
public const int INITIAL_CHECKPOINT = 0;
}
15 changes: 11 additions & 4 deletions XSharp/Engine/Entities/Enemies/Bosses/Sigma/JediSigma.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ public class JediSigma : Boss, IFSMEntity<JediSigmaState>
[Precache]
new internal static void Precache()
{
Engine.PrecacheSound("Sigma Stage", @"OST\X1\27 - Sigma Intro 2.mp3");
Engine.PrecacheSound("Sigma Boss Intro", @"OST\X1\05 - Sigma Intro 1.mp3");
Engine.PrecacheSound("Sigma Boss Battle", @"OST\X1\06 - Sigma Boss Battle.mp3");
Engine.PrecacheSound("Jedi Sigma Battle", @"OST\X1\28 - Sigma Battle.mp3");
Engine.PrecacheSound("Wolf Sigma Intro", @"OST\X1\29 - Stigma Defeated.mp3");
Engine.PrecacheSound("Wolf Sigma Battle", @"OST\X1\30 - Sigma Battle 2.mp3");

var palette = Engine.PrecachePalette("JediSigmaPalette", PALETTE);
var spriteSheet = Engine.CreateSpriteSheet("JediSigma", true, true);

Expand All @@ -114,13 +121,13 @@ public class JediSigma : Boss, IFSMEntity<JediSigmaState>
sequence.AddFrame(7, 7, 303, 15, 38, 60, 22);
sequence.AddFrame(15, 2, 357, 20, 50, 55, 20);
sequence.AddFrame(19, 2, 413, 20, 54, 55, 4);
sequence.AddFrame(30, 2, 473, 20, 58, 55, 4); // total of 78 frames
sequence.AddFrame(23, 2, 473, 20, 58, 55, 4); // total of 78 frames
sequence.AddFrame(40, 7, 537, 15, 75, 61, 1, true); // hp start to fill after 32 frames from here

sequence = spriteSheet.AddFrameSquence("Idle");
sequence.OriginOffset = -HITBOX.Origin - HITBOX.Mins;
sequence.Hitbox = HITBOX;
sequence.AddFrame(40, 8, 537, 15, 75, 61, 1, true);
sequence.AddFrame(40, 7, 537, 15, 75, 61, 1, true);

sequence = spriteSheet.AddFrameSquence("Defending");
sequence.OriginOffset = -HITBOX.Origin - HITBOX.Mins;
Expand All @@ -144,7 +151,7 @@ public class JediSigma : Boss, IFSMEntity<JediSigmaState>
sequence = spriteSheet.AddFrameSquence("Shooting");
sequence.OriginOffset = -HITBOX.Origin - HITBOX.Mins;
sequence.Hitbox = HITBOX;
sequence.AddFrame(40, 8, 537, 15, 75, 61, 32);
sequence.AddFrame(40, 7, 537, 15, 75, 61, 32);
sequence.AddFrame(39, 10, 618, 12, 75, 63, 4, true); // shot spawn here
sequence.AddFrame(40, 8, 699, 14, 75, 61, 8); // total of 44 frames, loop of 12 frames

Expand All @@ -158,7 +165,7 @@ public class JediSigma : Boss, IFSMEntity<JediSigmaState>
sequence.Hitbox = HITBOX;
sequence.AddFrame(39, 10, 618, 12, 75, 63, 4);
sequence.AddFrame(40, 7, 780, 15, 75, 60, 8);
sequence.AddFrame(40, 8, 537, 15, 75, 61, 12); // total of 24 frames
sequence.AddFrame(40, 7, 537, 15, 75, 61, 12); // total of 24 frames

sequence = spriteSheet.AddFrameSquence("Slashing");
sequence.OriginOffset = -HITBOX.Origin - HITBOX.Mins;
Expand Down
2 changes: 1 addition & 1 deletion XSharp/Engine/Sound/SoundStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public override int Read(byte[] buffer, int offset, int count)
while (totalBytesRead < count)
{
int bytesToRead = count - totalBytesRead;
if (source.Stream.Position + bytesToRead > StopPoint)
if (source.Stream.Position + bytesToRead >= StopPoint)
bytesToRead = (int) (StopPoint - source.Stream.Position);

if (bytesToRead < 0)
Expand Down
4 changes: 3 additions & 1 deletion XSharp/Engine/Sound/WaveStreamUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public static WaveStream FromFile(string path)

public static long TimeToBytePosition(WaveStream stream, double time)
{
return (long) (time * stream.WaveFormat.AverageBytesPerSecond);
var position = (long) (time * stream.WaveFormat.AverageBytesPerSecond);
position -= position % stream.WaveFormat.BlockAlign;
return position;
}
}
24 changes: 18 additions & 6 deletions XSharp/XSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,12 @@
<Content Include="Assets\Sounds\OST\X1\02 - Title Screen.mp3" />
<Content Include="Assets\Sounds\OST\X1\03 - Password Screen.mp3" />
<Content Include="Assets\Sounds\OST\X1\04 - Intro Stage.mp3" />
<Content Include="Assets\Sounds\OST\X1\05 - Sigma Intro 1.mp3" />
<Content Include="Assets\Sounds\OST\X1\06 - Sigma Boss Battle.mp3" />
<Content Include="Assets\Sounds\OST\X1\05 - Sigma Intro 1.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Assets\Sounds\OST\X1\06 - Sigma Boss Battle.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Assets\Sounds\OST\X1\07 - Zero 1.mp3" />
<Content Include="Assets\Sounds\OST\X1\08 - Zero 2.mp3" />
<Content Include="Assets\Sounds\OST\X1\09 - Stage Select 1.mp3" />
Expand Down Expand Up @@ -102,10 +106,18 @@
<Content Include="Assets\Sounds\OST\X1\24 - Sigma Fortress 1.mp3" />
<Content Include="Assets\Sounds\OST\X1\25 - Sigma Fortress 2.mp3" />
<Content Include="Assets\Sounds\OST\X1\26 - Sigma Fortress 3.mp3" />
<Content Include="Assets\Sounds\OST\X1\27 - Sigma Intro 2.mp3" />
<Content Include="Assets\Sounds\OST\X1\28 - Sigma Battle.mp3" />
<Content Include="Assets\Sounds\OST\X1\29 - Stigma Defeated.mp3" />
<Content Include="Assets\Sounds\OST\X1\30 - Sigma Battle 2.mp3" />
<Content Include="Assets\Sounds\OST\X1\27 - Sigma Intro 2.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Assets\Sounds\OST\X1\28 - Sigma Battle.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Assets\Sounds\OST\X1\29 - Stigma Defeated.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Assets\Sounds\OST\X1\30 - Sigma Battle 2.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Assets\Sounds\OST\X1\31 - Dr. Light.mp3" />
<Content Include="Assets\Sounds\OST\X1\32 - Ending.mp3" />
<Content Include="Assets\Sounds\OST\X1\33 - Castings.mp3" />
Expand Down
78 changes: 49 additions & 29 deletions XSharpShared/Serialization/BinarySerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ public bool Resolve()
if (reference.Factory == null)
return false;

if (reference is IIndexedFactoryItemReference indexed)
if (reference is IIndexedFactoryItemReference indexed && indexed.TargetIndex != -1)
reference = indexed.Factory.GetReferenceTo(indexed.TargetIndex);
else if (reference is INamedFactoryItemReference named)
else if (reference is INamedFactoryItemReference named && named.TargetName != null)
reference = named.Factory.GetReferenceTo(named.TargetName);
else
return false;
Expand Down Expand Up @@ -1216,31 +1216,41 @@ public override object ReadObject(bool acceptNonSerializable = false, bool ignor

obj = FormatterServices.GetUninitializedObject(objectType);

var eventNames = new HashSet<string>();

for (var type = objectType; type != null; type = type.BaseType)
{
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
foreach (var field in fields)
{
var attribute = Attribute.GetCustomAttribute(field, typeof(NotSerializableAttribute));
if (attribute != null)
continue;

string name = field.Name;
var fieldType = field.FieldType;
if (!fieldType.IsAssignableTo(typeof(MulticastDelegate)))
DeserializeField(field, type, obj);
}
eventNames.Clear();

var events = type.GetEvents(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
foreach (var eventInfo in events)
{
var field = type.GetField(eventInfo.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);

var attribute = Attribute.GetCustomAttribute(eventInfo, typeof(NotSerializableAttribute));
if (attribute != null)
continue;

var fieldName = field.Name;
eventNames.Add(fieldName);

DeserializeEvent(obj, eventInfo);
}

var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
foreach (var field in fields)
{
var attribute = Attribute.GetCustomAttribute(field, typeof(NotSerializableAttribute));
if (attribute != null)
continue;

string name = field.Name;
if (eventNames.Contains(name))
continue;

var fieldType = field.FieldType;
DeserializeField(field, type, obj);
}
}
}
}
Expand Down Expand Up @@ -1310,35 +1320,43 @@ public override void WriteObject(object obj, bool acceptNonSerializable = false,
if (!acceptNonSerializable && !objectType.Name.StartsWith("<>c__DisplayClass") && Attribute.GetCustomAttribute(objectType, typeof(SerializableAttribute)) == null)
throw new Exception($"Type '{objectType}' is not serializable. Use the attribute 'NotSerialize' if you dont want to serialize members of this type.");

var eventNames = new HashSet<string>();

for (var type = objectType; type != null; type = type.BaseType)
{
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
foreach (var field in fields)
{
var attribute = Attribute.GetCustomAttribute(field, typeof(NotSerializableAttribute));
if (attribute != null)
continue;

string name = field.Name;
var fieldType = field.FieldType;
if (!fieldType.IsAssignableTo(typeof(MulticastDelegate)))
{
object value = field.GetValue(obj);
WriteValue(fieldType, value);
}
}
eventNames.Clear();

var events = type.GetEvents(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
foreach (var eventInfo in events)
{
var field = type.GetField(eventInfo.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);

var attribute = Attribute.GetCustomAttribute(eventInfo, typeof(NotSerializableAttribute));
if (attribute != null)
continue;

var fieldName = field.Name;
eventNames.Add(fieldName);

var value = (MulticastDelegate) field.GetValue(obj);
SerializeEvent(value);
}

var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
foreach (var field in fields)
{
var attribute = Attribute.GetCustomAttribute(field, typeof(NotSerializableAttribute));
if (attribute != null)
continue;

string name = field.Name;
if (eventNames.Contains(name))
continue;

var fieldType = field.FieldType;
object value = field.GetValue(obj);
WriteValue(fieldType, value);
}
}
}
}
Expand Down Expand Up @@ -1592,8 +1610,10 @@ public void Resolve()
future.Resolve();

foreach (var future in futuresToResolve)
{
if (!future.IsResolved)
throw new Exception($"Can't resolve future {future}.");
}

foreach (var (array, indices, future) in arrayElementsToResolve)
array.SetValue(future.Value, indices);
Expand Down

0 comments on commit 5d676b1

Please sign in to comment.