NorbiPeti
64b42830a3
Fixed getting the selected blueprint Fixed block groups not being assigned to first block
185 lines
No EOL
6.4 KiB
C#
185 lines
No EOL
6.4 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
using Gamecraft.Blocks.BlockGroups;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
|
|
using GamecraftModdingAPI.Blocks;
|
|
using GamecraftModdingAPI.Utility;
|
|
|
|
namespace GamecraftModdingAPI
|
|
{
|
|
/// <summary>
|
|
/// A group of blocks that can be selected together. The placed version of blueprints.
|
|
/// </summary>
|
|
public class BlockGroup : ICollection<Block>
|
|
{
|
|
internal static BlueprintEngine _engine = new BlueprintEngine();
|
|
public int Id { get; }
|
|
private readonly Block sourceBlock;
|
|
private readonly List<Block> blocks;
|
|
private float3 position, rotation;
|
|
internal bool PosAndRotCalculated;
|
|
|
|
internal BlockGroup(int id, Block block)
|
|
{
|
|
if (id == BlockGroupUtility.GROUP_UNASSIGNED)
|
|
throw new BlockException("Cannot create a block group for blocks without a group!");
|
|
Id = id;
|
|
sourceBlock = block;
|
|
blocks = new List<Block>(GetBlocks());
|
|
}
|
|
|
|
/// <summary>
|
|
/// The position of the block group (center). Recalculated if blocks have been added/removed since the last query.
|
|
/// </summary>
|
|
public float3 Position
|
|
{
|
|
get
|
|
{
|
|
if (!PosAndRotCalculated)
|
|
Refresh();
|
|
return position;
|
|
}
|
|
set
|
|
{
|
|
var diff = value - position;
|
|
foreach (var block in blocks)
|
|
block.Position += diff;
|
|
if (!PosAndRotCalculated) //The condition can only be true if a block has been added/removed manually
|
|
Refresh(); //So the blocks array is up to date
|
|
else
|
|
position += diff;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The rotation of the block group. Recalculated if blocks have been added/removed since the last query.
|
|
/// </summary>
|
|
public float3 Rotation
|
|
{
|
|
get
|
|
{
|
|
if (!PosAndRotCalculated)
|
|
Refresh();
|
|
return rotation;
|
|
}
|
|
set
|
|
{
|
|
var diff = value - rotation;
|
|
var qdiff = Quaternion.Euler(diff);
|
|
foreach (var block in blocks)
|
|
{
|
|
block.Rotation += diff;
|
|
block.Position = qdiff * block.Position;
|
|
}
|
|
if (!PosAndRotCalculated)
|
|
Refresh();
|
|
else
|
|
rotation += diff;
|
|
}
|
|
}
|
|
|
|
/*/// <summary>
|
|
/// Removes all of the blocks in this group from the world.
|
|
/// </summary>
|
|
public void RemoveBlocks()
|
|
{
|
|
_engine.RemoveBlockGroup(Id); - TODO: Causes a hard crash
|
|
}*/
|
|
|
|
/// <summary>
|
|
/// Creates a new block group consisting of a single block.
|
|
/// You can add more blocks using the Add() method or by setting the BlockGroup property of the blocks.<br />
|
|
/// Note that only newly placed blocks should be added to groups.
|
|
/// </summary>
|
|
/// <param name="block">The block to add</param>
|
|
/// <returns>A new block group containing the given block</returns>
|
|
public static BlockGroup Create(Block block)
|
|
{
|
|
var bg = new BlockGroup(_engine.CreateBlockGroup(default, default), block);
|
|
block.BlockGroup = bg;
|
|
return bg;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Collects each block that is a part of this group. Also sets the position and rotation.
|
|
/// </summary>
|
|
/// <returns>An array of blocks</returns>
|
|
private Block[] GetBlocks()
|
|
{
|
|
if (!sourceBlock.Exists) return new[] {sourceBlock}; //The block must exist to get the others
|
|
var ret = _engine.GetBlocksFromGroup(sourceBlock.Id, out var pos, out var rot);
|
|
position = pos;
|
|
rotation = ((Quaternion) rot).eulerAngles;
|
|
PosAndRotCalculated = true;
|
|
return ret;
|
|
}
|
|
|
|
private void Refresh()
|
|
{
|
|
blocks.Clear();
|
|
blocks.AddRange(GetBlocks());
|
|
}
|
|
|
|
internal static void Init()
|
|
{
|
|
GameEngineManager.AddGameEngine(_engine);
|
|
}
|
|
|
|
public IEnumerator<Block> GetEnumerator() => blocks.GetEnumerator();
|
|
IEnumerator IEnumerable.GetEnumerator() => blocks.GetEnumerator();
|
|
|
|
/// <summary>
|
|
/// Adds a block to the group. You should only add newly placed blocks
|
|
/// so that the game initializes the group membership properly.
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <exception cref="NullReferenceException"></exception>
|
|
public void Add(Block item)
|
|
{
|
|
if (item == null) throw new NullReferenceException("Cannot add null to a block group");
|
|
item.BlockGroup = this; //Calls AddInternal
|
|
}
|
|
|
|
internal void AddInternal(Block item) => blocks.Add(item);
|
|
|
|
/// <summary>
|
|
/// Removes all blocks from this group.
|
|
/// You should not remove blocks that have been initialized, only those that you placed recently.
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
while (blocks.Count > 0)
|
|
Remove(blocks[blocks.Count - 1]);
|
|
}
|
|
|
|
public bool Contains(Block item) => blocks.Contains(item);
|
|
public void CopyTo(Block[] array, int arrayIndex) => blocks.CopyTo(array, arrayIndex);
|
|
|
|
/// <summary>
|
|
/// Removes a block from this group.
|
|
/// You should not remove blocks that have been initialized, only those that you placed recently.
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <returns></returns>
|
|
/// <exception cref="NullReferenceException"></exception>
|
|
public bool Remove(Block item)
|
|
{
|
|
if (item == null) throw new NullReferenceException("Cannot remove null from a block group");
|
|
bool ret = item.BlockGroup == this;
|
|
if (ret)
|
|
item.BlockGroup = null; //Calls RemoveInternal
|
|
return ret;
|
|
}
|
|
|
|
internal void RemoveInternal(Block item) => blocks.Remove(item);
|
|
|
|
public int Count => blocks.Count;
|
|
public bool IsReadOnly { get; } = false;
|
|
|
|
public Block this[int index] => blocks[index]; //Setting is not supported, since the order doesn't matter
|
|
}
|
|
} |