Skip to content

Commit

Permalink
Merge pull request #1238 from VladiStep/psemChunkFix
Browse files Browse the repository at this point in the history
  • Loading branch information
Grossley authored Mar 25, 2023
2 parents 3d0fc23 + 211e92b commit 0caa16e
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 18 deletions.
2 changes: 1 addition & 1 deletion UndertaleModLib/Models/UndertaleEmbeddedTexture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public void SerializeBlob(UndertaleWriter writer)

if (writer.undertaleData.IsVersionAtLeast(2022, 3))
{
_textureBlockSize = texStartPos - writer.Position;
_textureBlockSize = writer.Position - texStartPos;
// Write the actual size of the texture block in
// the place of _textureBlockSize
var posBackup = writer.Position;
Expand Down
15 changes: 14 additions & 1 deletion UndertaleModLib/Models/UndertaleFont.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,17 @@ public class UndertaleFont : UndertaleNamedResource, IDisposable
public float ScaleY { get; set; }

/// <summary>
/// TODO: currently unknown, needs investigation. GMS2022.2 specific?
/// TODO: currently unknown, needs investigation. GM 2022.2 specific?
/// </summary>
public uint Ascender { get; set; }

/// <summary>
/// A spread value that's used for SDF rendering.
/// Introduced in GM 2023.2.
/// </summary>
/// <value><c>0</c> if SDF is disabled for this font.</value>
public uint SDFSpread { get; set; }

/// <summary>
/// The glyphs that this font uses.
/// </summary>
Expand Down Expand Up @@ -242,6 +249,8 @@ public void Serialize(UndertaleWriter writer)
writer.Write(AscenderOffset);
if (writer.undertaleData.IsVersionAtLeast(2022, 2))
writer.Write(Ascender);
if (writer.undertaleData.IsVersionAtLeast(2023, 2))
writer.Write(SDFSpread);
writer.WriteUndertaleObject(Glyphs);
}

Expand Down Expand Up @@ -274,6 +283,8 @@ public void Unserialize(UndertaleReader reader)
AscenderOffset = reader.ReadInt32();
if (reader.undertaleData.IsVersionAtLeast(2022, 2))
Ascender = reader.ReadUInt32();
if (reader.undertaleData.IsVersionAtLeast(2023, 2))
SDFSpread = reader.ReadUInt32();
Glyphs = reader.ReadUndertaleObject<UndertalePointerList<Glyph>>();
}

Expand All @@ -285,6 +296,8 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader)
skipSize += 4; // AscenderOffset
if (reader.undertaleData.IsVersionAtLeast(2022, 2))
skipSize += 4; // Ascender
if (reader.undertaleData.IsVersionAtLeast(2023, 2))
skipSize += 4; // SDFSpread

reader.Position += skipSize;

Expand Down
4 changes: 3 additions & 1 deletion UndertaleModLib/Models/UndertaleGeneralInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,9 @@ public static (uint, uint, uint, uint) TestForCommonGMSVersions(UndertaleReader
(uint Major, uint Minor, uint Release, uint Build) detectedVer = readVersion;

// Some GMS2+ version detection. The rest is spread around, mostly in UndertaleChunks.cs
if (reader.AllChunkNames.Contains("FEAT")) // 2022.8
if (reader.AllChunkNames.Contains("PSEM")) // 2023.2
detectedVer = (2023, 2, 0, 0);
else if (reader.AllChunkNames.Contains("FEAT")) // 2022.8
detectedVer = (2022, 8, 0, 0);
else if (reader.AllChunkNames.Contains("FEDS")) // 2.3.6
detectedVer = (2, 3, 6, 0);
Expand Down
47 changes: 47 additions & 0 deletions UndertaleModLib/Models/UndertaleRoom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1812,6 +1812,7 @@ public class LayerAssetsData : LayerData
public UndertalePointerList<SpriteInstance> Sprites { get; set; }
public UndertalePointerList<SequenceInstance> Sequences { get; set; }
public UndertalePointerList<SpriteInstance> NineSlices { get; set; } // Removed in 2.3.2, before never used
public UndertalePointerList<ParticleSystemInstance> ParticleSystems { get; set; }

/// <inheritdoc />
public void Serialize(UndertaleWriter writer)
Expand All @@ -1823,6 +1824,8 @@ public void Serialize(UndertaleWriter writer)
writer.WriteUndertaleObjectPointer(Sequences);
if (!writer.undertaleData.IsVersionAtLeast(2, 3, 2))
writer.WriteUndertaleObjectPointer(NineSlices);
if (writer.undertaleData.IsVersionAtLeast(2023, 2))
writer.WriteUndertaleObjectPointer(ParticleSystems);
}
writer.WriteUndertaleObject(LegacyTiles);
writer.WriteUndertaleObject(Sprites);
Expand All @@ -1831,6 +1834,8 @@ public void Serialize(UndertaleWriter writer)
writer.WriteUndertaleObject(Sequences);
if (!writer.undertaleData.IsVersionAtLeast(2, 3, 2))
writer.WriteUndertaleObject(NineSlices);
if (writer.undertaleData.IsVersionAtLeast(2023, 2))
writer.WriteUndertaleObject(ParticleSystems);
}
}

Expand All @@ -1844,6 +1849,8 @@ public void Unserialize(UndertaleReader reader)
Sequences = reader.ReadUndertaleObjectPointer<UndertalePointerList<SequenceInstance>>();
if (!reader.undertaleData.IsVersionAtLeast(2, 3, 2))
NineSlices = reader.ReadUndertaleObjectPointer<UndertalePointerList<SpriteInstance>>();
if (reader.undertaleData.IsVersionAtLeast(2023, 2))
ParticleSystems = reader.ReadUndertaleObjectPointer<UndertalePointerList<ParticleSystemInstance>>();
}
reader.ReadUndertaleObject(LegacyTiles);
reader.ReadUndertaleObject(Sprites);
Expand All @@ -1852,6 +1859,8 @@ public void Unserialize(UndertaleReader reader)
reader.ReadUndertaleObject(Sequences);
if (!reader.undertaleData.IsVersionAtLeast(2, 3, 2))
reader.ReadUndertaleObject(NineSlices);
if (reader.undertaleData.IsVersionAtLeast(2023, 2))
reader.ReadUndertaleObject(ParticleSystems);
}
}

Expand All @@ -1864,11 +1873,14 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader)
uint spritesPtr = reader.ReadUInt32();
uint sequencesPtr = 0;
uint nineSlicesPtr = 0;
uint partSystemsPtr = 0;
if (reader.undertaleData.IsVersionAtLeast(2, 3))
{
sequencesPtr = reader.ReadUInt32();
if (!reader.undertaleData.IsVersionAtLeast(2, 3, 2))
nineSlicesPtr = reader.ReadUInt32();
if (reader.undertaleData.IsVersionAtLeast(2023, 2))
partSystemsPtr = reader.ReadUInt32();
}

reader.AbsPosition = legacyTilesPtr;
Expand All @@ -1884,6 +1896,11 @@ public static uint UnserializeChildObjectCount(UndertaleReader reader)
reader.AbsPosition = nineSlicesPtr;
count += 1 + UndertalePointerList<SpriteInstance>.UnserializeChildObjectCount(reader);
}
if (reader.undertaleData.IsVersionAtLeast(2023, 2))
{
reader.AbsPosition = partSystemsPtr;
count += 1 + UndertalePointerList<ParticleSystemInstance>.UnserializeChildObjectCount(reader);
}
}

return count;
Expand Down Expand Up @@ -2196,6 +2213,36 @@ public void Dispose()
Name = null;
}
}

// It's not fully implemented yet
public class ParticleSystemInstance : UndertaleObject, INotifyPropertyChanged, IStaticChildObjCount, IStaticChildObjectsSize, IDisposable
{
/// <inheritdoc cref="IStaticChildObjCount.ChildObjectCount" />
public static readonly uint ChildObjectCount = 0;

/// <inheritdoc cref="IStaticChildObjectsSize.ChildObjectsSize" />
public static readonly uint ChildObjectsSize = 32;

public event PropertyChangedEventHandler PropertyChanged;

private byte[] rawData;

public void Serialize(UndertaleWriter writer)
{
writer.Write(rawData);
}

public void Unserialize(UndertaleReader reader)
{
rawData = reader.ReadBytes((int)ChildObjectsSize);
}

/// <inheritdoc/>
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
}

public enum AnimationSpeedType : uint
Expand Down
43 changes: 36 additions & 7 deletions UndertaleModLib/Models/UndertaleSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,12 @@ public void Serialize(UndertaleWriter writer)
case "GMColourTrack":
writer.WriteUndertaleObject(Keyframes as RealKeyframes);
break;
case "GMTextTrack": // Introduced in GM 2022.2
case "GMTextTrack": // Introduced in GM 2022.2
writer.WriteUndertaleObject(Keyframes as TextKeyframes);
break;
case "GMParticleTrack": // Introduced in GM 2023.2
writer.WriteUndertaleObject(Keyframes as ParticleKeyframes);
break;
}
}

Expand Down Expand Up @@ -408,12 +411,13 @@ UndertaleString ForceReadString()
case "GMColourTrack":
Keyframes = reader.ReadUndertaleObject<RealKeyframes>();
break;
case "GMTextTrack": // Introduced in GM 2022.2
case "GMTextTrack": // Introduced in GM 2022.2
Keyframes = reader.ReadUndertaleObject<TextKeyframes>();
break;
case "GMParticleTrack": // Introduced in GM 2023.2
Keyframes = reader.ReadUndertaleObject<ParticleKeyframes>();
break;

case "GMParticleTrack":
throw new NotImplementedException("GMParticleTrack not implemented, report this");
case "GMGroupTrack":
throw new NotImplementedException("GMGroupTrack not implemented, report this");
case "GMClipMaskTrack":
Expand Down Expand Up @@ -492,12 +496,13 @@ string ForceReadString()
case "GMColourTrack":
count += 1 + RealKeyframes.UnserializeChildObjectCount(reader);
break;
case "GMTextTrack": // Introduced in GM 2022.2
case "GMTextTrack": // Introduced in GM 2022.2
count += 1 + TextKeyframes.UnserializeChildObjectCount(reader);
break;
case "GMParticleTrack": // Introduced in GM 2023.2
count += 1 + ParticleKeyframes.UnserializeChildObjectCount(reader);
break;

case "GMParticleTrack":
throw new NotImplementedException("GMParticleTrack not implemented, report this");
case "GMGroupTrack":
throw new NotImplementedException("GMGroupTrack not implemented, report this");
case "GMClipMaskTrack":
Expand Down Expand Up @@ -918,4 +923,28 @@ public void Unserialize(UndertaleReader reader)
}
}
}

public class ParticleKeyframes : TrackKeyframes<ParticleKeyframes.Data>
{
// A temporary implementation, its type should be "ResourceData<UndertaleResourceById<...>>"
public class Data : UndertaleObject, IStaticChildObjectsSize
{
/// <inheritdoc cref="IStaticChildObjectsSize.ChildObjectsSize" />
public static readonly uint ChildObjectsSize = 4;

public int ParticleSystemIndex { get; set; }

/// <inheritdoc />
public void Serialize(UndertaleWriter writer)
{
writer.Write(ParticleSystemIndex);
}

/// <inheritdoc />
public void Unserialize(UndertaleReader reader)
{
ParticleSystemIndex = reader.ReadInt32();
}
}
}
}
16 changes: 16 additions & 0 deletions UndertaleModLib/UndertaleChunkTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -345,4 +345,20 @@ internal override void UnserializeChunk(UndertaleReader reader)

internal override uint UnserializeObjectCount(UndertaleReader reader) => 0;
}

public abstract class UndertaleUnsupportedChunk : UndertaleChunk
{
public byte[] RawData;
internal override void SerializeChunk(UndertaleWriter writer)
{
writer.Write(RawData);
}

internal override void UnserializeChunk(UndertaleReader reader)
{
RawData = reader.ReadBytes((int)Length);
}

internal override uint UnserializeObjectCount(UndertaleReader reader) => 0;
}
}
16 changes: 13 additions & 3 deletions UndertaleModLib/UndertaleChunks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1586,14 +1586,14 @@ internal override uint UnserializeObjectCount(UndertaleReader reader)
}
}

// GMS2022.8+ only
// GM2022.8+ only
public class UndertaleChunkFEAT : UndertaleSingleChunk<UndertaleFeatureFlags>
{
public override string Name => "FEAT";

internal override void SerializeChunk(UndertaleWriter writer)
{
if (writer.undertaleData.GeneralInfo.Major < 2)
if (!writer.undertaleData.IsGameMaker2())
throw new InvalidOperationException();

while (writer.Position % 4 != 0)
Expand All @@ -1604,7 +1604,7 @@ internal override void SerializeChunk(UndertaleWriter writer)

internal override void UnserializeChunk(UndertaleReader reader)
{
if (reader.undertaleData.GeneralInfo.Major < 2)
if (!reader.undertaleData.IsGameMaker2())
throw new InvalidOperationException();

// Padding
Expand All @@ -1628,4 +1628,14 @@ internal override uint UnserializeObjectCount(UndertaleReader reader)
return base.UnserializeObjectCount(reader);
}
}

// GM2023.2+ only
public class UndertaleChunkPSEM : UndertaleUnsupportedChunk
{
public override string Name => "PSEM";
}
public class UndertaleChunkPSYS : UndertaleUnsupportedChunk
{
public override string Name => "PSYS";
}
}
14 changes: 9 additions & 5 deletions UndertaleModTool/Editors/UndertaleFontEditor.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<TextBlock Grid.Row="0" Grid.Column="0" Margin="3">Name</TextBlock>
Expand Down Expand Up @@ -83,7 +84,10 @@
<TextBox Grid.Column="1" Margin="3" Text="{Binding ScaleY}"/>
</Grid>

<Viewbox Grid.Row="10" Grid.Column="1" Stretch="Uniform" StretchDirection="DownOnly">
<TextBlock Grid.Row="10" Grid.Column="0" Margin="3">SDF spread value</TextBlock>
<TextBox Grid.Row="10" Grid.Column="1" Margin="3" Text="{Binding SDFSpread}"/>

<Viewbox Grid.Row="11" Grid.Column="1" Stretch="Uniform" StretchDirection="DownOnly">
<Border>
<Border.Background>
<SolidColorBrush Color="Black"/>
Expand All @@ -92,8 +96,8 @@
</Border>
</Viewbox>

<TextBlock Grid.Row="11" Grid.Column="0" Margin="3,30,3,3">Glyphs:</TextBlock>
<local:DataGridDark Grid.Row="12" Grid.ColumnSpan="2" MaxHeight="370" Margin="3" x:Name="GlyphsGrid" ItemsSource="{Binding Glyphs, Mode=OneWay}"
<TextBlock Grid.Row="12" Grid.Column="0" Margin="3,30,3,3">Glyphs:</TextBlock>
<local:DataGridDark Grid.Row="13" Grid.ColumnSpan="2" MaxHeight="370" Margin="3" x:Name="GlyphsGrid" ItemsSource="{Binding Glyphs, Mode=OneWay}"
AutoGenerateColumns="False" CanUserAddRows="True" CanUserDeleteRows="True" HorizontalGridLinesBrush="LightGray" VerticalGridLinesBrush="LightGray" HeadersVisibility="Column" SelectionMode="Single" SelectionUnit="FullRow"
ScrollViewer.CanContentScroll="True"
VirtualizingPanel.IsVirtualizing="True"
Expand Down Expand Up @@ -166,10 +170,10 @@
</DataGrid.Columns>
</local:DataGridDark>

<TextBlock Grid.Row="13" Grid.Column="0" Grid.ColumnSpan="2" Margin="3" TextWrapping="Wrap" HorizontalAlignment="Center">
<TextBlock Grid.Row="14" Grid.Column="0" Grid.ColumnSpan="2" Margin="3" TextWrapping="Wrap" HorizontalAlignment="Center">
Note that the glyphs need to be specified in ascending order.<LineBreak/>
Press the button below to sort them appropriately.
</TextBlock>
<local:ButtonDark Grid.Row="14" Grid.Column="0" Grid.ColumnSpan="2" Margin="3" Click="Button_Sort_Click">Sort glyphs</local:ButtonDark>
<local:ButtonDark Grid.Row="15" Grid.Column="0" Grid.ColumnSpan="2" Margin="3" Click="Button_Sort_Click">Sort glyphs</local:ButtonDark>
</Grid>
</local:DataUserControl>
7 changes: 7 additions & 0 deletions UndertaleModTool/Editors/UndertaleRoomEditor.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@
</TextBlock.Text>
</TextBlock>
</DataTemplate>
<DataTemplate DataType="{x:Type undertale:UndertaleRoom+ParticleSystemInstance}">
<TextBlock Text="ParticleSystemInstance (unsupported)"
Foreground="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</DataTemplate>
</TreeView.Resources>

<TreeViewItem Header="{Binding Name.Content}" Name="RoomRootItem" IsExpanded="True">
Expand Down Expand Up @@ -236,6 +240,9 @@
</MultiBinding.Converter>
<Binding Path="AssetsData.LegacyTiles"/>
<Binding Path="AssetsData.Sprites"/>
<Binding Path="AssetsData.Sequences"/>
<Binding Path="AssetsData.NineSlices"/>
<Binding Path="AssetsData.ParticleSystems"/>
</MultiBinding>
</HierarchicalDataTemplate.ItemsSource>
<TextBlock Text="{Binding LayerName.Content, Mode=OneWay}" Style="{StaticResource LayerItemStyle}">
Expand Down
4 changes: 4 additions & 0 deletions UndertaleModTool/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,10 @@ private async Task LoadFile(string filename, bool preventClose = false)
this.ShowWarning("This game is set to run with the GameMaker Studio debugger and the normal runtime will simply hang after loading if the debugger is not running. You can turn this off in General Info by checking the \"Disable Debugger\" box and saving.", "GMS Debugger");
}
}
if (data.IsVersionAtLeast(2023, 2))
{
this.ShowWarning("The particle systems that were added in GM 2023.2 are not fully supported yet.");
}
if (Path.GetDirectoryName(FilePath) != Path.GetDirectoryName(filename))
CloseChildFiles();

Expand Down

0 comments on commit 0caa16e

Please sign in to comment.