tModLoader v0.11.8.9
A mod to make and play Terraria mods
ItemIO.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.IO;
4using Terraria.ID;
5using Terraria.ModLoader.Default;
7
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 e) {
179 Logging.tML.Error(e);
180 }
181
182 Logging.tML.Error($"Above IOException error caused by {item.modItem.Name} from the {item.modItem.mod.Name} mod.");
183 }
184
185 foreach (var globalItem in ItemLoader.NetGlobals) {
186 try {
187 reader.SafeRead(r => globalItem.Instance(item).NetReceive(item, r));
188 }
189 catch (IOException e) {
191 Logging.tML.Error(e);
192 }
193
194 Logging.tML.Error($"Above IOException error caused by {globalItem.Name} from the {globalItem.mod.Name} mod while reading {item.Name}.");
195 }
196 }
197 }
198
199 public static void LoadLegacy(Item item, BinaryReader reader, bool readStack = false, bool readFavorite = false) {
200 string modName = reader.ReadString();
201 bool hasGlobalSaving = false;
202 if (modName.Length == 0) {
203 hasGlobalSaving = true;
204 modName = reader.ReadString();
205 }
206 if (modName == "Terraria") {
207 item.netDefaults(reader.ReadInt32());
208 LoadLegacyModData(item, LegacyModData(item.type, reader, hasGlobalSaving), hasGlobalSaving);
209 }
210 else {
211 string itemName = reader.ReadString();
212 int type = ModLoader.GetMod(modName)?.ItemType(itemName) ?? 0;
213 byte[] data = LegacyModData(type == 0 ? int.MaxValue : type, reader, hasGlobalSaving);
214 if (type != 0) {
215 item.netDefaults(type);
216 LoadLegacyModData(item, data, hasGlobalSaving);
217 }
218 else {
219 item.netDefaults(ModContent.ItemType<MysteryItem>());
220 var tag = new TagCompound {
221 ["mod"] = modName,
222 ["name"] = itemName,
223 ["hasGlobalSaving"] = hasGlobalSaving,
224 ["legacyData"] = data
225 };
226 ((MysteryItem)item.modItem).Setup(tag);
227 }
228 }
229
230 item.Prefix(reader.ReadByte());
231
232 if (readStack)
233 item.stack = reader.ReadInt32();
234
235 if (readFavorite)
236 item.favorited = reader.ReadBoolean();
237 }
238
239 internal static byte[] LegacyModData(int type, BinaryReader reader, bool hasGlobalSaving = true) {
240 using (MemoryStream memoryStream = new MemoryStream()) {
241 using (BinaryWriter writer = new BinaryWriter(memoryStream)) {
242 if (type >= ItemID.Count) {
243 ushort length = reader.ReadUInt16();
244 writer.Write(length);
245 writer.Write(reader.ReadBytes(length));
246 }
247 if (hasGlobalSaving) {
248 ushort count = reader.ReadUInt16();
249 writer.Write(count);
250 for (int k = 0; k < count; k++) {
251 writer.Write(reader.ReadString());
252 writer.Write(reader.ReadString());
253 ushort length = reader.ReadUInt16();
254 writer.Write(length);
255 writer.Write(reader.ReadBytes(length));
256 }
257 }
258 }
259 return memoryStream.ToArray();
260 }
261 }
262
263 internal static void LoadLegacyModData(Item item, byte[] data, bool hasGlobalSaving = true) {
264 using (BinaryReader reader = new BinaryReader(new MemoryStream(data))) {
265 if (item.modItem != null) {
266 byte[] modData = reader.ReadBytes(reader.ReadUInt16());
267 if (modData.Length > 0) {
268 using (BinaryReader customReader = new BinaryReader(new MemoryStream(modData))) {
269 try {
270 item.modItem.LoadLegacy(customReader);
271 }
272 catch (Exception e) {
273 throw new CustomModDataException(item.modItem.mod,
274 "Error in reading custom item data for " + item.modItem.mod.Name, e);
275 }
276 }
277 }
278 }
279 if (hasGlobalSaving) {
280 int count = reader.ReadUInt16();
281 for (int k = 0; k < count; k++) {
282 string modName = reader.ReadString();
283 string globalName = reader.ReadString();
284 byte[] globalData = reader.ReadBytes(reader.ReadUInt16());
285 GlobalItem globalItem = ModLoader.GetMod(modName)?.GetGlobalItem(globalName);
286 //could support legacy global data in mystery globals but eh...
287 if (globalItem != null && globalData.Length > 0) {
288 using (BinaryReader customReader = new BinaryReader(new MemoryStream(globalData))) {
289 try {
290 globalItem.LoadLegacy(item, customReader);
291 }
292 catch (Exception e) {
293 throw new CustomModDataException(globalItem.mod,
294 "Error in reading custom global item data for " + globalItem.mod.Name, e);
295 }
296 }
297 }
298 }
299 }
300 }
301 }
302
303 public static void LoadLegacyInventory(Item[] inv, BinaryReader reader, bool readStack = false, bool readFavorite = false) {
304 int count = reader.ReadUInt16();
305 for (int k = 0; k < count; k++) {
306 LoadLegacy(inv[reader.ReadUInt16()], reader, readStack, readFavorite);
307 }
308 }
309
310 public static string ToBase64(Item item) {
311 MemoryStream ms = new MemoryStream();
312 TagIO.ToStream(ItemIO.Save(item), ms, true);
313 return Convert.ToBase64String(ms.ToArray());
314 }
315
316 public static Item FromBase64(string base64) {
317 MemoryStream ms = new MemoryStream(Convert.FromBase64String(base64));
318 return ItemIO.Load(TagIO.FromStream(ms, true));
319 }
320 }
321}
static readonly Framework Framework
This class allows you to modify and use hooks for all items, including vanilla items....
Definition: GlobalItem.cs:16
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
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
GlobalItem Instance(Item item)
Mod mod
The mod to which this GlobalItem belongs.
Definition: GlobalItem.cs:20
static void LoadLegacy(Item item, BinaryReader reader, bool readStack=false, bool readFavorite=false)
Definition: ItemIO.cs:199
static TagCompound Save(Item item)
Definition: ItemIO.cs:18
static void Receive(Item item, BinaryReader reader, bool readStack=false, bool readFavorite=false)
Definition: ItemIO.cs:151
static void Load(Item item, TagCompound tag)
Definition: ItemIO.cs:55
static Item Load(TagCompound tag)
Definition: ItemIO.cs:98
static string ToBase64(Item item)
Definition: ItemIO.cs:310
static void Send(Item item, BinaryWriter writer, bool writeStack=false, bool writeFavourite=false)
Definition: ItemIO.cs:143
static void LoadLegacyInventory(Item[] inv, BinaryReader reader, bool readStack=false, bool readFavorite=false)
Definition: ItemIO.cs:303
static void SendModData(Item item, BinaryWriter writer)
Definition: ItemIO.cs:165
static Item FromBase64(string base64)
Definition: ItemIO.cs:316
static Item Receive(BinaryReader reader, bool readStack=false, bool readFavorite=false)
Definition: ItemIO.cs:159
static void ReceiveModData(Item item, BinaryReader reader)
Definition: ItemIO.cs:172
byte[] GetByteArray(string key)
TagCompound GetCompound(string key)
static void ToStream(TagCompound root, Stream stream, bool compress=true)
Definition: TagIO.cs:316
static TagCompound FromStream(Stream stream, bool compressed=true)
Definition: TagIO.cs:292
This serves as the central class from which item-related functions are carried out....
Definition: ItemLoader.cs:22
Manages content added by mods. Liasons between mod content and Terraria's arrays and oversees the Loa...
Definition: ModContent.cs:27
byte PrefixType(string name)
Gets the internal ID / type of the ModPrefix corresponding to the name. Returns 0 if no ModPrefix wit...
GlobalItem GetGlobalItem(string name)
Gets the GlobalItem instance with the given name from this mod.
int ItemType(string name)
Gets the internal ID / type of the ModItem corresponding to the name. Returns 0 if no ModItem with th...
virtual string Name
Stores the name of the mod. This name serves as the mod's identification, and also helps with saving ...
Definition: Mod.cs:42
This serves as the central class which loads mods. It contains many static fields and methods related...
Definition: ModLoader.cs:29
static Mod GetMod(string name)
Gets the instance of the Mod with the specified name.
Definition: ModLoader.cs:90
static ModPrefix GetPrefix(byte type)
Returns the ModPrefix associated with specified type If not a ModPrefix, returns null.
Definition: ModPrefix.cs:40