30 m_newWorldNames =
new ReadOnlyList<string>(text.Split([
'\n',
'\r'], StringSplitOptions.RemoveEmptyEntries));
36 throw new InvalidOperationException(
"Cannot import worlds in trial mode.");
40 UnpackWorld(unusedWorldDirectoryName, sourceStream,
true);
48 throw new InvalidOperationException(
"Cannot import world because it does not contain valid world data.");
50 return unusedWorldDirectoryName;
53 public static void ExportWorld(
string directoryName, Stream targetStream) {
54 PackWorld(directoryName, targetStream,
null,
true);
70 $
"Project file at \"{text}\" is corrupt or nonexistent. Will try copying data from the backup file. If that fails, will try making a recovery project file."
79 throw new InvalidOperationException(
"Recovery project file could not be generated because chunks file does not exist.");
84 Vector3 vector =
new(16 * cx, 255f, 16 * cz);
85 xElement?.Element(
"Subsystems")
97 catch (Exception ex) {
99 throw new InvalidOperationException(
"The world files are corrupt and could not be repaired.");
116 PackWorld(directoryName, targetStream, fn => Path.GetExtension(fn).ToLower() !=
".snapshot",
false);
140 if (worldInfo !=
null) {
147 if (
string.IsNullOrEmpty(name)
148 || name.Contains(
'\\')
149 || name.Contains(
'\n')
150 || name.Length > 128) {
157 WorldInfo worldInfo =
new() { DirectoryName = directoryName, LastSaveTime = DateTime.MinValue };
158 List<string> list =
new();
160 if (list.Count > 0) {
161 foreach (
string item
in list) {
164 worldInfo.LastSaveTime = fileLastWriteTime;
169 catch (Exception e2) {
185 foreach (XElement item2
in (from e
in GetPlayersNode(xElement).Elements()
191 XElement xElement2 = (from e in item2.Elements()
193 select e).FirstOrDefault();
194 if (xElement2 !=
null) {
203 catch (Exception e3) {
215 throw new InvalidOperationException($
"World name \"{worldSettings.Name}\" is invalid.");
221 else if (
string.IsNullOrEmpty(worldSettings.
Seed)) {
224 else if (worldSettings.
Seed ==
"0") {
230 string seed = worldSettings.
Seed;
231 foreach (
char c
in seed) {
232 worldSeed += c * num2;
237 worldSettings.
Save(valuesDictionary,
false);
238 valuesDictionary.SetValue(
"WorldDirectoryName", unusedWorldDirectoryName);
239 valuesDictionary.SetValue(
"WorldSeed", worldSeed);
247 XElement xElement =
new(
"Project");
252 XElement xElement2 =
new(
"Subsystems");
253 xElement.Add(xElement2);
254 XElement xElement3 =
new(
"Values");
256 valuesDictionary.
Save(xElement3);
257 xElement2.Add(xElement3);
258 XElement xElement4 =
new(
"Values");
260 valuesDictionary2.
Save(xElement4);
261 xElement2.Add(xElement4);
281 worldSettings.
Save(valuesDictionary,
true);
282 gameInfoNode.RemoveNodes();
283 valuesDictionary.
Save(gameInfoNode);
287 if (worldSettings.
GameMode != value) {
299 for (
int i = 0; i < 1000; i++) {
302 string text2 = $
"{arg}{(i > 0 ? i.ToString() : string.Empty)}{extension}";
308 throw new InvalidOperationException($
"Out of filenames for root \"{text}\".");
313 List<string> directories,
314 Func<string, bool> filesFilter) {
319 directories?.Add(text);
324 if (filesFilter ==
null
325 || filesFilter(text2)) {
331 catch (Exception ex) {
332 Log.
Error($
"Error enumerating files/directories. Reason: {ex.Message}");
337 XElement xElement = (from n in projectNode.Element(
"Subsystems")?.Elements(
"Values")
339 select n).FirstOrDefault();
340 if (xElement !=
null) {
343 throw new InvalidOperationException(
"GameInfo node not found in project.");
351 public static XElement
GetSubsystemNode(XElement projectNode,
string subsystemName,
bool throwOnError) {
352 XElement xElement = (from n in projectNode.Element(
"Subsystems")?.Elements(
"Values")
354 select n).FirstOrDefault();
355 if (xElement !=
null) {
359 throw new InvalidOperationException($
"{subsystemName} node not found in project.");
365 XElement xElement = (from n in projectNode.Element(
"Subsystems")?.Elements(
"Values")
367 select n).FirstOrDefault();
368 if (xElement !=
null) {
371 throw new InvalidOperationException(
"Players node not found in project.");
390 public static void PackWorld(
string directoryName, Stream targetStream, Func<string, bool> filter,
bool embedExternalContent) {
392 if (worldInfo ==
null) {
393 throw new InvalidOperationException(
"Directory does not contain a world.");
395 List<string> list =
new();
398 foreach (
string item
in list) {
401 fileName = fileName.StartsWith(
"Region") ?
Storage.
CombinePaths(
"Regions", fileName) : item.Replace($
"{directoryName}/",
"");
402 zipArchive.AddStream(fileName, source);
404 if (embedExternalContent) {
413 $
"{Storage.GetFileNameWithoutExtension(worldInfo.WorldSettings.BlocksTextureName)}.scbtex"
415 zipArchive.AddStream(filenameInZip, source2);
417 catch (Exception ex) {
418 Log.
Warning($
"Failed to embed blocks texture \"{worldInfo.WorldSettings.BlocksTextureName}\". Reason: {ex.Message}");
421 foreach (
PlayerInfo playerInfo
in worldInfo.PlayerInfos) {
430 $
"{Storage.GetFileNameWithoutExtension(playerInfo.CharacterSkinName)}.scskin"
432 zipArchive.AddStream(filenameInZip2, source3);
434 catch (Exception ex2) {
435 Log.
Warning($
"Failed to embed character skin \"{playerInfo.CharacterSkinName}\". Reason: {ex2.Message}");
442 public static void UnpackWorld(
string directoryName, Stream sourceStream,
bool importEmbeddedExternalContent) {
444 throw new InvalidOperationException($
"Cannot import world into \"{directoryName}\" because this directory does not exist.");
448 if (item.FileSize == 0) {
451 string text = item.FilenameInZip.Replace(
'\\',
'/');
453 if (text.StartsWith(
"EmbeddedContent")) {
455 if (importEmbeddedExternalContent) {
456 MemoryStream memoryStream =
new();
457 zipArchive.ExtractFile(item, memoryStream);
458 memoryStream.Position = 0L;
463 catch (Exception ex) {
464 Log.
Warning($
"Failed to import embedded content \"{text}\". Reason: {ex.Message}");
469 if (fileName.StartsWith(
"Region")) {
483 zipArchive.ExtractFile(item, stream);
489 List<string> list =
new();
490 List<string> list2 =
new();
492 foreach (
string item
in list) {
495 foreach (
string item2
in list2) {
503 public static bool TestXmlFile(
string fileName,
string rootNodeName) {
508 return xElement !=
null && xElement.Name == rootNodeName;
static void Error(object message)
static void Warning(object message)
static string ConvertToString(object value)
static void CreateDirectory(string path)
static bool DirectoryExists(string path)
static IEnumerable< string > ListDirectoryNames(string path)
static IEnumerable< string > ListFileNames(string path)
static Stream OpenFile(string path, OpenFileMode openFileMode)
static string GetExtension(string path)
static DateTime GetFileLastWriteTime(string path)
static bool FileExists(string path)
static string GetDirectoryName(string path)
static string GetFileNameWithoutExtension(string path)
static string GetFileName(string path)
static long GetFileSize(string path)
static void DeleteDirectory(string path)
static void DeleteFile(string path)
static string CombinePaths(params string[] paths)
static void CopyFile(string sourcePath, string destinationPath)
static bool IsBuiltIn(string name)
static string GetFileName(string name)
static string GetFileName(string name)
static bool IsBuiltIn(string name)
static object Get(Type type, string name)
static GameDatabase GameDatabase
static string MakeFullErrorMessage(Exception e)
static ExternalContentType ExtensionToType(string extension)
static string ImportExternalContentSync(Stream stream, ExternalContentType type, string name)
static void ReadTOCEntry(Stream stream, out int cx, out int cz, out int offset)
static string SerializationVersion
static void UpgradeProjectXml(XElement projectNode)
WorldSettings WorldSettings
List< PlayerInfo > PlayerInfos
void Save(ValuesDictionary valuesDictionary, bool liveModifiableParametersOnly)
void Load(ValuesDictionary valuesDictionary)
static List< WorldInfo > m_worldInfos
static void RestoreWorldFromSnapshot(string directoryName, string snapshotName)
static void UpdateWorldsList()
static Action< string > WorldDeleted
static ReadOnlyList< WorldInfo > WorldInfos
static void DeleteWorldContents(string directoryName, Func< string, bool > filter)
static void TakeWorldSnapshot(string directoryName, string snapshotName)
static bool TestXmlFile(string fileName, string rootNodeName)
static XElement GetProjectNode(WorldInfo worldInfo)
static XElement GetSubsystemNode(XElement projectNode, string subsystemName)
static string WorldsDirectoryName
static string MakeSnapshotFilename(string directoryName, string snapshotName)
static void UnpackWorld(string directoryName, Stream sourceStream, bool importEmbeddedExternalContent)
static void MakeQuickWorldBackup(string directoryName)
static XElement GetPlayersNode(XElement projectNode)
static void RepairWorldIfNeeded(string directoryName)
static string GetUnusedWorldDirectoryName()
static string ImportWorld(Stream sourceStream)
static bool SnapshotExists(string directoryName, string snapshotName)
static WorldInfo CreateWorld(WorldSettings worldSettings)
static bool ValidateWorldName(string name)
static XElement GetSubsystemNode(XElement projectNode, string subsystemName, bool throwOnError)
保证和旧引用的兼容性,这里不使用默认参数
static void ExportWorld(string directoryName, Stream targetStream)
static ReadOnlyList< string > NewWorldNames
static ReadOnlyList< string > m_newWorldNames
static void PackWorld(string directoryName, Stream targetStream, Func< string, bool > filter, bool embedExternalContent)
const int MaxAllowedWorlds
static WorldInfo GetWorldInfo(string directoryName)
static void DeleteWorldSnapshot(string directoryName, string snapshotName)
static void DeleteWorld(string directoryName)
static void ChangeWorld(string directoryName, WorldSettings worldSettings)
static void RecursiveEnumerateDirectory(string directoryName, List< string > files, List< string > directories, Func< string, bool > filesFilter)
static XElement GetGameInfoNode(XElement projectNode)
static ZipArchive Create(Stream stream, bool keepStreamOpen=false)
static ZipArchive Open(Stream stream, bool keepStreamOpen=false)
static string WorldsDirectoryName
static string APIVersionString
void ApplyOverrides(ValuesDictionary overridesValuesDictionary)
static void SetAttributeValue(XElement node, string attributeName, object value)
static object GetAttributeValue(XElement node, string attributeName, Type type)
static XElement LoadXmlFromStream(Stream stream, Encoding encoding, bool throwOnError)
static void SaveXmlToStream(XElement node, Stream stream, Encoding encoding, bool throwOnError)