Init commit
This commit is contained in:
commit
18dcce592d
|
@ -0,0 +1,71 @@
|
|||
# 用户特定文件
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# 构建结果
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 缓存/选项目录
|
||||
.vs/
|
||||
|
||||
# MSTest 测试结果
|
||||
[Tt]est[Rr]esult*/
|
||||
|
||||
# .NET Core 项目
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
# NuGet 包
|
||||
*.nupkg
|
||||
**/packages/*
|
||||
!**/packages/build/
|
||||
|
||||
# Microsoft Azure 构建输出
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store 应用包目录和文件
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
|
||||
# Visual Studio 缓存文件
|
||||
*. [Cc]ache
|
||||
!?*. [Cc]ache/
|
||||
|
||||
# 其他
|
||||
ClientBin/
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# JetBrains Rider
|
||||
idea/
|
||||
*.sln.iml
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Visual Studio Code
|
||||
vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
|
@ -0,0 +1,16 @@
|
|||
<Application x:Class="MCI18n.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:MCI18n"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<!-- 引入自定义按钮样式 -->
|
||||
<ResourceDictionary Source="Theme/MCButtonStyle.xaml"/>
|
||||
<ResourceDictionary Source="Theme/MCTabTheme.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<local:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
|
@ -0,0 +1,14 @@
|
|||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Windows;
|
||||
|
||||
namespace MCI18n
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace MCI18n;
|
||||
|
||||
public class NullToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value != null ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DebugType>full</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DebugType>full</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="einformation_7new_mechanics.snbt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharpNBT\SharpNBT\SharpNBT.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36212.18
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MCI18n", "MCI18n.csproj", "{471DA248-800A-4E64-94FA-F7054AEA248F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpNBT", "..\SharpNBT\SharpNBT\SharpNBT.csproj", "{173F7856-B894-5F24-D410-91B18378A44B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{471DA248-800A-4E64-94FA-F7054AEA248F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{471DA248-800A-4E64-94FA-F7054AEA248F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{471DA248-800A-4E64-94FA-F7054AEA248F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{471DA248-800A-4E64-94FA-F7054AEA248F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{173F7856-B894-5F24-D410-91B18378A44B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{173F7856-B894-5F24-D410-91B18378A44B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{173F7856-B894-5F24-D410-91B18378A44B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{173F7856-B894-5F24-D410-91B18378A44B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {DF86C6F0-F56B-49DD-BF07-99777173117F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,60 @@
|
|||
<Window
|
||||
x:Class="MCI18n.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MCI18n"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="SNBT编辑器"
|
||||
Width="900"
|
||||
Height="600"
|
||||
Background="#3d3d3d"
|
||||
Foreground="White"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Window.DataContext>
|
||||
<local:MainWindowViewModel />
|
||||
</Window.DataContext>
|
||||
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Margin="10"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
Width="100"
|
||||
Height="30"
|
||||
Command="{Binding LoadQuestsCommand}"
|
||||
Content="打开文件夹"
|
||||
Style="{StaticResource MinecraftButtonStyle}" />
|
||||
<Button
|
||||
Width="100"
|
||||
Height="30"
|
||||
Command="{Binding SaveQuestAsCommand}"
|
||||
Content="另存为"
|
||||
Style="{StaticResource MinecraftButtonStyle}" />
|
||||
<Button
|
||||
Width="100"
|
||||
Height="30"
|
||||
Command="{Binding SaveQuestCommand}"
|
||||
Content="保存(覆盖)"
|
||||
Style="{StaticResource MinecraftButtonStyle}" />
|
||||
|
||||
</StackPanel>
|
||||
<TabControl Grid.Row="1">
|
||||
<TabItem Header="任务列表" />
|
||||
<TabItem Header="战利品列表" />
|
||||
</TabControl>
|
||||
<!-- 状态栏
|
||||
<StatusBar Grid.Row="2" Background="Transparent">
|
||||
<TextBlock Background="Transparent" Foreground="White" Text="{Binding CurrentFilePath, StringFormat={}当前文件: {0}, TargetNullValue=未打开任何文件}"/>
|
||||
</StatusBar>-->
|
||||
</Grid>
|
||||
</Window>
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
using MCI18n.Utilities;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MCI18n
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private MainWindowViewModel viewModel;
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.DataContext = viewModel = new MainWindowViewModel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using MCI18n.Utilities;
|
||||
using Microsoft.Win32;
|
||||
using SharpNBT;
|
||||
using SharpNBT.SNBT;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MCI18n
|
||||
{
|
||||
public partial class MainWindowViewModel : ObservableObject
|
||||
{
|
||||
|
||||
[ObservableProperty]
|
||||
private string _currentFilePath;
|
||||
|
||||
|
||||
[RelayCommand]
|
||||
private void LoadQuests()
|
||||
{
|
||||
var openFileDialog = new OpenFileDialog
|
||||
{
|
||||
Filter = "SNBT Files (*.snbt)|*.snbt|All Files (*.*)|*.*",
|
||||
Title = "选择SNBT文件"
|
||||
};
|
||||
|
||||
if (openFileDialog.ShowDialog() == true)
|
||||
{
|
||||
try
|
||||
{
|
||||
CurrentFilePath = openFileDialog.FileName;
|
||||
//var questData = SNBTParser.LoadFromFile<QuestData>(CurrentFilePath);
|
||||
var questData = StringNbt.Parse(File.ReadAllText(CurrentFilePath));
|
||||
//if (questData != null)
|
||||
//{
|
||||
// //QuestList = new ObservableCollection<QuestData> { questData };
|
||||
// //SelectedQuest = questData;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// //QuestList = new ObservableCollection<QuestData>();
|
||||
// //SelectedQuest = null;
|
||||
//}
|
||||
//var fileContent = File.ReadAllText(CurrentFilePath, Encoding.UTF8);
|
||||
//var parser = new NbtTagParser();
|
||||
//var snbtData = parser.Parse(fileContent);
|
||||
// var datas = SNBTParser.LoadFromFile(CurrentFilePath).Parse();
|
||||
|
||||
// 解析SNBT文件
|
||||
//var data = SNBTParser.ParseFile(CurrentFilePath);
|
||||
//NbtFile.Write(CurrentFilePath + ".r", questData, FormatOptions.None);
|
||||
//StringNbt.SaveToFile(questData, CurrentFilePath + ".r",prettyPrint:true);
|
||||
SnbtWriter.SaveToFile(questData, CurrentFilePath + ".r", prettyPrint: true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"加载文件失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SaveQuest()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SaveQuestAs()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CreateNewQuest()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Any CPU</Platform>
|
||||
<PublishDir>bin\Release\net8.0-windows\publish\win-x64\</PublishDir>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<SelfContained>false</SelfContained>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<PublishReadyToRun>false</PublishReadyToRun>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -0,0 +1,70 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Style TargetType="Button" x:Key="MinecraftButtonStyle">
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="Background" Value="#48494a"/>
|
||||
<Setter Property="BorderBrush" Value="#373737"/>
|
||||
<Setter Property="BorderThickness" Value="2"/>
|
||||
<Setter Property="FontFamily" Value="Segoe UI"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="Padding" Value="10,5"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Margin" Value="2"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border
|
||||
BorderBrush="Black"
|
||||
BorderThickness="2"
|
||||
>
|
||||
<Grid>
|
||||
<!-- 按钮底部阴影 -->
|
||||
<Border x:Name="ShadowBorder"
|
||||
Background="#313233"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- 按钮主体 -->
|
||||
<Border x:Name="MainBorder"
|
||||
Background="#5B5B5B"
|
||||
BorderBrush="#373737"
|
||||
BorderThickness="2,2,2,4"
|
||||
CornerRadius="0"
|
||||
Margin="0,0,0,0">
|
||||
|
||||
<ContentPresenter x:Name="ContentPresenter"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<!-- 鼠标悬停效果 -->
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="MainBorder" Property="Background" Value="#6B6B6B"/>
|
||||
<Setter TargetName="MainBorder" Property="BorderBrush" Value="#cccccc"/>
|
||||
</Trigger>
|
||||
|
||||
<!-- 点击效果 -->
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="MainBorder" Property="Margin" Value="0,2,0,0"/>
|
||||
<Setter TargetName="MainBorder" Property="BorderThickness" Value="2,2,2,2"/>
|
||||
<Setter TargetName="ShadowBorder" Property="Visibility" Value="Hidden"/>
|
||||
|
||||
</Trigger>
|
||||
|
||||
<!-- 禁用效果 -->
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="MainBorder" Property="Background" Value="#3F3F3F"/>
|
||||
<Setter TargetName="MainBorder" Property="BorderBrush" Value="#2A2A2A"/>
|
||||
<Setter Property="Foreground" Value="#909090"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
|
@ -0,0 +1,78 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Style TargetType="TabControl">
|
||||
<Setter Property="Background" Value="#48494a" />
|
||||
</Style>
|
||||
<Style TargetType="TabItem">
|
||||
<Setter Property="Background" Value="#48494a" />
|
||||
<Setter Property="Foreground" Value="#fff" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type TabItem}">
|
||||
|
||||
|
||||
<!--<Grid>
|
||||
<Border Background="{TemplateBinding Background}" BorderBrush="#373737" BorderThickness="2">
|
||||
<ContentPresenter x:Name="ContentSite"
|
||||
ContentSource="Header"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</Grid>-->
|
||||
<Border
|
||||
x:Name="OutBorder"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="1">
|
||||
<Grid>
|
||||
<!-- 按钮底部阴影 -->
|
||||
<Border
|
||||
x:Name="ShadowBorder"
|
||||
Background="#313233"
|
||||
CornerRadius="0" />
|
||||
|
||||
<!-- 按钮主体 -->
|
||||
<Border
|
||||
x:Name="MainBorder"
|
||||
Margin="0,0,0,0"
|
||||
Background="#5B5B5B"
|
||||
BorderBrush="#373737"
|
||||
BorderThickness="1,1,1,1"
|
||||
CornerRadius="0">
|
||||
|
||||
<ContentPresenter
|
||||
x:Name="ContentSite"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
ContentSource="Header" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<!-- 鼠标悬停效果 -->
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="MainBorder" Property="Background" Value="#6B6B6B" />
|
||||
<Setter TargetName="MainBorder" Property="BorderBrush" Value="#cccccc" />
|
||||
</Trigger>
|
||||
|
||||
<!-- 选中效果 -->
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter TargetName="MainBorder" Property="BorderThickness" Value="1,1,1,4" />
|
||||
<Setter TargetName="ShadowBorder" Property="Visibility" Value="Hidden" />
|
||||
<Setter TargetName="OutBorder" Property="BorderBrush" Value="#cccccc" />
|
||||
<Setter TargetName="OutBorder" Property="BorderThickness" Value="1,1,1,0" />
|
||||
|
||||
</Trigger>
|
||||
<!-- 禁用效果 -->
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="MainBorder" Property="Background" Value="#3F3F3F" />
|
||||
<Setter TargetName="MainBorder" Property="BorderBrush" Value="#2A2A2A" />
|
||||
<Setter Property="Foreground" Value="#909090" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
||||
</Style>
|
||||
</ResourceDictionary>
|
|
@ -0,0 +1,211 @@
|
|||
using SharpNBT;
|
||||
using SharpNBT.SNBT;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
|
||||
namespace MCI18n.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// 提供用于将CompoundTag保存为SNBT格式文件的工具方法
|
||||
/// </summary>
|
||||
public static class SnbtWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// 将CompoundTag保存为SNBT格式文件
|
||||
/// </summary>
|
||||
/// <param name="tag">要保存的CompoundTag</param>
|
||||
/// <param name="filePath">文件路径</param>
|
||||
/// <param name="prettyPrint">是否进行美化格式输出</param>
|
||||
/// <exception cref="ArgumentNullException">当tag为null时抛出</exception>
|
||||
/// <exception cref="IOException">写入文件失败时抛出</exception>
|
||||
public static void SaveToFile(CompoundTag tag, string filePath, bool prettyPrint = true)
|
||||
{
|
||||
if (tag == null)
|
||||
throw new ArgumentNullException(nameof(tag));
|
||||
|
||||
try
|
||||
{
|
||||
string snbt = ConvertToSnbt(tag, prettyPrint);
|
||||
File.WriteAllText(filePath, snbt, Encoding.UTF8);
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or DirectoryNotFoundException)
|
||||
{
|
||||
throw new IOException($"保存SNBT文件失败 '{filePath}': {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将CompoundTag转换为SNBT格式字符串
|
||||
/// </summary>
|
||||
/// <param name="tag">要转换的CompoundTag</param>
|
||||
/// <param name="prettyPrint">是否美化输出格式</param>
|
||||
/// <returns>SNBT格式字符串</returns>
|
||||
public static string ConvertToSnbt(CompoundTag tag, bool prettyPrint = true)
|
||||
{
|
||||
if (prettyPrint)
|
||||
return FormatCompound(tag, 0);
|
||||
else
|
||||
return tag.Stringify(true);
|
||||
}
|
||||
|
||||
private static string FormatCompound(CompoundTag tag, int indentLevel)
|
||||
{
|
||||
if (tag.Count == 0)
|
||||
return "{}";
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("{");
|
||||
|
||||
int i = 0;
|
||||
foreach (var child in tag)
|
||||
{
|
||||
sb.Append('\t', indentLevel + 1);
|
||||
sb.Append($"{EscapeName(child.Name)}: ");
|
||||
sb.Append(FormatTag(child, indentLevel + 1));
|
||||
|
||||
//if (i < tag.Count - 1)
|
||||
// sb.AppendLine(",");
|
||||
//else
|
||||
// sb.AppendLine();
|
||||
sb.AppendLine();
|
||||
i++;
|
||||
}
|
||||
|
||||
sb.Append('\t', indentLevel);
|
||||
sb.Append("}");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string FormatTag(Tag tag, int indentLevel)
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
case CompoundTag compoundTag:
|
||||
return FormatCompound(compoundTag, indentLevel);
|
||||
|
||||
case ListTag listTag:
|
||||
return FormatList(listTag, indentLevel);
|
||||
|
||||
case ByteArrayTag byteArrayTag:
|
||||
return FormatArray(byteArrayTag, 'B', 'b', indentLevel);
|
||||
|
||||
case IntArrayTag intArrayTag:
|
||||
return FormatArray(intArrayTag, 'I', null, indentLevel);
|
||||
|
||||
case LongArrayTag longArrayTag:
|
||||
return FormatArray(longArrayTag, 'L', 'L', indentLevel);
|
||||
|
||||
case StringTag stringTag:
|
||||
return $"\"{EscapeString(stringTag.Value)}\"";
|
||||
|
||||
case ByteTag byteTag:
|
||||
//return $"{byteTag.Value}b";
|
||||
return byteTag.Bool ? "true" : "false";
|
||||
|
||||
case ShortTag shortTag:
|
||||
return $"{shortTag.Value}s";
|
||||
|
||||
case IntTag intTag:
|
||||
return intTag.Value.ToString();
|
||||
|
||||
case LongTag longTag:
|
||||
return $"{longTag.Value}L";
|
||||
|
||||
case FloatTag floatTag:
|
||||
return $"{floatTag.Value.ToString("0.#####", CultureInfo.InvariantCulture)}f";
|
||||
|
||||
case DoubleTag doubleTag:
|
||||
return $"{doubleTag.Value.ToString("0.#####", CultureInfo.InvariantCulture)}d";
|
||||
|
||||
default:
|
||||
return tag.Stringify(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatList(ListTag listTag, int indentLevel)
|
||||
{
|
||||
if (listTag.Count == 0)
|
||||
return "[]";
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("[");
|
||||
|
||||
for (int i = 0; i < listTag.Count; i++)
|
||||
{
|
||||
sb.Append('\t', indentLevel + 1);
|
||||
sb.Append(FormatTag(listTag[i], indentLevel + 1));
|
||||
|
||||
//if (i < listTag.Count - 1)
|
||||
// sb.AppendLine(",");
|
||||
//else
|
||||
// sb.AppendLine();
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
sb.Append('\t', indentLevel);
|
||||
sb.Append("]");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string FormatArray<T>(ArrayTag<T> arrayTag, char prefix, char? suffix, int indentLevel)
|
||||
where T : unmanaged, INumber<T>
|
||||
{
|
||||
if (arrayTag.Count == 0)
|
||||
return $"[{prefix};]";
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append($"[{prefix};");
|
||||
|
||||
// 对于数组类型,我们通常不使用多行格式
|
||||
for (int i = 0; i < arrayTag.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
sb.AppendLine();
|
||||
//sb.Append("\r\n");
|
||||
|
||||
|
||||
sb.Append(arrayTag[i]);
|
||||
|
||||
if (suffix != null)
|
||||
sb.Append(suffix.Value);
|
||||
}
|
||||
|
||||
sb.Append("]");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string EscapeName(string name)
|
||||
{
|
||||
// 如果名称包含特殊字符,需要用引号括起来
|
||||
if (string.IsNullOrEmpty(name) || NeedsQuotes(name))
|
||||
return $"\"{EscapeString(name)}\"";
|
||||
return name;
|
||||
}
|
||||
|
||||
private static bool NeedsQuotes(string s)
|
||||
{
|
||||
foreach (char c in s)
|
||||
{
|
||||
if (!char.IsLetterOrDigit(c) && c != '_' && c != '-' && c != '.')
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string EscapeString(string str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return str;
|
||||
|
||||
return str.Replace("\\", "\\\\")
|
||||
.Replace("\"", "\\\"")
|
||||
.Replace("\n", "\\n")
|
||||
.Replace("\r", "\\r")
|
||||
.Replace("\t", "\\t");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue