Skip to content

Commit

Permalink
Migrated to new framework. Now it's cross platform!
Browse files Browse the repository at this point in the history
Windows version uses net 5 and wpf. Linux/OSX uses netcore 3.1 and AvaloniaUI.
Items loaded wont have it's content scanned. Only the name.txt file. IP.BIN will be read on demmand. This way the contents from card will load a lot faster.
Menu is now created in GDI format.
Windows version still uses 7z. Linux/OSX uses native dot net zip.
Added 0GDTEXT image vizualization in Info screen.
Added detection of CodeBreaker.
Other small fixes and improvements.
  • Loading branch information
sonik-br committed Feb 12, 2021
1 parent e1f052e commit 0210528
Show file tree
Hide file tree
Showing 352 changed files with 53,526 additions and 2,105 deletions.
32 changes: 28 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
# GDMENU Card Manager
Manage content on SD Card for Dreamcast's GDEmu/GDMenu

For GDEMU to propperly work it's required to follow a pattern when putting files on the SD Card.<br/>
If not done correctly it will take a lot of time to boot and can even fail to.<br/>
This program will save the files the proper way so you console will boot super fast!

![Main window](docs/capture1.png)
![Info window](docs/capture2.png)


## Features
* Supports GDI and CDI files. Also compressed GDI inside zip/rar/7z
* Multi platform. Windows/Linux/OSX
* Supports GDI, CDI, MDS and CCD files. Also compressed files inside zip/rar/7z
* Add/delete/rename items
* Sort alphabetically
* Sort manually by drag and drop
* Automatically rename based on folder name, file name or internal name (IP.BIN)
* GDI Shrinking (from [gditools](https://sourceforge.net/projects/dcisotools/))
* Show cover image (0GDTEX.PVR)
* If using a CodeBreaker image it can detect if it's the correct one.
* Saves name.txt on each folder to keep compatibility with other managers.
* Menu is built in GDI format. Compatible with consoles that cant boot MIL-CD.
* GDI Shrinking. Can reduce file size by removing dummy data without reducing the quality.

### GDI Shrinking
Can reduce the size of the game but some games won't work propperly.
Expand All @@ -19,6 +30,19 @@ The program have a blacklist with some games known to have problems after shrink
By default the blacklist will be used and those games will not be shrinked.

### Limitations
Only works with GDI and CDI formats.
Linux version can't open rar and 7z files. Also it's not possible to use drag-and-drop.

**OSX version is untested as I don't have access to a mac**

### Credits
This software is made possible by using third party toosl:

GDmenu by neuroacid<br />
[GdiTools](https://sourceforge.net/projects/dcisotools/),
[GdiBuilder](/~https://github.com/Sappharad/GDIbuilder/),
[Aaru](/~https://github.com/aaru-dps/Aaru/),
[PuyoTools](/~https://github.com/nickworonekin/puyotools/),
[7-zip](https://www.7-zip.org/),
[SevenZipSharp](/~https://github.com/squid-box/SevenZipSharp/)

**Don't use it if you have games in CCD, MDS, etc.**
Special thanks to megavolt85 and everyone in the dreamcast scene
Binary file modified docs/capture1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/capture2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
138 changes: 138 additions & 0 deletions src/GDMENUCardManager.AvaloniaUI/AboutWindow.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<Window xmlns="/~https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:conv="clr-namespace:GDMENUCardManager.Converter"
mc:Ignorable="d" d:DesignWidth="760" d:DesignHeight="700"
x:Class="GDMENUCardManager.AboutWindow"
Title="About" Height="500" Width="700" CanResize="False"
WindowStartupLocation="CenterOwner">
<Window.Resources>
<Viewbox x:Key="ViewOpenInNew" Width="12" Height="12">
<Canvas Width="24" Height="24">
<Path Fill="Black" Data="M14,3V5H17.59L7.76,14.83L9.17,16.24L19,6.41V10H21V3M19,19H5V5H12V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19Z" />
</Canvas>
</Viewbox>
</Window.Resources>
<Grid Margin="10">
<StackPanel>
<TextBlock FontWeight="Bold">GD MENU Card Manager - by Sonik</TextBlock>
<TextBlock>Tool to manage games on SD card - For use with GDEMU/GDMENU</TextBlock>
<!--<Rectangle Fill="Black" Height="1"/>-->
<TextBlock Text=" "/>

<StackPanel Orientation="Horizontal">
<TextBlock>/~https://github.com/sonik-br/GDMENUCardManager/</TextBlock>
<Button Margin="5 0 0 0" ToolTip.Tip="Open Link" Padding="2" Background="Transparent" BorderBrush="Transparent" Click="ButtonLink_Click">
<ContentControl Content="{StaticResource ViewOpenInNew}"/>
</Button>
</StackPanel>
<TextBlock Text=" "/>
<TextBlock>Supported image formats: GDI, CDI, CCD and MDS</TextBlock>
<TextBlock>Supported compressed formats: ZIP</TextBlock>

<Rectangle Fill="Black" Height="1" Margin="0 10"/>

<!--<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="210"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
</Grid>-->

<StackPanel Orientation="Horizontal">
<TextBlock Width="210" FontWeight="Bold">Add items to list</TextBlock>
<TextBlock>
- Click on [+] button and select supported files
</TextBlock>
</StackPanel>

<Rectangle Fill="Black" Height="1" Margin="0 10"/>

<StackPanel Orientation="Horizontal">
<TextBlock Width="210" FontWeight="Bold">Remove items from list</TextBlock>
<TextBlock>
- Select items and click on [-] button&#x0a;- Or select items and press Delete key
</TextBlock>
</StackPanel>

<Rectangle Fill="Black" Height="1" Margin="0 10"/>

<StackPanel Orientation="Horizontal">
<TextBlock Width="210" FontWeight="Bold">Change list order</TextBlock>
<TextBlock>
- Select items and click on [up] or [down] button
</TextBlock>
</StackPanel>

<Rectangle Fill="Black" Height="1" Margin="0 10"/>

<StackPanel Orientation="Horizontal">
<TextBlock Width="210" FontWeight="Bold">Rename a single item</TextBlock>
<TextBlock>
- Double click on item name&#x0a;- Or right mouse button on item and select "Rename"&#x0a;- Or select item and press F2 key
</TextBlock>
</StackPanel>

<Rectangle Fill="Black" Height="1" Margin="0 10"/>

<StackPanel Orientation="Horizontal">
<TextBlock Width="210" FontWeight="Bold">Automatically rename item(s)</TextBlock>
<TextBlock>
- Select item(s) and right mouse button click then select "Automatically Rename"
</TextBlock>
</StackPanel>

<Rectangle Fill="Black" Height="1" Margin="0 10"/>

<StackPanel Orientation="Horizontal">
<TextBlock Width="210" FontWeight="Bold">Commit changes</TextBlock>
<TextBlock>
- Click on [Save Changes] button
</TextBlock>
</StackPanel>

<Rectangle Fill="Black" Height="1" Margin="0 10"/>

<WrapPanel Orientation="Horizontal">
<TextBlock FontWeight="Bold" Text="GDEMU"/>
<TextBlock Text=" - Deunan; "/>

<TextBlock FontWeight="Bold">GDmenu</TextBlock>
<TextBlock Text=" - neuroacid; "></TextBlock>

<!--<TextBlock FontWeight="Bold" Text="GdiShrink"/>
<TextBlock Text=" - FamilyGuy; "/>-->
<TextBlock FontWeight="Bold" Text="GdiBuilder"/>
<TextBlock Text=" - Paul Kratt; "/>

<TextBlock FontWeight="Bold" Text="Aaru"/>
<TextBlock Text=" - Natalia Portillo; "/>

<TextBlock FontWeight="Bold" Text="PuyoTools"/>
<TextBlock Text=" - Nick Woronekin; "/>
</WrapPanel>
<WrapPanel Orientation="Horizontal">
<!--<TextBlock FontWeight="Bold" Text="7z"/>
<TextBlock Text=" - Igor Pavlov; "/>
<TextBlock FontWeight="Bold" Text="SevenZipSharp"/>
<TextBlock Text=" - Joel Ahlgren; "/>-->
</WrapPanel>

</StackPanel>

<HeaderedContentControl Header="Version" Width="120" Height="80" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0 0 10 0">
<StackPanel>
<TextBlock Text="{Binding CurrentVersion, Mode=OneTime, StringFormat='Current: {0}'}"/>
<TextBlock Text="{Binding LatestVersion, Mode=OneWay, StringFormat='Latest: {0}'}"/>
<Button Click="ButtonVersion_Click">Check Online</Button>
</StackPanel>
</HeaderedContentControl>

</Grid>

</Window>
153 changes: 153 additions & 0 deletions src/GDMENUCardManager.AvaloniaUI/AboutWindow.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using MessageBox.Avalonia;
using MessageBox.Avalonia.Enums;
using MessageBox.Avalonia.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using GDMENUCardManager.Core.Interface;
using GDMENUCardManager.Core;
using System.Threading;
using System.Net.Http;
using System.Net;
using System.Text.Json;
using System.Runtime.InteropServices;
using Avalonia.Input;
using Avalonia.Platform;
using Avalonia.Media;

namespace GDMENUCardManager
{
public class AboutWindow : Window, INotifyPropertyChanged
{
public string CurrentVersion => Constants.Version;

private string _LatestVersion = "?";
public string LatestVersion
{
get { return _LatestVersion; }
set { _LatestVersion = value; RaisePropertyChanged(); }
}

private static HttpClient _Client = null;
private HttpClient Client
{
get
{
if (_Client == null)
{
_Client = new HttpClient();
_Client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github.v3+json");
_Client.DefaultRequestHeaders.UserAgent.ParseAdd(@"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0");
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
}
return _Client;
}
}

private readonly Queue<Key> lastKeys = new Queue<Key>(10);
private readonly Key[] konamiCodeKeys = new Key[] { Key.Up, Key.Up, Key.Down, Key.Down, Key.Left, Key.Right, Key.Left, Key.Right, Key.B, Key.A };

public event PropertyChangedEventHandler PropertyChanged;


public AboutWindow()
{
InitializeComponent();
#if DEBUG
//this.AttachDevTools();
//this.OpenDevTools();
#endif
this.KeyDown += AboutWindow_KeyDown;
DataContext = this;
}

private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}

private void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

private void AboutWindow_KeyDown(object sender, Avalonia.Input.KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
Close();
}
else
{
if (lastKeys.Count == 10)
lastKeys.Dequeue();
lastKeys.Enqueue(e.Key);
if (lastKeys.Count == 10 && lastKeys.SequenceEqual(konamiCodeKeys))
{
if (((Grid)Content).Children[0] is Image == false && Application.Current.TryFindResource("dreamcastLogoDrawingImage", out object img))
((Grid)Content).Children.Insert(0, new Image { Source = (DrawingImage)img });
Title = "Dreamcast Lives!";
lastKeys.Clear();
}
}
}

private void ButtonLink_Click(object sender, RoutedEventArgs e)
{
var url = @"/~https://github.com/sonik-br/GDMENUCardManager/";
try
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true });
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
Process.Start("xdg-open", url);
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
Process.Start("open", url);
}
catch { }
}

private async void ButtonVersion_Click(object sender, RoutedEventArgs e)
{
var btn = (Button)sender;
var oldContent = btn.Content;
btn.IsEnabled = false;
btn.Content = "Checking...";
try
{
var token = new CancellationTokenSource(10000).Token;//for time out
using (var response = await Client.GetAsync("https://api.github.com/repos/sonik-br/GDMENUCardManager/releases/latest", token))
{
response.EnsureSuccessStatusCode();
using (var stream = await response.Content.ReadAsStreamAsync())
{
var obj = await JsonDocument.ParseAsync(stream, cancellationToken: token);
LatestVersion = obj.RootElement.GetProperty("tag_name").GetString();
}
}
}
catch
{
LatestVersion = "Error";
}
finally
{
btn.IsEnabled = true;
btn.Content = oldContent;
}
}

}
}
Loading

0 comments on commit 0210528

Please sign in to comment.