WorldBuilder/World.Spawn.cs
using System;
using Clover.Data;
using Clover.Items;
using Clover.Persistence;
using Sandbox.Diagnostics;
namespace Clover;
public sealed partial class World
{
public WorldItem SpawnPlacedItem( ItemData itemData, Vector2Int position, ItemRotation rotation )
{
return SpawnNode( itemData, ItemPlacementType.Placed, position, rotation );
}
public WorldItem SpawnPlacedItem( PersistentItem persistentItem, Vector2Int position, ItemRotation rotation )
{
var itemData = persistentItem.ItemData;
var worldItem = SpawnPlacedItem( itemData, position, rotation );
worldItem.LoadPersistence( persistentItem );
return worldItem;
}
public WorldItem SpawnPlacedItem( ItemData itemData, Vector3 position, Rotation rotation )
{
return SpawnNode( itemData, ItemPlacementType.Placed, position, rotation );
}
public WorldItem SpawnPlacedItem( PersistentItem persistentItem, Vector3 position, Rotation rotation )
{
var itemData = persistentItem.ItemData;
var worldItem = SpawnPlacedItem( itemData, position, rotation );
worldItem.LoadPersistence( persistentItem );
return worldItem;
}
public WorldItem SpawnDroppedNode( ItemData itemData, Vector2Int position, ItemRotation rotation )
{
return SpawnNode( itemData, ItemPlacementType.Dropped, position, rotation );
}
public WorldItem SpawnDroppedNode( PersistentItem persistentItem, Vector2Int position, ItemRotation rotation )
{
var itemData = persistentItem.ItemData;
var worldItem = SpawnDroppedNode( itemData, position, rotation );
worldItem.LoadPersistence( persistentItem );
return worldItem;
}
public WorldItem SpawnCustomItem( ItemData itemData, GameObject prefab, Vector2Int position,
ItemRotation rotation )
{
if ( IsOutsideGrid( position ) )
{
throw new Exception( $"Position {position} is outside the grid" );
}
/*if ( !itemData.Placements.HasFlag( placement ) )
{
throw new Exception( $"Item {itemData.Name} does not support placement {placement}" );
}*/
var positions = itemData.GetGridPositions( rotation, position );
/*if ( !CanPlaceItem( positions, placement ) )
{
throw new Exception( $"Cannot place item {itemData.Name} at {position} with placement {placement}" );
}*/
if ( prefab == null )
{
throw new Exception( $"Item {itemData.Name} has no scene" );
}
var gameObject = prefab.Clone();
if ( !gameObject.IsValid() )
{
throw new Exception( $"Failed to clone scene for {itemData.Name}" );
}
gameObject.WorldPosition = ItemGridToWorld( position );
gameObject.WorldRotation = GetRotation( rotation );
var nodeLink = AddItem( position, rotation, gameObject );
nodeLink.SetItemData( itemData );
nodeLink.ItemPlacement = ItemPlacementType.Placed;
nodeLink.CalculateSize();
// UpdateTransform( nodeLink );
// nodeLink.OnNodeAdded();
gameObject.NetworkSpawn();
var worldItem = nodeLink.GetComponent<WorldItem>();
return worldItem;
}
private WorldItem SpawnNode( ItemData itemData, ItemPlacementType placementType, Vector2Int position,
ItemRotation rotation )
{
Assert.NotNull( itemData, "Item data is null" );
if ( IsOutsideGrid( position ) )
{
throw new Exception( $"Position {position} is outside the grid" );
}
/*if ( !itemData.Placements.HasFlag( placement ) )
{
throw new Exception( $"Item {itemData.Name} does not support placement {placement}" );
}*/
var defaultDropScene = GameObject.GetPrefab( "items/misc/dropped_item/dropped_item.prefab" );
var spawnPrefab = placementType switch
{
ItemPlacementType.Placed => itemData.PlaceScene,
ItemPlacementType.Dropped => itemData.DropScene ?? defaultDropScene,
_ => throw new ArgumentOutOfRangeException( nameof(placementType), placementType, null )
};
if ( !spawnPrefab.IsValid() )
{
throw new Exception( $"Item {(itemData.Name ?? itemData.ResourceName)} has no {placementType} scene" );
}
// dropped items are always 1x1
var positions = placementType == ItemPlacementType.Dropped
? new List<Vector2Int> { position }
: itemData.GetGridPositions( rotation, position );
/*if ( !CanPlaceItem( positions, placement ) )
{
throw new Exception( $"Cannot place item {itemData.Name} at {position} with placement {placement}" );
}*/
var gameObject = spawnPrefab.Clone();
gameObject.WorldPosition = ItemGridToWorld( position );
gameObject.WorldRotation = GetRotation( rotation );
var nodeLink = AddItem( position, rotation, gameObject );
nodeLink.SetItemData( itemData );
nodeLink.ItemPlacement = ItemPlacementType.Placed;
// replace itemdata with the one from the item, mainly for dropped items
/*if ( nodeLink.Components.TryGet<WorldItem>( out var worldItem ) )
{
worldItem.ItemData = itemData;
}*/
// nodeLink.CalculateSize();
// UpdateTransform( nodeLink );
gameObject.Name = nodeLink.GetName();
// AddNodeLinkToGridMap( nodeLink );
WorldItems.Add( nodeLink );
// nodeLink.OnNodeAdded();
gameObject.NetworkSpawn();
return nodeLink;
}
private WorldItem SpawnNode( ItemData itemData, ItemPlacementType placementType, Vector3 position,
Rotation rotation )
{
Assert.NotNull( itemData, "Item data is null" );
if ( IsOutsideGrid( WorldToItemGrid( position ) ) )
{
throw new Exception( $"Position {position} is outside the grid" );
}
/*if ( !itemData.Placements.HasFlag( placement ) )
{
throw new Exception( $"Item {itemData.Name} does not support placement {placement}" );
}
*/
var defaultDropScene =
GameObject.GetPrefab( "items/misc/dropped_item/dropped_item.prefab" );
var spawnPrefab = placementType switch
{
ItemPlacementType.Placed => itemData.PlaceScene,
ItemPlacementType.Dropped => itemData.DropScene ?? defaultDropScene,
_ => throw new ArgumentOutOfRangeException( nameof(placementType), placementType, null )
};
if ( spawnPrefab == null )
{
throw new Exception( $"Item {(itemData.Name ?? itemData.ResourceName)} has no {placementType} scene" );
}
// dropped items are always 1x1
/*var positions = placementType == ItemPlacementType.Dropped
? new List<Vector2Int> { position }
: itemData.GetGridPositions( rotation, position );
if ( !CanPlaceItem( positions, placement ) )
{
throw new Exception( $"Cannot place item {itemData.Name} at {position} with placement {placement}" );
}*/
var gameObject = spawnPrefab.Clone();
gameObject.WorldPosition = position;
gameObject.WorldRotation = rotation;
var nodeLink = AddItem( gameObject );
nodeLink.SetItemData( itemData );
nodeLink.ItemPlacement = ItemPlacementType.Placed;
// replace itemdata with the one from the item, mainly for dropped items
/*if ( nodeLink.Components.TryGet<WorldItem>( out var worldItem ) )
{
worldItem.ItemData = itemData;
}*/
// nodeLink.CalculateSize();
// UpdateTransform( nodeLink );
gameObject.Name = nodeLink.GetName();
// AddNodeLinkToGridMap( nodeLink );
// nodeLink.OnNodeAdded();
gameObject.NetworkSpawn();
return nodeLink;
}
/// <summary>
/// Adds an item to the world at the specified position and placement. It does not check if the item can be placed at the specified position.
/// </summary>
/// <param name="position"></param>
/// <param name="rotation"></param>
/// <param name="placement"></param>
/// <param name="item"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public WorldItem AddItem( Vector2Int position, ItemRotation rotation, GameObject item )
{
if ( IsOutsideGrid( position ) )
{
throw new Exception( $"Position {position} is outside the grid" );
}
// var nodeLink = new WorldNodeLink( this, item );
// nodeLink.GridPosition = position;
// nodeLink.GridRotation = rotation;
// nodeLink.GridPlacement = placement;
// nodeLink.PrefabPath = nodeLink.GetPrefabPath();
// NODE LINK IS NOT ADDED TO WORLD YET, CAN'T DO IT HERE BECAUSE WE NEED TO CALCULATE SIZE FIRST
// AddNodeLinkToGridMap( nodeLink );
item.SetParent( GameObject ); // TODO: should items be parented to the world?
// OnItemAdded?.Invoke( nodeLink );
// nodeLink.OnNodeAdded();
// UpdateTransform( nodeLink );
var worldItem = item.GetComponent<WorldItem>();
WorldItems.Add( worldItem );
Log.Info( $"Added item {item.Name} at {position} ({item.Id})" );
// return nodeLink;
return worldItem;
}
public WorldItem AddItem( GameObject item )
{
/*if ( IsOutsideGrid( position ) )
{
throw new Exception( $"Position {position} is outside the grid" );
}*/
// var nodeLink = new WorldNodeLink( this, item );
// nodeLink.GridPlacement = placement;
// nodeLink.PrefabPath = nodeLink.GetPrefabPath();
// NODE LINK IS NOT ADDED TO WORLD YET, CAN'T DO IT HERE BECAUSE WE NEED TO CALCULATE SIZE FIRST
// AddNodeLinkToGridMap( nodeLink );
item.SetParent( GameObject ); // TODO: should items be parented to the world?
// WorldItems.Add( nodeLink );
var nodeLink = item.GetComponent<WorldItem>();
WorldItems.Add( nodeLink );
// OnItemAdded?.Invoke( nodeLink );
// nodeLink.OnNodeAdded();
// UpdateTransform( nodeLink );
Log.Info( $"Added item {item.Name} at {item.WorldPosition} ({item.Id})" );
return nodeLink;
}
}