Terraria ModLoader  0.11.7.5
A mod to make and play Terraria mods
ItemIO.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using Terraria.ID;
5 using Terraria.ModLoader.Default;
7 
8 namespace Terraria.ModLoader.IO
9 {
10  public static class ItemIO
11  {
12  //replace netID writes in Terraria.Player.SavePlayer
13  //in Terraria.IO.WorldFile.SaveChests include IsModItem for no-item check
14  internal static void WriteVanillaID(Item item, BinaryWriter writer) {
15  writer.Write(item.modItem != null ? 0 : item.netID);
16  }
17 
18  public static TagCompound Save(Item item) {
19  var tag = new TagCompound();
20  if (item.type <= 0)
21  return tag;
22 
23  if (item.modItem == null) {
24  tag.Set("mod", "Terraria");
25  tag.Set("id", item.netID);
26  }
27  else {
28  tag.Set("mod", item.modItem.mod.Name);
29  tag.Set("name", item.modItem.Name);
30  tag.Set("data", item.modItem.Save());
31  }
32 
33  if (item.prefix != 0 && item.prefix < PrefixID.Count)
34  tag.Set("prefix", item.prefix);
35 
36  if (item.prefix >= PrefixID.Count) {
37  ModPrefix modPrefix = ModPrefix.GetPrefix(item.prefix);
38  if (modPrefix != null) {
39  tag.Set("modPrefixMod", modPrefix.mod.Name);
40  tag.Set("modPrefixName", modPrefix.Name);
41  }
42  }
43 
44  if (item.stack > 1)
45  tag.Set("stack", item.stack);
46 
47  if (item.favorited)
48  tag.Set("fav", true);
49 
50  tag.Set("globalData", SaveGlobals(item));
51 
52  return tag;
53  }
54 
55  public static void Load(Item item, TagCompound tag)
56  {
57  string modName = tag.GetString("mod");
58  if (modName == "") {
59  item.netDefaults(0);
60  return;
61  }
62 
63  if (modName == "Terraria") {
64  item.netDefaults(tag.GetInt("id"));
65  if (tag.ContainsKey("legacyData"))
66  LoadLegacyModData(item, tag.GetByteArray("legacyData"), tag.GetBool("hasGlobalSaving"));
67  }
68  else {
69  int type = ModLoader.GetMod(modName)?.ItemType(tag.GetString("name")) ?? 0;
70  if (type > 0) {
71  item.netDefaults(type);
72  if (tag.ContainsKey("legacyData"))
73  LoadLegacyModData(item, tag.GetByteArray("legacyData"), tag.GetBool("hasGlobalSaving"));
74  else
75  item.modItem.Load(tag.GetCompound("data"));
76  }
77  else {
78  item.netDefaults(ModContent.ItemType<MysteryItem>());
79  ((MysteryItem)item.modItem).Setup(tag);
80  }
81  }
82 
83  if (tag.ContainsKey("modPrefixMod") && tag.ContainsKey("modPrefixName")) {
84  string prefixMod = tag.GetString("modPrefixMod");
85  string prefixName = tag.GetString("modPrefixName");
86  item.Prefix(ModLoader.GetMod(prefixMod)?.PrefixType(prefixName) ?? 0);
87  }
88  else if (tag.ContainsKey("prefix")) {
89  item.Prefix(tag.GetByte("prefix"));
90  }
91  item.stack = tag.Get<int?>("stack") ?? 1;
92  item.favorited = tag.GetBool("fav");
93 
94  if (!(item.modItem is MysteryItem))
95  LoadGlobals(item, tag.GetList<TagCompound>("globalData"));
96  }
97 
98  public static Item Load(TagCompound tag) {
99  var item = new Item();
100  Load(item, tag);
101  return item;
102  }
103 
104  internal static List<TagCompound> SaveGlobals(Item item) {
105  if (item.modItem is MysteryItem)
106  return null; //MysteryItems cannot have global data
107 
108  var list = new List<TagCompound>();
109  foreach (var globalItem in ItemLoader.globalItems) {
110  var globalItemInstance = globalItem.Instance(item);
111  if (!globalItemInstance.NeedsSaving(item))
112  continue;
113 
114  list.Add(new TagCompound {
115  ["mod"] = globalItemInstance.mod.Name,
116  ["name"] = globalItemInstance.Name,
117  ["data"] = globalItemInstance.Save(item)
118  });
119  }
120  return list.Count > 0 ? list : null;
121  }
122 
123  internal static void LoadGlobals(Item item, IList<TagCompound> list) {
124  foreach (var tag in list) {
125  var mod = ModLoader.GetMod(tag.GetString("mod"));
126  var globalItem = mod?.GetGlobalItem(tag.GetString("name"));
127  if (globalItem != null) {
128  var globalItemInstance = globalItem.Instance(item);
129  try {
130  globalItemInstance.Load(item, tag.GetCompound("data"));
131  }
132  catch (Exception e) {
133  throw new CustomModDataException(mod,
134  "Error in reading custom player data for " + mod.Name, e);
135  }
136  }
137  else {
138  item.GetGlobalItem<MysteryGlobalItem>().data.Add(tag);
139  }
140  }
141  }
142 
143  public static void Send(Item item, BinaryWriter writer, bool writeStack = false, bool writeFavourite = false) {
144  writer.Write((short)item.netID);
145  writer.Write(item.prefix);
146  if (writeStack) writer.Write((short)item.stack);
147  if (writeFavourite) writer.Write(item.favorited);
148  SendModData(item, writer);
149  }
150 
151  public static void Receive(Item item, BinaryReader reader, bool readStack = false, bool readFavorite = false) {
152  item.netDefaults(reader.ReadInt16());
153  item.Prefix(reader.ReadByte());
154  if (readStack) item.stack = reader.ReadInt16();
155  if (readFavorite) item.favorited = reader.ReadBoolean();
156  ReceiveModData(item, reader);
157  }
158 
159  public static Item Receive(BinaryReader reader, bool readStack = false, bool readFavorite = false) {
160  var item = new Item();
161  Receive(item, reader, readStack, readFavorite);
162  return item;
163  }
164 
165  public static void SendModData(Item item, BinaryWriter writer) {
166  if (item.IsAir) return;
167  writer.SafeWrite(w => item.modItem?.NetSend(w));
168  foreach (var globalItem in ItemLoader.NetGlobals)
169  writer.SafeWrite(w => globalItem.Instance(item).NetSend(item, w));
170  }
171 
172  public static void ReceiveModData(Item item, BinaryReader reader) {
173  if (item.IsAir) return;
174  try {
175  reader.SafeRead(r => item.modItem?.NetRecieve(r));
176  }
177  catch (IOException) {
178  Logging.tML.Error($"Above IOException error caused by {item.modItem.Name} from the {item.modItem.mod.Name} mod.");
179  }
180 
181  foreach (var globalItem in ItemLoader.NetGlobals) {
182  try {
183  reader.SafeRead(r => globalItem.Instance(item).NetReceive(item, r));
184  }
185  catch (IOException) {
186  Logging.tML.Error($"Above IOException error caused by {globalItem.Name} from the {globalItem.mod.Name} mod while reading {item.Name}.");
187  }
188  }
189  }
190 
191  public static void LoadLegacy(Item item, BinaryReader reader, bool readStack = false, bool readFavorite = false) {
192  string modName = reader.ReadString();
193  bool hasGlobalSaving = false;
194  if (modName.Length == 0) {
195  hasGlobalSaving = true;
196  modName = reader.ReadString();
197  }
198  if (modName == "Terraria") {
199  item.netDefaults(reader.ReadInt32());
200  LoadLegacyModData(item, LegacyModData(item.type, reader, hasGlobalSaving), hasGlobalSaving);
201  }
202  else {
203  string itemName = reader.ReadString();
204  int type = ModLoader.GetMod(modName)?.ItemType(itemName) ?? 0;
205  byte[] data = LegacyModData(type == 0 ? int.MaxValue : type, reader, hasGlobalSaving);
206  if (type != 0) {
207  item.netDefaults(type);
208  LoadLegacyModData(item, data, hasGlobalSaving);
209  }
210  else {
211  item.netDefaults(ModContent.ItemType<MysteryItem>());
212  var tag = new TagCompound {
213  ["mod"] = modName,
214  ["name"] = itemName,
215  ["hasGlobalSaving"] = hasGlobalSaving,
216  ["legacyData"] = data
217  };
218  ((MysteryItem)item.modItem).Setup(tag);
219  }
220  }
221 
222  item.Prefix(reader.ReadByte());
223 
224  if (readStack)
225  item.stack = reader.ReadInt32();
226 
227  if (readFavorite)
228  item.favorited = reader.ReadBoolean();
229  }
230 
231  internal static byte[] LegacyModData(int type, BinaryReader reader, bool hasGlobalSaving = true) {
232  using (MemoryStream memoryStream = new MemoryStream()) {
233  using (BinaryWriter writer = new BinaryWriter(memoryStream)) {
234  if (type >= ItemID.Count) {
235  ushort length = reader.ReadUInt16();
236  writer.Write(length);
237  writer.Write(reader.ReadBytes(length));
238  }
239  if (hasGlobalSaving) {
240  ushort count = reader.ReadUInt16();
241  writer.Write(count);
242  for (int k = 0; k < count; k++) {
243  writer.Write(reader.ReadString());
244  writer.Write(reader.ReadString());
245  ushort length = reader.ReadUInt16();
246  writer.Write(length);
247  writer.Write(reader.ReadBytes(length));
248  }
249  }
250  }
251  return memoryStream.ToArray();
252  }
253  }
254 
255  internal static void LoadLegacyModData(Item item, byte[] data, bool hasGlobalSaving = true) {
256  using (BinaryReader reader = new BinaryReader(new MemoryStream(data))) {
257  if (item.modItem != null) {
258  byte[] modData = reader.ReadBytes(reader.ReadUInt16());
259  if (modData.Length > 0) {
260  using (BinaryReader customReader = new BinaryReader(new MemoryStream(modData))) {
261  try {
262  item.modItem.LoadLegacy(customReader);
263  }
264  catch (Exception e) {
265  throw new CustomModDataException(item.modItem.mod,
266  "Error in reading custom item data for " + item.modItem.mod.Name, e);
267  }
268  }
269  }
270  }
271  if (hasGlobalSaving) {
272  int count = reader.ReadUInt16();
273  for (int k = 0; k < count; k++) {
274  string modName = reader.ReadString();
275  string globalName = reader.ReadString();
276  byte[] globalData = reader.ReadBytes(reader.ReadUInt16());
277  GlobalItem globalItem = ModLoader.GetMod(modName)?.GetGlobalItem(globalName);
278  //could support legacy global data in mystery globals but eh...
279  if (globalItem != null && globalData.Length > 0) {
280  using (BinaryReader customReader = new BinaryReader(new MemoryStream(globalData))) {
281  try {
282  globalItem.LoadLegacy(item, customReader);
283  }
284  catch (Exception e) {
285  throw new CustomModDataException(globalItem.mod,
286  "Error in reading custom global item data for " + globalItem.mod.Name, e);
287  }
288  }
289  }
290  }
291  }
292  }
293  }
294 
295  public static void LoadLegacyInventory(Item[] inv, BinaryReader reader, bool readStack = false, bool readFavorite = false) {
296  int count = reader.ReadUInt16();
297  for (int k = 0; k < count; k++) {
298  LoadLegacy(inv[reader.ReadUInt16()], reader, readStack, readFavorite);
299  }
300  }
301 
302  public static string ToBase64(Item item) {
303  MemoryStream ms = new MemoryStream();
304  TagIO.ToStream(ItemIO.Save(item), ms, true);
305  return Convert.ToBase64String(ms.ToArray());
306  }
307 
308  public static Item FromBase64(string base64) {
309  MemoryStream ms = new MemoryStream(Convert.FromBase64String(base64));
310  return ItemIO.Load(TagIO.FromStream(ms, true));
311  }
312  }
313 }
static TagCompound FromStream(Stream stream, bool compressed=true)
Definition: TagIO.cs:292
virtual void LoadLegacy(Item item, BinaryReader reader)
Allows you to load pre-v0.9 custom data that you have saved for the given item.
Definition: GlobalItem.cs:911
static Item Load(TagCompound tag)
Definition: ItemIO.cs:98
int ItemType(string name)
Gets the internal ID / type of the ModItem corresponding to the name. Returns 0 if no ModItem with th...
static void LoadLegacyInventory(Item[] inv, BinaryReader reader, bool readStack=false, bool readFavorite=false)
Definition: ItemIO.cs:295
This serves as the central class which loads mods. It contains many static fields and methods related...
Definition: ModLoader.cs:28
Mod mod
The mod to which this GlobalItem belongs.
Definition: GlobalItem.cs:20
static ModPrefix GetPrefix(byte type)
Returns the ModPrefix associated with specified type If not a ModPrefix, returns null.
Definition: ModPrefix.cs:40
Manages content added by mods. Liasons between mod content and Terraria&#39;s arrays and oversees the Loa...
Definition: ModContent.cs:26
static void Load(Item item, TagCompound tag)
Definition: ItemIO.cs:55
This class allows you to modify and use hooks for all items, including vanilla items. Create an instance of an overriding class then call Mod.AddGlobalItem to use this.
Definition: GlobalItem.cs:15
static TagCompound Save(Item item)
Definition: ItemIO.cs:18
byte PrefixType(string name)
Gets the internal ID / type of the ModPrefix corresponding to the name. Returns 0 if no ModPrefix wit...
static void LoadLegacy(Item item, BinaryReader reader, bool readStack=false, bool readFavorite=false)
Definition: ItemIO.cs:191
This serves as the central class from which item-related functions are carried out. It also stores a list of mod items by ID.
Definition: ItemLoader.cs:21
static void SendModData(Item item, BinaryWriter writer)
Definition: ItemIO.cs:165
TagCompound GetCompound(string key)
static void Receive(Item item, BinaryReader reader, bool readStack=false, bool readFavorite=false)
Definition: ItemIO.cs:151
static void ReceiveModData(Item item, BinaryReader reader)
Definition: ItemIO.cs:172
static Item Receive(BinaryReader reader, bool readStack=false, bool readFavorite=false)
Definition: ItemIO.cs:159
static void Send(Item item, BinaryWriter writer, bool writeStack=false, bool writeFavourite=false)
Definition: ItemIO.cs:143
byte[] GetByteArray(string key)
static void ToStream(TagCompound root, Stream stream, bool compress=true)
Definition: TagIO.cs:316
GlobalItem GetGlobalItem(string name)
Gets the GlobalItem instance with the given name from this mod.
virtual string Name
Stores the name of the mod. This name serves as the mod&#39;s identification, and also helps with saving ...
Definition: Mod.cs:42
virtual void Load(Item item, TagCompound tag)
Allows you to load custom data that you have saved for the given item.
Definition: GlobalItem.cs:905
GlobalItem Instance(Item item)
static string ToBase64(Item item)
Definition: ItemIO.cs:302
static Item FromBase64(string base64)
Definition: ItemIO.cs:308
static Mod GetMod(string name)
Gets the instance of the Mod with the specified name.
Definition: ModLoader.cs:90