-
-
Save jasoncg/e253f3ddc6488f378ccf13d91ca939d6 to your computer and use it in GitHub Desktop.
MapMagic Voxeland Objects generator with absolute positioning
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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