Skip to content

Instantly share code, notes, and snippets.

@jasoncg
Last active August 11, 2018 18:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasoncg/e253f3ddc6488f378ccf13d91ca939d6 to your computer and use it in GitHub Desktop.
Save jasoncg/e253f3ddc6488f378ccf13d91ca939d6 to your computer and use it in GitHub Desktop.
MapMagic Voxeland Objects generator with absolute positioning
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MapMagic;
[System.Serializable]
[GeneratorMenu(menu = "MyGenerators", name = "Voxeland Objects", disengageable = true, priority = 10, helpLink = "https://gitlab.com/denispahunov/mapmagic/wikis/output_generators/Voxeland%20Objects")]
public class VoxelandObjectsOutput : OutputGenerator {
public enum Positioning {
Base,
RelativeHeight,
Absolute
}
public class Layer {
public int voxelandObjectIndex = -1;
public Input inputMask = new Input(InoutType.Map);
public Input input = new Input(InoutType.Objects);
//If set, then this will be the height of the output object
public Input heightInput = new Input(InoutType.Map);
public bool enabled = true;
public Positioning positioning = Positioning.RelativeHeight;
//public bool relativeHeight = true;
}
public Layer[] layers = new Layer[] { };
private int selected = -1;
public override IEnumerable<Input> Inputs () {
for(int i = 0; i < layers.Length; i++) {
if(layers[i] == null) layers[i] = new Layer();
yield return layers[i].input;
yield return layers[i].inputMask;
yield return layers[i].heightInput;
}
}
public float layer { get; set; }
#if VOXELAND
public static Voxeland5.Voxeland voxeland; //TODO static is not serialized
//TODO: somehow assign voxeland on data asssign or window open
#endif
public void TempLogSelected () { Debug.Log(selected); } //just to avoid warning
//get static actions using instance
public override MapMagic.Action<CoordRect, Chunk.Results, GeneratorsAsset, Chunk.Size, System.Func<float, bool>> GetProces () { return Process; }
public override System.Func<CoordRect, UnityEngine.Terrain, object, System.Func<float, bool>, IEnumerator> GetApply () { return Apply; }
public override System.Action<CoordRect, UnityEngine.Terrain> GetPurge () { return null; }
public static void Process (CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, System.Func<float, bool> stop = null) {
#if VOXELAND
if(stop != null && stop(0)) return;
if(voxeland == null) {
Debug.LogError("VoxelandObjectsOutput: voxeland not provided");
return;
}
//TODO get height factor
//int heightFactor = 200;
int heightFactor = (voxeland?.data?.generator != null ? voxeland.data.generator.heightFactor : 200);
lock(voxeland.data) {
//finding area by rect offset
Coord areaCoord = Coord.PickCell(rect.offset.x, rect.offset.z, voxeland.data.areaSize);
Voxeland5.Data.Area area = voxeland.data.areas[areaCoord.x, areaCoord.z];
//clearing objects
area.ClearObjects();
//preparing random
Noise noise = new Noise(12345); //to disable biome objects
//processing
foreach(VoxelandObjectsOutput gen in gens.GeneratorsOfType<VoxelandObjectsOutput>(onlyEnabled: true, checkBiomes: true)) {
//reading output directly
//Output output = gen.areaOutput;
if(stop != null && stop(0)) return; //checking stop before reading output
//if (!results.results.ContainsKey(output)) continue;
//Voxeland5.Data.Area genArea = (Voxeland5.Data.Area)results.results[output];
//loading biome matrix
Matrix biomeMask = null;
if(gen.biome != null) {
object biomeMaskObj = gen.biome.mask.GetObject(results);
if(biomeMaskObj == null) continue; //adding nothing if biome has no mask
biomeMask = (Matrix)biomeMaskObj;
if(biomeMask == null) continue;
if(biomeMask.IsEmpty()) continue; //optimizing empty biomes
}
//iterating layers
for(int l = 0; l < gen.layers.Length; l++) {
try {
Layer layer = gen.layers[l];
if(!layer.enabled) continue;
//loading inputs
Matrix srcMap = (Matrix)layer.inputMask.GetObject(results);
SpatialHash src = (SpatialHash)layer.input.GetObject(results);
if(src == null) continue;
foreach(SpatialObject obj in src.AllObjs()) {
int objX = (int)(obj.pos.x + 0.5f);
int objZ = (int)(obj.pos.y + 0.5f);
if(layer.positioning == Positioning.Absolute) {
if(srcMap?.array != null) {
try {
var result = srcMap[objX, objZ];
if(result == 0)
continue;
} catch(System.Exception e) {
Debug.LogException(e);
}
}
}
//biome masking
float biomeVal = 1;
if(gen.biome != null) {
if(biomeMask == null) biomeVal = 0;
else biomeVal = biomeMask[objX, objZ];
}
lock(noise)
if(biomeVal < noise.Random(objX, objZ))
continue;
//flooring
//Default to 0 (bottom of Voxeland)
float terrainHeight = 0;
Matrix heightSrc = layer.heightInput.GetObject(results) as Matrix;
switch(layer.positioning) {
case Positioning.Base:
terrainHeight = 0;
break;
case Positioning.RelativeHeight:
//If relative height is set, place on top of the heightmap
terrainHeight = results.heights[objX, objZ];
break;
case Positioning.Absolute:
if(heightSrc?.array != null) {
//Get the height from the height input matrix
terrainHeight = heightSrc[objX, objZ];
}
break;
default:
break;
}
int objHeight = (int)((obj.height + terrainHeight) * heightFactor + 0.5f);
//area.AddObject(new CoordDir(objX, objHeight, objZ), (short)l);
area.AddObject(objX, objHeight, objZ, 0, (short)layer.voxelandObjectIndex);
}
} catch(System.Exception e) {
Debug.LogException(e);
}
}
}
//pushing to apply
if(stop != null && stop(0)) return;
results.apply.CheckAdd(typeof(VoxelandOutput), null, replace: true);
}
#endif
}
public static void Purge (CoordRect rect, UnityEngine.Terrain terrain) {
}
public static IEnumerator Apply (CoordRect rect, UnityEngine.Terrain terrain, object dataBox, System.Func<float, bool> stop = null) {
yield return null;
}
private List<string> voxelandObjects = new List<string>();
public override void OnGUI (GeneratorsAsset gens) {
#if VOXELAND
//voxeland = MapMagic.instance.GetComponent("Voxeland");
//refreshing voxeland blocks information
if(voxeland == null) voxeland = GameObject.FindObjectOfType<Voxeland5.Voxeland>();
//creating layers
if(voxeland != null) {
voxelandObjects.Clear();
if(voxeland?.objectsTypes.array!=null)
foreach(var obj in voxeland.objectsTypes.array) {
voxelandObjects.Add(obj.name);
}
}
if(layers.Length == 0) {
layout.Par(32);
layout.Label("Voxeland terrain has no Object Block types", rect: layout.Inset(), helpbox: true);
}
//drawing layers
layout.Par(1); layout.Label("Temp", rect: layout.Inset()); //needed to reset label bold style
layout.margin = 10; layout.rightMargin = 10;
for(int i = layers.Length - 1; i >= 0; i--)
layout.DrawLayer(OnLayerGUI, ref selected, i);
layout.Par(3); layout.Par();
layout.DrawArrayAdd(ref layers, ref selected, layout.Inset(0.15f), reverse: true, createElement: () => new Layer());
layout.DrawArrayRemove(ref layers, ref selected, layout.Inset(0.15f), reverse: true);
layout.DrawArrayDown(ref layers, ref selected, layout.Inset(0.15f), dispUp: true);
layout.DrawArrayUp(ref layers, ref selected, layout.Inset(0.15f), dispDown: true);
layout.Par(5);
#endif
}
public void OnLayerGUI (Layout layout, bool selected, int num) {
#if VOXELAND
Layer layer = layers[num];
if(layer.voxelandObjectIndex<0) {
layer.voxelandObjectIndex = num;
}
layout.margin = 10; layout.rightMargin = 10;
layout.Par(2);
//name
layout.Par(19); layout.Inset(5);
layout.Toggle(ref layer.enabled, rect: layout.Inset(15));
layout.Label(voxeland.objectsTypes.array[layer.voxelandObjectIndex].name,
rect: layout.Inset(layout.field.width));
//input
layer.input.DrawIcon(layout, "", mandatory: false);
if(layer.positioning == Positioning.Absolute) {
layout.Par();
layer.inputMask.DrawIcon(layout, "Mask", mandatory: false);
layout.Par();
layer.heightInput.DrawIcon(layout, "Height", mandatory: false);
} else {
layer.inputMask.Unlink();
layer.heightInput.Unlink();
}
if(selected) {
layout.Par(); layout.Label("Object:", rect: layout.Inset(layout.field.width - 74));
layout.Par(); layer.voxelandObjectIndex = layout.Popup(layer.voxelandObjectIndex,
voxelandObjects.ToArray(),
rect: layout.Inset(layout.field.width - 74));
layout.Par();
layout.margin = 30;
layout.Field(ref layer.positioning, "Positioning");
layout.margin = 10;
}
#endif
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment