public static bool save(string filename, ref OtbList items) { FileStream fileStream = new FileStream(filename, FileMode.Create); try { using (OtbLoader writer = new OtbLoader(fileStream)) { writer.writeUInt32(0, false); //version, always 0 writer.createNode(0); //root node writer.writeUInt32(0, true); //flags, unused for root node VERSIONINFO vi = new VERSIONINFO(); vi.dwMajorVersion = items.dwMajorVersion; vi.dwMinorVersion = items.dwMinorVersion; vi.dwBuildNumber = items.dwBuildNumber; vi.CSDVersion = String.Format("OTB {0}.{1}.{2}-{3}.{4}", vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber, items.clientVersion / 100, items.clientVersion % 100); MemoryStream ms = new MemoryStream(); BinaryWriter property = new BinaryWriter(ms); property.Write(vi.dwMajorVersion); property.Write(vi.dwMinorVersion); property.Write(vi.dwBuildNumber); byte[] CSDVersion = System.Text.Encoding.ASCII.GetBytes(vi.CSDVersion); Array.Resize(ref CSDVersion, 128); property.Write(CSDVersion); writer.writeProp(rootattrib_t.ROOT_ATTR_VERSION, property); foreach (OtbItem item in items) { List <itemattrib_t> saveAttributeList = new List <itemattrib_t>(); saveAttributeList.Add(itemattrib_t.ITEM_ATTR_SERVERID); if (item.type == ItemType.Deprecated) { //no other attributes should be saved for this type } else { saveAttributeList.Add(itemattrib_t.ITEM_ATTR_CLIENTID); saveAttributeList.Add(itemattrib_t.ITEM_ATTR_SPRITEHASH); if (item.minimapColor != 0) { saveAttributeList.Add(itemattrib_t.ITEM_ATTR_MINIMAPCOLOR); } if (item.maxReadWriteChars != 0) { saveAttributeList.Add(itemattrib_t.ITEM_ATTR_07); } if (item.maxReadChars != 0) { saveAttributeList.Add(itemattrib_t.ITEM_ATTR_08); } if (item.lightLevel != 0 || item.lightColor != 0) { saveAttributeList.Add(itemattrib_t.ITEM_ATTR_LIGHT2); } if (item.type == ItemType.Ground) { saveAttributeList.Add(itemattrib_t.ITEM_ATTR_SPEED); } if (item.alwaysOnTop) { saveAttributeList.Add(itemattrib_t.ITEM_ATTR_TOPORDER); } if (item.wareId != 0) { saveAttributeList.Add(itemattrib_t.ITEM_ATTR_WAREID); } if (!string.IsNullOrEmpty(item.name)) { saveAttributeList.Add(itemattrib_t.ITEM_ATTR_NAME); } } switch (item.type) { case ItemType.Container: writer.createNode((byte)itemgroup_t.ITEM_GROUP_CONTAINER); break; case ItemType.Fluid: writer.createNode((byte)itemgroup_t.ITEM_GROUP_FLUID); break; case ItemType.Ground: writer.createNode((byte)itemgroup_t.ITEM_GROUP_GROUND); break; case ItemType.Splash: writer.createNode((byte)itemgroup_t.ITEM_GROUP_SPLASH); break; case ItemType.Deprecated: writer.createNode((byte)itemgroup_t.ITEM_GROUP_DEPRECATED); break; default: writer.createNode((byte)itemgroup_t.ITEM_GROUP_NONE); break; } UInt32 flags = 0; if (item.blockObject) { flags |= (UInt32)itemflags_t.FLAG_BLOCK_SOLID; } if (item.blockProjectile) { flags |= (UInt32)itemflags_t.FLAG_BLOCK_PROJECTILE; } if (item.blockPathFind) { flags |= (UInt32)itemflags_t.FLAG_BLOCK_PATHFIND; } if (item.hasHeight) { flags |= (UInt32)itemflags_t.FLAG_HAS_HEIGHT; } if (item.hasUseWith) { flags |= (UInt32)itemflags_t.FLAG_USEABLE; } if (item.isPickupable) { flags |= (UInt32)itemflags_t.FLAG_PICKUPABLE; } if (item.isMoveable) { flags |= (UInt32)itemflags_t.FLAG_MOVEABLE; } if (item.isStackable) { flags |= (UInt32)itemflags_t.FLAG_STACKABLE; } if (item.alwaysOnTop) { flags |= (UInt32)itemflags_t.FLAG_ALWAYSONTOP; } if (item.isReadable) { flags |= (UInt32)itemflags_t.FLAG_READABLE; } if (item.isRotatable) { flags |= (UInt32)itemflags_t.FLAG_ROTABLE; } if (item.isHangable) { flags |= (UInt32)itemflags_t.FLAG_HANGABLE; } if (item.isVertical) { flags |= (UInt32)itemflags_t.FLAG_VERTICAL; } if (item.isHorizontal) { flags |= (UInt32)itemflags_t.FLAG_HORIZONTAL; } if (item.lookThrough) { flags |= (UInt32)itemflags_t.FLAG_LOOKTHROUGH; } if (item.allowDistRead) { flags |= (UInt32)itemflags_t.FLAG_ALLOWDISTREAD; } if (item.isAnimation) { flags |= (UInt32)itemflags_t.FLAG_ANIMATION; } if (item.walkStack) { flags |= (UInt32)itemflags_t.FLAG_WALKSTACK; } writer.writeUInt32(flags, true); foreach (itemattrib_t attribute in saveAttributeList) { switch (attribute) { case itemattrib_t.ITEM_ATTR_SERVERID: { property.Write((UInt16)item.id); writer.writeProp(itemattrib_t.ITEM_ATTR_SERVERID, property); break; } case itemattrib_t.ITEM_ATTR_WAREID: { property.Write((UInt16)item.wareId); writer.writeProp(itemattrib_t.ITEM_ATTR_WAREID, property); break; } case itemattrib_t.ITEM_ATTR_CLIENTID: { property.Write((UInt16)item.spriteId); writer.writeProp(itemattrib_t.ITEM_ATTR_CLIENTID, property); break; } case itemattrib_t.ITEM_ATTR_SPEED: { property.Write((UInt16)item.groundSpeed); writer.writeProp(itemattrib_t.ITEM_ATTR_SPEED, property); break; } case itemattrib_t.ITEM_ATTR_NAME: { for (UInt16 i = 0; i < item.name.Length; ++i) { property.Write((char)item.name[i]); } writer.writeProp(itemattrib_t.ITEM_ATTR_NAME, property); break; } case itemattrib_t.ITEM_ATTR_SPRITEHASH: { property.Write(item.spriteHash); writer.writeProp(itemattrib_t.ITEM_ATTR_SPRITEHASH, property); break; } case itemattrib_t.ITEM_ATTR_MINIMAPCOLOR: { property.Write((UInt16)item.minimapColor); writer.writeProp(itemattrib_t.ITEM_ATTR_MINIMAPCOLOR, property); break; } case itemattrib_t.ITEM_ATTR_07: { property.Write((UInt16)item.maxReadWriteChars); writer.writeProp(itemattrib_t.ITEM_ATTR_07, property); break; } case itemattrib_t.ITEM_ATTR_08: { property.Write((UInt16)item.maxReadChars); writer.writeProp(itemattrib_t.ITEM_ATTR_08, property); break; } case itemattrib_t.ITEM_ATTR_LIGHT2: { property.Write((UInt16)item.lightLevel); property.Write((UInt16)item.lightColor); writer.writeProp(itemattrib_t.ITEM_ATTR_LIGHT2, property); break; } case itemattrib_t.ITEM_ATTR_TOPORDER: { property.Write((byte)item.alwaysOnTopOrder); writer.writeProp(itemattrib_t.ITEM_ATTR_TOPORDER, property); break; } } } writer.closeNode(); } writer.closeNode(); } } finally { fileStream.Close(); } return(true); }
public static bool open(string filename, ref OtbList items, bool outputDebug) { FileStream fileStream = new FileStream(filename, FileMode.Open); try { using (OtbLoader reader = new OtbLoader(fileStream)) { //get root node BinaryReader nodeReader = reader.getRootNode(); if (nodeReader == null) { return(false); } nodeReader.ReadByte(); //first byte of otb is 0 nodeReader.ReadUInt32(); //4 bytes flags, unused byte attr = nodeReader.ReadByte(); if ((rootattrib_t)attr == rootattrib_t.ROOT_ATTR_VERSION) { UInt16 datalen = nodeReader.ReadUInt16(); if (datalen != 4 + 4 + 4 + 1 * 128) { //error = wxT("items.otb: Size of version header is invalid, updated .otb version?"); if (outputDebug) { Trace.WriteLine(String.Format("Size of version header is invalid.")); } return(false); } items.dwMajorVersion = nodeReader.ReadUInt32(); //major, file version items.dwMinorVersion = nodeReader.ReadUInt32(); //minor, client version items.dwBuildNumber = nodeReader.ReadUInt32(); //build number, revision nodeReader.BaseStream.Seek(128, SeekOrigin.Current); } nodeReader = reader.getChildNode(); if (nodeReader == null) { return(false); } do { OtbItem item = new OtbItem(); byte itemGroup = nodeReader.ReadByte(); if (outputDebug) { Trace.WriteLine(String.Format("Node:ItemGroup {0}", (itemgroup_t)itemGroup)); } switch ((itemgroup_t)itemGroup) { case itemgroup_t.ITEM_GROUP_NONE: item.type = ItemType.None; break; case itemgroup_t.ITEM_GROUP_GROUND: item.type = ItemType.Ground; break; case itemgroup_t.ITEM_GROUP_SPLASH: item.type = ItemType.Splash; break; case itemgroup_t.ITEM_GROUP_FLUID: item.type = ItemType.Fluid; break; case itemgroup_t.ITEM_GROUP_CONTAINER: item.type = ItemType.Container; break; case itemgroup_t.ITEM_GROUP_DEPRECATED: item.type = ItemType.Deprecated; break; default: break; } itemflags_t flags = (itemflags_t)nodeReader.ReadUInt32(); if (outputDebug) { Trace.WriteLine(String.Format("Node:flags {0}", flags)); } item.blockObject = ((flags & itemflags_t.FLAG_BLOCK_SOLID) == itemflags_t.FLAG_BLOCK_SOLID); item.blockProjectile = ((flags & itemflags_t.FLAG_BLOCK_PROJECTILE) == itemflags_t.FLAG_BLOCK_PROJECTILE); item.blockPathFind = ((flags & itemflags_t.FLAG_BLOCK_PATHFIND) == itemflags_t.FLAG_BLOCK_PATHFIND); item.isPickupable = ((flags & itemflags_t.FLAG_PICKUPABLE) == itemflags_t.FLAG_PICKUPABLE); item.isMoveable = ((flags & itemflags_t.FLAG_MOVEABLE) == itemflags_t.FLAG_MOVEABLE); item.isStackable = ((flags & itemflags_t.FLAG_STACKABLE) == itemflags_t.FLAG_STACKABLE); item.alwaysOnTop = ((flags & itemflags_t.FLAG_ALWAYSONTOP) == itemflags_t.FLAG_ALWAYSONTOP); item.isVertical = ((flags & itemflags_t.FLAG_VERTICAL) == itemflags_t.FLAG_VERTICAL); item.isHorizontal = ((flags & itemflags_t.FLAG_HORIZONTAL) == itemflags_t.FLAG_HORIZONTAL); item.isHangable = ((flags & itemflags_t.FLAG_HANGABLE) == itemflags_t.FLAG_HANGABLE); item.isRotatable = ((flags & itemflags_t.FLAG_ROTABLE) == itemflags_t.FLAG_ROTABLE); item.isReadable = ((flags & itemflags_t.FLAG_READABLE) == itemflags_t.FLAG_READABLE); item.hasUseWith = ((flags & itemflags_t.FLAG_USEABLE) == itemflags_t.FLAG_USEABLE); item.hasHeight = ((flags & itemflags_t.FLAG_HAS_HEIGHT) == itemflags_t.FLAG_HAS_HEIGHT); item.lookThrough = ((flags & itemflags_t.FLAG_LOOKTHROUGH) == itemflags_t.FLAG_LOOKTHROUGH); item.allowDistRead = ((flags & itemflags_t.FLAG_ALLOWDISTREAD) == itemflags_t.FLAG_ALLOWDISTREAD); item.isAnimation = ((flags & itemflags_t.FLAG_ANIMATION) == itemflags_t.FLAG_ANIMATION); item.walkStack = ((flags & itemflags_t.FLAG_WALKSTACK) == itemflags_t.FLAG_WALKSTACK); while (nodeReader.PeekChar() != -1) { byte attribute = nodeReader.ReadByte(); UInt16 datalen = nodeReader.ReadUInt16(); if (outputDebug) { Trace.WriteLine(String.Format("Node[{0}]:attribut {1}, size: {2}", reader.currentNodePos, ((itemattrib_t)attribute), datalen, reader.currentNodePos + nodeReader.BaseStream.Position)); } switch ((itemattrib_t)attribute) { case itemattrib_t.ITEM_ATTR_SERVERID: { if (datalen != sizeof(UInt16)) { if (outputDebug) { Trace.WriteLine(String.Format("Unexpected data length of server id block (Should be 2 bytes)")); } return(false); } item.id = nodeReader.ReadUInt16(); if (outputDebug) { System.Diagnostics.Debug.WriteLine(String.Format("Node:attribute:data {0}", item.id)); } } break; case itemattrib_t.ITEM_ATTR_CLIENTID: { if (datalen != sizeof(UInt16)) { if (outputDebug) { Trace.WriteLine(String.Format("Unexpected data length of client id block (Should be 2 bytes)")); } return(false); } item.spriteId = nodeReader.ReadUInt16(); if (outputDebug) { Trace.WriteLine(String.Format("Node:attribute:data {0}", item.spriteId)); } } break; case itemattrib_t.ITEM_ATTR_WAREID: { if (datalen != sizeof(UInt16)) { if (outputDebug) { Trace.WriteLine(String.Format("Unexpected data length of ware id block (Should be 2 bytes)")); } return(false); } item.wareId = nodeReader.ReadUInt16(); if (outputDebug) { Trace.WriteLine(String.Format("Node:attribute:data {0}", item.wareId)); } } break; case itemattrib_t.ITEM_ATTR_SPEED: { if (datalen != sizeof(UInt16)) { if (outputDebug) { Trace.WriteLine(String.Format("Unexpected data length of speed block (Should be 2 bytes)")); } return(false); } item.groundSpeed = nodeReader.ReadUInt16(); if (outputDebug) { Trace.WriteLine(String.Format("Node:attribute:data {0}", item.groundSpeed)); } } break; case itemattrib_t.ITEM_ATTR_NAME: { item.name = new string(nodeReader.ReadChars(datalen)); if (outputDebug) { Trace.WriteLine(String.Format("Node:attribute:data {0}", item.name)); } } break; case itemattrib_t.ITEM_ATTR_SPRITEHASH: { if (datalen != 16) { return(false); } item.spriteHash = nodeReader.ReadBytes(16); if (outputDebug) { Trace.WriteLine(String.Format("Node:attribute:data {0}", item.alwaysOnTopOrder)); } } break; case itemattrib_t.ITEM_ATTR_MINIMAPCOLOR: { if (datalen != 2) { return(false); } item.minimapColor = nodeReader.ReadUInt16(); if (outputDebug) { Trace.WriteLine(String.Format("Node:attribute:data {0}", item.minimapColor)); } } break; case itemattrib_t.ITEM_ATTR_07: { //read/write-able if (datalen != 2) { return(false); } item.maxReadWriteChars = nodeReader.ReadUInt16(); } break; case itemattrib_t.ITEM_ATTR_08: { //readable if (datalen != 2) { return(false); } item.maxReadChars = nodeReader.ReadUInt16(); } break; case itemattrib_t.ITEM_ATTR_LIGHT2: { if (datalen != sizeof(UInt16) * 2) { if (outputDebug) { Trace.WriteLine(String.Format("Unexpected data length of item light (2) block")); } return(false); } item.lightLevel = nodeReader.ReadUInt16(); item.lightColor = nodeReader.ReadUInt16(); if (outputDebug) { Trace.WriteLine(String.Format("Node:attribute:data {0}, {1}", item.lightLevel, item.lightColor)); } } break; case itemattrib_t.ITEM_ATTR_TOPORDER: { if (datalen != sizeof(byte)) { if (outputDebug) { Trace.WriteLine(String.Format("Unexpected data length of item toporder block (Should be 1 byte)")); } return(false); } item.alwaysOnTopOrder = nodeReader.ReadByte(); if (outputDebug) { Trace.WriteLine(String.Format("Node:attribute:data {0}", item.alwaysOnTopOrder)); } } break; default: { //skip unknown attributes nodeReader.BaseStream.Seek(datalen, SeekOrigin.Current); if (outputDebug) { Trace.WriteLine(String.Format("Skipped unknown attribute")); } } break; } } items.Add(item); nodeReader = reader.getNextNode(); } while (nodeReader != null); } } finally { fileStream.Close(); } return(true); }