public IEnumerable <CommandChainEntry> EnumerateChain() { CommandChainEntry retVal = this; do { yield return(retVal); retVal = retVal.NextElement; } while (retVal != null); }
/// <summary> /// Saves a command block chain to a structure file at the given path. Does not attempt to modify it (e.g. for conditionals on turns). /// The file argument will be overwritten with a GZip-compressed NBT format structure file. /// </summary> /// <param name="chainStart">The beginning of the command block chain.</param> /// <param name="savePath">The path to the structure file where this command chain will be saved.</param> public void Save(CommandChainEntry chainStart, string savePath) { CommandChainEntry[] chain = chainStart.EnumerateChain().ToArray(); CommandBlockDirection dir = CommandBlockDirection.East; int rowFlat = 0; int height = 0; int columnFlat = 0; NbtFile file = new NbtFile(); file.RootTag = new NbtCompound("") { new NbtList("size") { // TODO calculate size dynamically new NbtInt(32), new NbtInt(32), new NbtInt(32) }, //new NbtList("entities") { }, new NbtList("palette") { }, new NbtList("blocks") { }, new NbtString("author", "MCCBL Compiler"), new NbtInt("version", 1) }; for (int i = 0; i < chain.Length; i++) { int state = -1; rowFlat = i / 32; columnFlat = i % 32; dir = rowFlat % 2 == 0 ? CommandBlockDirection.East : CommandBlockDirection.West; if (columnFlat == 31) { dir = height % 2 == 0 ? CommandBlockDirection.South : CommandBlockDirection.North; } //foreach (NbtCompound paletteE in ((NbtList)file.RootTag.Get("palette"))) //{ // if (paletteE == GetPaletteSignature(CommandBlockInfo.FromEnums(chain[i].Data, dir))) // { // alreadyInPalette = true; // break; // } // state++; //} NbtCompound palSig = GetPaletteSignature(CommandBlockInfo.FromEnums(chain[i].Data, dir)); var paletteList = file.RootTag.Get <NbtList>("palette"); // TODO does NbtCompound implement value equality? If not, we may have to use the general purpose IndexOf with our own comparison interface // Tested and does not // state = paletteList.IndexOf(palSig); for (int j = 0; j < paletteList.Count; j++) { NbtCompound curPal = paletteList[j] as NbtCompound; if (curPal == null) { continue; } if (AreCompoundsEqual(curPal, palSig)) { // We found an equivalent palette entry state = j; break; } } if (state == -1) { paletteList.Add(palSig); // TODO is this needed? // file.RootTag["palette"] = paletteList; state = paletteList.Count - 1; } NbtCompound block = new NbtCompound(); if (rowFlat % 2 == 0) { block.Add(new NbtList("pos") { new NbtInt(columnFlat), new NbtInt(height), new NbtInt(rowFlat) }); } else { block.Add(new NbtList("pos") { new NbtInt(31 - columnFlat), new NbtInt(height), new NbtInt(rowFlat) }); } block.Add(new NbtCompound("nbt") { new NbtByte("auto", Convert.ToByte(chain[i].Data.HasFlag(CommandBlockFlags.AlwaysOn))), new NbtString("Command", chain[i].Command), new NbtString("id", "Control"), new NbtString("CustomName", "@"), new NbtByte("TrackOutput", 0), new NbtByte("powered", 0), new NbtByte("conditionMet", 1), new NbtInt("SuccessCount", 0) }); block.Add(new NbtInt("state", state)); file.RootTag.Get <NbtList>("blocks").Add(block); } file.SaveToFile(savePath, NbtCompression.GZip); }
/// <summary> /// Preprocesses a command chain to work around turn-conditionals and other quirks that may occur in the underlying compilation. /// </summary> /// <param name="chain">The chain which will be preprocessed in place.</param> public void Preprocess(CommandChainEntry chain) { }