Skip to content

Instantly share code, notes, and snippets.

@HolyFot
Last active Aug 23, 2020
Embed
What would you like to do?
Old Voxel Minecraft Cube System C# Unity
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using Ist;
using BeardedManStudios.Network;
public class CubeBuilding : MonoBehaviour
{
public enum DataTransferMode
{
SingleCopy,
ArrayCopy,
ReserveAndWrite,
}
public struct Range
{
public int begin;
public int end;
}
//RENDER SETTINGS
public int maxObjects = 65536;
public bool enableRendering = true;
public bool m_enable_rotation;
public bool m_enable_multithread = true;
public int m_task_block_size = 2048; //For multi-threading
[HideInInspector]
public int m_num_draw; //Only for Display
public DataTransferMode m_transfer_mode;
//LOD SETTINGS
public float lodDist0 = 0f;
public float lodDist1 = 5f;
public float lodDist2 = 10f;
public float lodDist3 = 20f;
public float lodHideDist = 30f;
public bool hideMaxLod = false;
public float extraRadius = 30f;
//Renderers for all Types
BatchRenderer[] m_rendererLod0;
BatchRenderer[] m_rendererLod1;
BatchRenderer[] m_rendererLod2;
BatchRenderer[] m_rendererLod3;
CubeType[] cubeTypes;
Transform[] cubeTypesTrans;
int cubeTypeCount = 0;
//Colliders
CubeCollider boxCols;
Transform boxColTrans;
//CUBE 2D ARRAYS
Vector3[,] m_instance_t; //Transform Pos
Quaternion[,] m_instance_r; //Rotation
Vector3[,] m_instance_s; //Scale
int[,] m_instance_ID; //Gobject ID
int[] cubeCounter; //# of cubes per Type
//Internal Vars
Transform camera;
float m_time;
int m_num_active_tasks;
GameObject parentBuilding;
public int buildingID;
//Bounds Vars
public float farthestNorth;
public float farthestSouth;
public float farthestEast;
public float farthestWest;
public float farthestTop;
public float farthestBottom;
public float boundWidth;
public float boundHeight;
public float boundDepth;
//Bound Center
public float localCenterX;
public float localCenterY;
public float localCenterZ;
Vector3 localCenterPos;
void Awake()
{
//Get Parent Building
parentBuilding = transform.parent.transform.gameObject;
//Get LOD Renderers & Init Arrays
enableRendering = false;
GetLODs();
//Get Boundry Height
boundHeight = m_rendererLod0[0].m_bounds_size.y;
//Get Collider Class
boxColTrans = transform.Find("Colliders");
boxCols = boxColTrans.GetComponent<CubeCollider>();
boxCols.InitColliderList();
//Get Camera
camera = GameObject.FindGameObjectWithTag("MainCamera").transform;
}
void GetLODs()
{
//Get Cube Types & Count
foreach (Transform child in transform)
{
if (child.name != "Colliders")
{
cubeTypeCount++;
}
}
//Initialize Arrays
m_rendererLod0 = new BatchRenderer[cubeTypeCount];
m_rendererLod1 = new BatchRenderer[cubeTypeCount];
m_rendererLod2 = new BatchRenderer[cubeTypeCount];
m_rendererLod3 = new BatchRenderer[cubeTypeCount];
cubeTypes = new CubeType[cubeTypeCount];
cubeTypesTrans = new Transform[cubeTypeCount];
cubeCounter = new int[cubeTypeCount];
//Get LODs & their CubeType
int currCounter = 0;
foreach (Transform child in transform)
{
if (child.name != "Colliders")
{
m_rendererLod0[currCounter] = child.Find("LOD0").GetComponent<BatchRenderer>();
m_rendererLod1[currCounter] = child.Find("LOD1").GetComponent<BatchRenderer>();
m_rendererLod2[currCounter] = child.Find("LOD2").GetComponent<BatchRenderer>();
m_rendererLod3[currCounter] = child.Find("LOD3").GetComponent<BatchRenderer>();
cubeTypes[currCounter] = child.GetComponent<CubeType>();
cubeTypesTrans[currCounter] = child;
cubeCounter[currCounter] = 0; //Start at 0
currCounter++;
}
}
//Debug.Log("[CubeBuilding] Found Cube Types: " + cubeTypeCount);
//Setup 2D Cube Arrays
int num = maxObjects;
m_instance_t = new Vector3[cubeTypeCount,maxObjects]; //Transform Pos
m_instance_r = new Quaternion[cubeTypeCount,maxObjects]; //Rotation
m_instance_s = new Vector3[cubeTypeCount,maxObjects]; //Scale
m_instance_ID = new int[cubeTypeCount,maxObjects]; //ID
}
public int AddNewCube(Vector3 pos, int type, Quaternion rot)
{
//Create New Index
cubeCounter[type]++;
int index = cubeCounter[type];
//Debug.Log("[CubeBuilding] Add New Cube: (type: " + type + ", index: " + index + ") X: " + pos.x + ", Y: " + pos.y + ", Z: " + pos.z);
//Quaternion rot2 = Quaternion.AngleAxis(45.0f, Vector3.forward);
Vector3 scale = new Vector3(1f, 1f, 1f);
m_instance_t[type, index] = pos;
m_instance_r[type, index] = rot;
m_instance_s[type, index] = scale;
m_instance_ID[type, index] = index;
//Add Collider
Vector3 boxPos = transform.InverseTransformPoint(pos);
if (cubeTypes[type].collisionType == 0) //Box Colliders
{
boxCols.AddBoxCollider(index, type, boxPos);
}
if (cubeTypes[type].collisionType == 1) //Mesh Colliders
{
boxCols.AddMeshCollider(index, type, boxPos, m_rendererLod3[type].m_mesh, cubeTypes[type].meshColliderScale, rot);
}
//Update Bounds
CheckFurthestCube(boxPos);
enableRendering = true;
//Save Cube
if (bl_Utilz.IsClientServer == 0)
{
BuildingHandler.SaveCubeToDB(pos, rot, type, index, buildingID);
}
return index;
}
//Add Cube with GobjectID
public void AddNewCubeWithGobjID(Vector3 pos, int gobjID, int type, Quaternion rot)
{
//Create New Index
cubeCounter[type]++;
int index = cubeCounter[type];
//Debug.Log("[CubeBuilding] Add New Cube: (type: " + type + ", index: " + index + ")");
Vector3 scale = new Vector3(1f, 1f, 1f);
m_instance_t[type, index] = pos;
m_instance_r[type, index] = rot;
m_instance_s[type, index] = scale;
m_instance_ID[type, index] = gobjID;
//Add Collider
Vector3 boxPos = transform.InverseTransformPoint(pos);
if (cubeTypes[type].collisionType == 0) //Box Colliders
{
boxCols.AddBoxCollider(index, type, boxPos);
}
if (cubeTypes[type].collisionType == 1) //Mesh Colliders
{
boxCols.AddMeshCollider(index, type, boxPos, m_rendererLod3[type].m_mesh, cubeTypes[type].meshColliderScale, rot);
}
//Update Bounds
CheckFurthestCube(boxPos);
enableRendering = true;
}
//Check Farthest Cube & Update Bounds
public void CheckFurthestCube(Vector3 pos)
{
if (pos.z > farthestNorth) //North
{
farthestNorth = pos.z;
}
if (pos.z < farthestSouth) //South
{
farthestSouth = pos.z;
}
if (pos.x > farthestEast) //East
{
farthestEast = pos.x;
}
if (pos.x < farthestWest) //West
{
farthestWest = pos.x;
}
if (pos.y > farthestTop) //Top
{
farthestTop = pos.y;
}
if (pos.y < farthestBottom) //Bottom
{
farthestBottom = pos.y;
}
//Get Center
localCenterX = (farthestWest + farthestEast) / 2;
localCenterY = (farthestTop + farthestBottom) / 6;
localCenterZ = (farthestSouth + farthestNorth) / 2;
localCenterPos = new Vector3(localCenterX, localCenterY, localCenterZ);
SetBuildingBoundCenter();
//Calculate Size
boundWidth = (farthestEast + Mathf.Abs(farthestWest)) + extraRadius;
boundHeight = (farthestTop + Mathf.Abs(farthestBottom)) + extraRadius;
boundDepth = (farthestNorth + Mathf.Abs(farthestSouth)) + extraRadius;
if (Mathf.Round(boundWidth) == 0) { boundWidth = 20f + extraRadius; }
if (Mathf.Round(boundHeight) == 0) { boundHeight = 20f + extraRadius; }
if (Mathf.Round(boundDepth) == 0) { boundDepth = 20f + extraRadius; }
//Use the Largest Width/Depth for both Width/Depth
if (boundWidth > boundDepth)
boundDepth = boundWidth;
if (boundDepth > boundWidth)
boundWidth = boundDepth;
//Set Bound Rendering Size
SetBuildingBoundSize();
//Update Building's Collider Size
parentBuilding.GetComponent<Building>().UpdateBuildingsBounds();
}
//Remove Cube by GobjID
public void RemoveCubeGobj(int gobjID, int type)
{
for (int i = 0; i <= cubeCounter[type]; ++i)
{
if (m_instance_ID[type,i] == gobjID)
{
//Replace with Last Object
if (i > 1)
{
m_instance_t[type, i] = m_instance_t[type, cubeCounter[type]];
m_instance_r[type, i] = m_instance_r[type, cubeCounter[type]];
m_instance_s[type, i] = m_instance_s[type, cubeCounter[type]];
m_instance_ID[type, i] = m_instance_ID[type, cubeCounter[type]];
}
//Clear Old Object
m_instance_t[type, cubeCounter[type]] = new Vector3();
m_instance_r[type, cubeCounter[type]] = new Quaternion();
m_instance_s[type, cubeCounter[type]] = new Vector3();
m_instance_ID[type, cubeCounter[type]] = 0;
//Decrease Counter
cubeCounter[type]--;
//Remove Collider
boxCols.RemoveColliderByID(gobjID, type);
//Delete from DB
if (bl_Utilz.IsClientServer == 0)
{
BuildingHandler.DeleteCubeFromDB(gobjID, buildingID, type);
}
return;
}
}
}
//Sets the Building's Rendering Size
public void SetBuildingBoundSize()
{
for (int i = 0; i < cubeTypeCount; ++i)
{
m_rendererLod0[i].m_bounds_size.x = boundWidth;
m_rendererLod0[i].m_bounds_size.y = boundHeight;
m_rendererLod0[i].m_bounds_size.z = boundDepth;
m_rendererLod1[i].m_bounds_size.x = boundWidth;
m_rendererLod1[i].m_bounds_size.y = boundHeight;
m_rendererLod1[i].m_bounds_size.z = boundDepth;
m_rendererLod2[i].m_bounds_size.x = boundWidth;
m_rendererLod2[i].m_bounds_size.y = boundHeight;
m_rendererLod2[i].m_bounds_size.z = boundDepth;
m_rendererLod3[i].m_bounds_size.x = boundWidth;
m_rendererLod3[i].m_bounds_size.y = boundHeight;
m_rendererLod3[i].m_bounds_size.z = boundDepth;
}
}
//Sets the Building's Center when Adjusting the Bounds
public void SetBuildingBoundCenter()
{
for (int i = 0; i < cubeTypeCount; ++i)
{
cubeTypesTrans[i].localPosition = localCenterPos;
}
}
void Update()
{
if (!enableRendering) //If Disabled Rendering
return;
for (int y = 0; y < cubeTypeCount; ++y)
{
if (cubeCounter[y] > 0)
{
m_num_draw = cubeCounter[y];
m_time = Time.realtimeSinceStartup;
Interlocked.Increment(ref m_num_active_tasks);
UpdateTask(new Range { begin = 0, end = cubeCounter[y]+1 }, y);
}
}
/*int num = m_num_draw;
if (m_enable_multithread)
{
for (int i = 0; i < num; i += m_task_block_size)
{
Interlocked.Increment(ref m_num_active_tasks);
ThreadPool.QueueUserWorkItem(
UpdateTask,
new Range { begin = i, end = Mathf.Min(i + m_task_block_size, cubeCounter) });
}
while (m_num_active_tasks != 0) { }
}
else
{
Interlocked.Increment(ref m_num_active_tasks);
UpdateTask(new Range { begin = 0, end = cubeCounter });
}*/
//Flush All the Cube Renderers
/*for (int i = 0; i < cubeTypeCount; ++i)
{
m_rendererLod0[i].Flush();
m_rendererLod1[i].Flush();
m_rendererLod2[i].Flush();
m_rendererLod3[i].Flush();
}*/
}
//Multi-Threaded Update Function
void UpdateTask(System.Object arg, int type)
{
Range r = (Range)arg;
float time = m_time;
switch (m_transfer_mode)
{
case DataTransferMode.SingleCopy:
DataTransfer_SingleCopy(r, type);
break;
//case DataTransferMode.ArrayCopy:
//DataTransfer_ArrayCopy(r);
//break;
//case DataTransferMode.ReserveAndWrite:
//DataTransfer_ReserveAndWrite(r);
//break;
}
Interlocked.Decrement(ref m_num_active_tasks);
}
//Buffer Copy Rendering
void DataTransfer_SingleCopy(Range r, int type)
{
//if (m_enable_rotation)
//{
for (int i = r.begin; i < r.end; ++i)
{
float dist = Vector3.Distance(m_instance_t[type,i], camera.position);
if (dist >= lodDist0 && dist < lodDist1) //LOD 0
m_rendererLod0[type].AddInstanceTR(m_instance_t[type, i], m_instance_r[type, i]);
else if (dist >= lodDist1 && dist < lodDist2) //LOD 1
m_rendererLod1[type].AddInstanceTR(m_instance_t[type, i], m_instance_r[type, i]);
else if (dist >= lodDist2 && dist < lodDist3) //LOD 2
m_rendererLod2[type].AddInstanceTR(m_instance_t[type, i], m_instance_r[type, i]);
else if (dist >= lodDist3) //LOD 3
m_rendererLod3[type].AddInstanceTR(m_instance_t[type, i], m_instance_r[type, i]);
}
/*}
else
{
for (int i = r.begin; i < r.end; ++i)
{
float dist = Vector3.Distance(m_instance_t[type,i], camera.position);
if (dist >= lodDist0 && dist < lodDist1) //LOD 0
m_rendererLod0[type].AddInstanceT(m_instance_t[type, i]);
else if (dist >= lodDist1 && dist < lodDist2) //LOD 1
m_rendererLod1[type].AddInstanceT(m_instance_t[type, i]);
else if (dist >= lodDist2 && dist < lodDist3) //LOD 2
m_rendererLod2[type].AddInstanceT(m_instance_t[type, i]);
else if (dist >= lodDist3) //LOD 3
m_rendererLod3[type].AddInstanceT(m_instance_t[type, i]);
}
}*/
}
//UTIL FUNCTIONS
public int GetTypeIdByTypeName(string typeName)
{
int result = -1;
for (int i = 0; i < cubeTypeCount; ++i)
{
if (cubeTypes[i].typeName == typeName)
return i;
}
return result;
}
public string GetTypeNameByTypeId(int typeId)
{
string result = "";
for (int i = 0; i < cubeTypeCount; ++i)
{
if (cubeTypes[i].typeID == typeId)
return cubeTypes[i].typeName;
}
return result;
}
public Quaternion GetCubeRotation(int typeID, int gobjID)
{
return m_instance_r[typeID, gobjID];
}
public Vector3 GetCubePosition(int typeID, int gobjID)
{
return m_instance_t[typeID, gobjID];
}
//Finds GobjID/Type by Collider
public void FindCubeGobjIdByCollider(Collider col1, out int gobjID, out int type1)
{
int tempGobjID;
int tempType;
boxCols.FindBoxIdByCollider(col1, out tempGobjID, out tempType);
gobjID = tempGobjID;
type1 = tempType;
}
//Gets Type# from GobjID
public int GetTypeByGobjID(int gobjID)
{
int result = -1;
for (int y = 0; y < cubeTypeCount; ++y)
{
for (int x = 0; x <= cubeCounter[y]; ++x)
{
if (m_instance_ID[y, x] == gobjID)
{
return y;
}
}
}
return result;
}
//Gets Type# from ItemID
public int GetTypeByItemID(int itemID)
{
int result = -1;
for (int i = 0; i < cubeTypeCount; ++i)
{
if (cubeTypes[i].itemID == itemID)
return i;
}
return result;
}
//NETWORKING
/*public void SendCubeListToClient(NetworkingPlayer player)
{
//Loop Sending Cubes in Packets by Type
for (int t = 0; t < cubeTypeCount; ++t)
{
int cubeCount = 1; //cubeCounter[t]
//Map CubeIDs, Positions & Rotations
for (int i = 1; i <= cubeCounter[t]; ++i)
{
//Map BuildingID & Type & Count
BMSByte packetData = new BMSByte();
packetData = ObjectMapper.MapBytes(packetData, buildingID, t, cubeCount);
Vector3 pos = m_instance_t[t, i];
Quaternion rot = m_instance_r[t, i];
int id = m_instance_ID[t, i];
packetData = ObjectMapper.MapBytes(packetData, id, pos.x, pos.y, pos.z, rot.x, rot.y, rot.z, rot.w);
//Send Packet
Networking.WriteCustom(GameOpcodes.PKT_LoadCubeList, Networking.PrimarySocket, packetData, player, true);
}
}
}
public void ReceiveCubeList(NetworkingPlayer sender, NetworkingStream stream)
{
//Read BuildingID & Type & Count
//int buildID = ObjectMapper.Map<int>(stream);
int type = ObjectMapper.Map<int>(stream);
int count = ObjectMapper.Map<int>(stream);
Debug.Log("Type: " + type + ", CubeCount: " + count);
//Loop Through Cubes & Add Them
for (int i = 0; i < count; ++i)
{
int gobjID = ObjectMapper.Map<int>(stream);
float x = ObjectMapper.Map<float>(stream);
float y = ObjectMapper.Map<float>(stream);
float z = ObjectMapper.Map<float>(stream);
Vector3 pos = new Vector3(x, y, z);
float qx = ObjectMapper.Map<float>(stream);
float qy = ObjectMapper.Map<float>(stream);
float qz = ObjectMapper.Map<float>(stream);
float qw = ObjectMapper.Map<float>(stream);
Quaternion rot = new Quaternion(qx, qy, qz, qw);
//Add Cube with ID Given from Server
AddNewCubeWithGobjID(pos, gobjID, type, rot);
Debug.Log("Add Cube ID: " + gobjID + "(x: " + pos.x + ", y: " + pos.y + ", z: " + pos.z + ")");
}
}
public void RequestCubeList(int buildingID)
{
Debug.Log("Sending Request for CubeList, BuildingID: " + buildingID);
BMSByte cachedData = new BMSByte();
cachedData = ObjectMapper.MapBytes(cachedData, buildingID);
Networking.WriteCustom(GameOpcodes.PKT_RequestCubeList, Networking.PrimarySocket, cachedData, true);
}*/
//NOT USED
/*
void CreateTestCubes()
{
//Create Test Cubes
Quaternion rot = Quaternion.AngleAxis(45.0f, Vector3.forward);
for (int i = 0; i < m_num_draw; ++i)
{
//Random Positions
Vector3 pos = new Vector3(0f, Random.Range(0f, 5f), 0.1f * (i % 256) - 12.8f);
float s = 1.0f + Mathf.Sin((float)i * 1f) * 5f;
Vector3 scale = new Vector3(s, s, s); //Random Scaling
AddNewCube(pos, 0, rot);
}
}
//Sets the Rotation of objects in the building
public void SetBuildingRotation(float angle)
{
rotationAngle = angle;
Quaternion rot = Quaternion.AngleAxis(rotationAngle, Vector3.forward);
//Change Cube Rotations
for (int y = 0; y < cubeTypeCount; ++y)
{
for (int x = 0; x < cubeCounter[y]; ++x)
{
m_instance_r[y, x] = rot;
}
}
boxColTrans.localRotation = rot;
}*/
/*void DataTransfer_ArrayCopy(Range r)
{
int num = r.end - r.begin;
if (m_renderer.m_enable_scale)
{
m_renderer.AddInstancesTRS(m_instance_t, m_instance_r, m_instance_s, r.begin, num);
}
else if (m_renderer.m_enable_rotation)
{
m_renderer.AddInstancesTR(m_instance_t, m_instance_r, r.begin, num);
}
else
{
m_renderer.AddInstancesT(m_instance_t, r.begin, num);
}
}
void DataTransfer_ReserveAndWrite(Range r)
{
int num = r.end - r.begin;
int reserved_index;
int reserved_num;
BatchRenderer.InstanceData data = m_renderer.ReserveInstance(num, out reserved_index, out reserved_num);
System.Array.Copy(m_instance_t, r.begin, data.translation, reserved_index, reserved_num);
System.Array.Copy(m_instance_r, r.begin, data.rotation, reserved_index, reserved_num);
System.Array.Copy(m_instance_s, r.begin, data.scale, reserved_index, reserved_num);
}*/
}
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
public class CubeCollider : MonoBehaviour
{
public List<CustomCollider> colliders;
public int colliderCounter;
GameObject meshCols;
public void InitColliderList()
{
colliders = new List<CustomCollider>();
meshCols = transform.Find("MeshColliders").gameObject;
}
public void AddBoxCollider(int id, int type1, Vector3 pos)
{
//Add a Collider
BoxCollider boxCol = transform.gameObject.AddComponent(typeof(BoxCollider)) as BoxCollider;
boxCol.size = new Vector3(1f, 1f, 1f); //Scale
boxCol.center = pos; //Position
boxCol.isTrigger = false; //Allow Collisions
//Add To List
CustomCollider temp;
temp = new CustomCollider(id, type1, boxCol, null);
colliders.Add(temp);
colliderCounter++;
}
public void AddMeshCollider(int id, int type1, Vector3 pos, Mesh obj, float scale, Quaternion rot)
{
//Add GameObject then Set Position & Parent
GameObject meshCol1 = new GameObject("MeshCol "+id);
meshCol1.transform.parent = meshCols.transform;
meshCol1.transform.localPosition = pos;
meshCol1.transform.localScale = new Vector3(scale, scale, scale); //Scale (Move to CubeType)
meshCol1.transform.localRotation = rot; //Zero the Rotation
//Set Tag & Layer
meshCol1.tag = "Block";
meshCol1.layer = LayerMask.NameToLayer("BuildingStructure");
//Add a Collider
MeshCollider meshCol = meshCol1.AddComponent(typeof(MeshCollider)) as MeshCollider;
meshCol.convex = false; //Allows for Complete Object Mapping
meshCol.sharedMesh = obj;
meshCol.isTrigger = false; //Allow Collisions
//Attach vObjectDamage Destruct Detection
meshCol1.AddComponent<vObjectDamage>();
//Add To List
CustomCollider temp;
temp = new CustomCollider(id, type1, meshCol, meshCol1);
colliders.Add(temp);
colliderCounter++;
}
public void RemoveColliderByID(int id1, int type1)
{
for (var i = 0; i < colliders.Count; i++)
{
if (colliders[i].id == id1 && colliders[i].typeID == type1)
{
if (colliders[i].obj != null) //Delete MeshCollider Gobj
{
Destroy(colliders[i].obj);
colliders.Remove(colliders[i]); //Remove from List
colliderCounter--;
return;
}
else //Delete Box Collider
{
Destroy(colliders[i].col);
colliders.Remove(colliders[i]); //Remove from List
colliderCounter--;
return;
}
}
}
}
//NOT USED
public void RemoveCollider(Collider col1)
{
for (var i = 0; i < colliders.Count; i++)
{
if (colliders[i].col.GetInstanceID() == col1.GetInstanceID())
{
if (colliders[i].obj != null) //Delete MeshCollider Gobj
{
Destroy(colliders[i].obj);
colliders.Remove(colliders[i]); //Remove from List
colliderCounter--;
return;
}
else //Delete Box Collider
{
Destroy(colliders[i].col);
colliders.Remove(colliders[i]); //Remove from List
colliderCounter--;
return;
}
}
}
}
public void FindBoxIdByCollider(Collider col1, out int gobjID, out int type1)
{
gobjID = -1;
type1 = -1;
for (var i = 0; i < colliders.Count; i++)
{
if (colliders[i].col.GetInstanceID() == col1.GetInstanceID())
{
gobjID = colliders[i].id;
type1 = colliders[i].typeID;
return;
}
}
}
}
public class CustomCollider
{
public int id;
public int typeID;
public Collider col;
public GameObject obj;
public CustomCollider(int id1, int type1, Collider col1, GameObject obj1)
{
id = id1;
typeID = type1;
col = col1;
obj = obj1;
}
}
using UnityEngine;
public class CubeType : MonoBehaviour
{
[Tooltip("Keep the TypeIDs in Order (eg 0, 1, 2, 3)")]
public int typeID;
public string typeName;
public int itemID;
[Tooltip("Type 0 = Box, Type 1 = MeshCollider")]
public int collisionType;
public float meshColliderScale;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment