新的 C#er 在这里。我正在制作基于控制台的 RPG。它进展顺利,但我需要找出如何保存游戏。我猜想有一种方法可以将我的应用程序中的变量保存到一个文本文件中,该文件可用于在应用程序再次运行时加载变量。不幸的是,我不知道从哪里开始。
此外,我需要一种方法在加载保存文件时转到代码中的某个点。
我的一些变量包括:
int xCoordinate, yCoordinate, hp, hpmax, level;
任何示例代码将不胜感激。
将一些变量写入文本文件很简单:
TextWriter tw = new StreamWriter("SavedGame.txt");
// write lines of text to the file
tw.WriteLine(xCoordinate);
tw.WriteLine(yCoordinate);
// close the stream
tw.Close();
并将它们读回:
// create reader & open file
TextReader tr = new StreamReader("SavedGame.txt");
// read lines of text
string xCoordString = tr.ReadLine();
string yCoordString = tr.ReadLine();
//Convert the strings to int
xCoordinate = Convert.ToInt32(xCoordString);
yCoordinate = Convert.ToInt32(yCoordString);
// close the stream
tr.Close();
您可以使用二进制序列化来相当容易地完成此操作。首先,创建一个包含您要编写的所有变量的类:
[Serializable]
class Data
{
int x;
int y;
}
然后按如下方式使用它:
Data data = new Data();
//Set variables inside data here...
// Save data
BinaryFormatter formatter = new BinaryFormatter();
using (FileStream stream = File.OpenWrite("C:\\Temp\\bin.bin"))
{
formatter.Serialize(stream, data);
}
我的变量保存脚本(隐藏、加密、可以编辑、更改、保存、删除)
public class SavingPlugin
{
public static void SaveVariable(string savename, TypeCode tc, object value,string Encryption_password)
{
string path = AppDomain.CurrentDomain.BaseDirectory + @"\" + savename + "." + tc.ToString();
if (!File.Exists(path))
{
var myfile = File.Create(path);
myfile.Close();
string val = value.ToString();
string encrypted = StringCipher.Encrypt(val, Encryption_password);
File.WriteAllText(path, encrypted);
File.SetAttributes(path, FileAttributes.Hidden);
}
else
{
string txt = "";
try
{
txt = StringCipher.Decrypt(File.ReadAllText(path), Encryption_password);
File.SetAttributes(path, FileAttributes.Normal);
string val = value.ToString();
string encrypted = StringCipher.Encrypt(val, Encryption_password);
File.WriteAllText(path, encrypted);
File.WriteAllText(path, encrypted);
File.SetAttributes(path, FileAttributes.Hidden);
}
catch
{
MessageBox.Show("Incorrect password : " + Encryption_password + " for the variable : " + savename + "." + tc.ToString());
}
}
}
public static object GetVariable(string savename, TypeCode tc, string Encryption_password)
{
string path = AppDomain.CurrentDomain.BaseDirectory + @"\" + savename + "." + tc.ToString();
File.SetAttributes(path, FileAttributes.Normal);
string txt = "";
try
{
txt = StringCipher.Decrypt(File.ReadAllText(path), Encryption_password);
File.SetAttributes(path, FileAttributes.Hidden);
var value = Convert.ChangeType(txt, tc);
return value;
}
catch
{
MessageBox.Show("Incorrect password : " + Encryption_password + " for the variable : " + savename + "." + tc.ToString());
return null;
}
}
public static void DeleteVariable(string savename,TypeCode tc)
{
string path = AppDomain.CurrentDomain.BaseDirectory + @"\" + savename + "." + tc.ToString();
File.SetAttributes(path,FileAttributes.Normal);
File.Delete(path);
}
public static bool Exists(string savename,TypeCode tc)
{
string path = AppDomain.CurrentDomain.BaseDirectory + @"\" + savename + "." + tc.ToString();
bool _true = true;
try
{
File.SetAttributes(path, FileAttributes.Normal);
File.SetAttributes(path, FileAttributes.Hidden);
}
catch
{
_true = false;
}
return _true;
}
}
public static class StringCipher
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 256;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
// Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
var cipherTextBytes = saltStringBytes;
cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
memoryStream.Close();
cryptoStream.Close();
return Convert.ToBase64String(cipherTextBytes);
}
}
}
}
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}
如何使用 :
SavingPlugin.SaveVariable("int16",TypeCode.Int16,15,"awwdad");
MessageBox.Show(SavingPlugin.GetVariable("int16", TypeCode.Int16,"awwdad").ToString());
您可以使用 SaveVariable 更改已经存在的变量的值,但您需要输入正确的密码