Hello all,
I had yesterday a big problem with the World Editor. For whatever reason everything was duplicated. Maybe it was me, maybe a bug, I don't know. Anyway, it was to late to load my last saved work because I changed to much.
I was frustrate but than I said to myself: Chloe, calm down, you can code So I wrote a little command line tool for the new JSON-World format to remove duplicate objects. Also inside of groups. I didn't had many but if you work on complex structures it can happen that you duplicate a block by accident.
The usage is pretty straightforward:
ChloeCleanTheWorld.exe "c:\...\awesome.world"
The check routine does not considering material. So if you have two objects with the same size and position on top each other with different materials, one of them will be removed!
If you like to write your own version, here is the (quick and dirty) code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json;
namespace World
{
public interface IXHasChidren
{
List<XObject> objects { get; set; }
}
public class XRespawn
{
public int[] p { get; set; }
public double r { get; set; }
}
public class XObject : IXHasChidren
{
private string _tostring = null;
public string n { get; set; }
public int[] p { get; set; }
public int[] r { get; set; }
public int[] s { get; set; }
public int[] c { get; set; }
public string m { get; set; }
public List<XObject> objects { get; set; }
public override string ToString()
{
if (_tostring != null) return _tostring;
StringBuilder sb = new StringBuilder();
sb.Append("{");
sb.AppendFormat("n:{0}", n);
sb.Append(",");
if (n == "group")
{
sb.Append("objects:[");
bool first = true;
foreach(var obj in objects)
{
if (!first) sb.Append(",");
first = false;
sb.Append(obj.ToString());
}
sb.Append("]");
}
else
{
sb.AppendFormat("{0}:[{1},{2},{3}]", "p", p[0], p[1], p[2]);
if (r != null)
{
sb.Append(",");
sb.AppendFormat("{0}:[{1},{2},{3}]", "r", r[0], r[1], r[2]);
}
if (s != null)
{
sb.Append(",");
sb.AppendFormat("{0}:[{1},{2},{3}]", "s", s[0], s[1], s[2]);
}
if (c != null)
{
sb.Append(",");
sb.AppendFormat("{0}:[{1},{2},{3}]", "c", c[0], c[1], c[2]);
}
sb.Append("}");
}
sb.Append("}");
_tostring = sb.ToString();
return _tostring;
}
}
public class XDoc : IXHasChidren
{
public XRespawn respawn { get; set; }
public double oceanlevel { get; set; }
public string weather { get; set; }
public List<XObject> objects { get; set; }
}
class Program
{
static void RemoveDuplicates(IXHasChidren container)
{
List<XObject> uniqueObjects = new List<XObject>();
foreach (var objA in container.objects)
{
bool duplicate = false;
foreach (var objB in uniqueObjects)
{
if (objA != objB)
{
if (objA.ToString() == objB.ToString())
{
duplicate = true;
break;
}
}
}
if (!duplicate) uniqueObjects.Add(objA);
}
Console.WriteLine("{0} duplicate objects found.", container.objects.Count - uniqueObjects.Count);
container.objects = uniqueObjects;
}
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Please specify a filename :)");
return;
}
string fileName = args[0];
string json = File.ReadAllText(fileName);
XDoc doc = JsonConvert.DeserializeObject<XDoc>(json);
RemoveDuplicates(doc);
foreach (var objA in doc.objects)
{
if (objA.n == "group")
{
RemoveDuplicates(objA);
}
}
string cleanJson = JsonConvert.SerializeObject(
doc,
Formatting.None,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }
);
File.WriteAllText(fileName.Substring(0, fileName.Length - 6) + "_xxx_clean_xxx.world", cleanJson);
}
}
}
Have fun and take care!
Chloe
ChloeCleanTheWorld.zip
I have changed the code to do deep search of duplicate objects inside groups. Means more duplicate objects are now found
Please use the tool with care!
ChloeCleanTheWorld1_1.zip
SOURCE CODE:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json;
namespace World
{
public class XCollectedObject
{
public bool isgroup { get; set; }
public XObject obj { get; set; }
public IXHasChildren container { get; set; }
public string hash { get; set; }
}
public interface IXHasChildren
{
List<XObject> objects { get; set; }
}
public class XRespawn
{
public int[] p { get; set; }
public double r { get; set; }
}
public class XObject : IXHasChildren
{
public string n { get; set; }
public int[] p { get; set; }
public int[] r { get; set; }
public int[] s { get; set; }
public int[] c { get; set; }
public string m { get; set; }
public List<XObject> objects { get; set; }
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append("{");
sb.AppendFormat("n:{0}", n);
sb.Append(",");
if (n == "group")
{
sb.Append("objects:[");
bool first = true;
foreach(var obj in objects)
{
if (!first) sb.Append(",");
first = false;
sb.Append(obj.ToString());
}
sb.Append("]");
}
else
{
sb.AppendFormat("{0}:[{1},{2},{3}]", "p", p[0], p[1], p[2]);
if (r != null)
{
sb.Append(",");
sb.AppendFormat("{0}:[{1},{2},{3}]", "r", r[0], r[1], r[2]);
}
if (s != null)
{
sb.Append(",");
sb.AppendFormat("{0}:[{1},{2},{3}]", "s", s[0], s[1], s[2]);
}
if (c != null)
{
sb.Append(",");
sb.AppendFormat("{0}:[{1},{2},{3}]", "c", c[0], c[1], c[2]);
}
sb.Append("}");
}
sb.Append("}");
return sb.ToString();
}
}
public class XDoc : IXHasChildren
{
public XRespawn respawn { get; set; }
public double oceanlevel { get; set; }
public string weather { get; set; }
public List<XObject> objects { get; set; }
}
class Program
{
static void Collect(ref List<XCollectedObject> list, IXHasChildren container)
{
foreach (var obj in container.objects)
{
var c = new XCollectedObject()
{
isgroup = obj.n == "group",
obj = obj,
container = container,
hash = obj.ToString()
};
list.Add(c);
if (c.isgroup)
{
Collect(ref list, c.obj);
}
}
}
static void RemoveDuplicates(ref List<XCollectedObject> list)
{
List<XCollectedObject> unique = new List<XCollectedObject>();
foreach (var objA in list)
{
bool duplicate = false;
foreach (var objB in unique)
{
if (objA.hash == objB.hash)
{
// remove object from parent container
objA.container.objects.Remove(objA.obj);
duplicate = true;
break;
}
}
if (!duplicate) unique.Add(objA);
}
// find empty containers
foreach (var objA in list)
{
if (objA.isgroup)
{
if (objA.obj.objects.Count == 0)
{
objA.container.objects.Remove(objA.obj);
}
}
}
Console.WriteLine("{0} duplicate objects found.", list.Count - unique.Count);
}
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Please specify a filename :)");
return;
}
string fileName = args[0];
string json = File.ReadAllText(fileName);
XDoc doc = JsonConvert.DeserializeObject<XDoc>(json);
List<XCollectedObject> allObjects = new List<XCollectedObject>();
Collect(ref allObjects, doc);
RemoveDuplicates(ref allObjects);
string cleanJson = JsonConvert.SerializeObject(
doc,
Formatting.None,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }
);
File.WriteAllText(fileName.Substring(0, fileName.Length - 6) + "_xxx_clean_xxx.world", cleanJson);
}
}
}