260 lines
5.7 KiB
C#
260 lines
5.7 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Godot;
|
|
using System;
|
|
|
|
|
|
|
|
namespace Rokojori
|
|
{
|
|
[Tool]
|
|
[GlobalClass, Icon("res://Scripts/Rokojori/Rokojori-Action-Library/Icons/Scatterer.svg") ]
|
|
public partial class Scatterer:Node3D
|
|
{
|
|
[Export]
|
|
public bool update = false;
|
|
[Export]
|
|
public bool updateAlways = false;
|
|
[Export]
|
|
public Node3D[] containersToClearNodes;
|
|
[Export]
|
|
public bool clearContainers = false;
|
|
|
|
[Export]
|
|
public bool removeDiscarded = false;
|
|
|
|
[Export]
|
|
public int READ_ONLY_createdPoints = 0;
|
|
[Export]
|
|
public int READ_ONLY_instantiatedPoints = 0;
|
|
[Export]
|
|
public int READ_ONLY_reusedPoints = 0;
|
|
[Export]
|
|
public int READ_ONLY_remappedPoints = 0;
|
|
|
|
|
|
public override void _Process( double delta )
|
|
{
|
|
if ( clearContainers )
|
|
{
|
|
clearContainers = false;
|
|
ClearContainers();
|
|
}
|
|
|
|
if ( ! ( update || updateAlways ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
update = false;
|
|
|
|
ScatterAndInstantiatePoints();
|
|
}
|
|
|
|
public void ClearContainers()
|
|
{
|
|
Arrays.ForEach( containersToClearNodes,
|
|
c =>
|
|
{
|
|
Nodes.RemoveAndDeleteChildren( c );
|
|
}
|
|
);
|
|
}
|
|
|
|
class InstantiatedScatterPoint
|
|
{
|
|
public string hash;
|
|
public ScatterPoint scatterPoint;
|
|
public Node3D output;
|
|
}
|
|
|
|
Dictionary<string,InstantiatedScatterPoint> _instantiatedPoints = new Dictionary<string, InstantiatedScatterPoint>();
|
|
|
|
Dictionary<Scatterer,int> _scattererIDs = new Dictionary<Scatterer, int>();
|
|
|
|
int GetScattererID( Scatterer s )
|
|
{
|
|
if ( ! _scattererIDs.ContainsKey( s ) )
|
|
{
|
|
_scattererIDs[ s ] = _scattererIDs.Count;
|
|
}
|
|
|
|
return _scattererIDs[ s ];
|
|
}
|
|
|
|
string GetScatterPointHash( ScatterPoint p )
|
|
{
|
|
var scatterID = GetScattererID( p.creator ) + ":" + p.creatorID;
|
|
|
|
return scatterID;
|
|
}
|
|
|
|
public void ScatterAndInstantiatePoints()
|
|
{
|
|
if ( _instantiatedPoints.Count == 0 )
|
|
{
|
|
ClearContainers();
|
|
}
|
|
|
|
var points = Scatter( new List<ScatterPoint>() );
|
|
|
|
READ_ONLY_createdPoints = points.Count;
|
|
READ_ONLY_instantiatedPoints = 0;
|
|
READ_ONLY_reusedPoints = 0;
|
|
READ_ONLY_remappedPoints = 0;
|
|
|
|
var usedPoints = new HashSet<string>();
|
|
|
|
points.RemoveAll( p => ! p.visible );
|
|
|
|
points.ForEach( p =>
|
|
{
|
|
var hash = GetScatterPointHash( p );
|
|
|
|
if ( ! CanReuse( hash, p ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var existing = _instantiatedPoints[ hash ];
|
|
existing.scatterPoint = p;
|
|
existing.scatterPoint.UpdateInstantiated( existing.output );
|
|
|
|
usedPoints.Add( hash );
|
|
|
|
READ_ONLY_reusedPoints ++;
|
|
return;
|
|
|
|
}
|
|
);
|
|
|
|
var unused = new DictionaryList<PackedScene,InstantiatedScatterPoint>();
|
|
|
|
foreach ( var vk in _instantiatedPoints )
|
|
{
|
|
var ip = vk.Value;
|
|
|
|
if ( usedPoints.Contains( ip.hash ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
unused.Add( ip.scatterPoint.scene, ip );
|
|
}
|
|
|
|
points.ForEach( p =>
|
|
{
|
|
var hash = GetScatterPointHash( p );
|
|
|
|
if ( usedPoints.Contains( hash ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( unused.ContainsKey( p.scene ) )
|
|
{
|
|
var unusedPoint = unused[ p.scene ].Find( ip => ip.scatterPoint.CanBeReusedBy( p ) );
|
|
|
|
if ( unusedPoint != null )
|
|
{
|
|
unused.Remove( p.scene, unusedPoint );
|
|
unusedPoint.scatterPoint = p;
|
|
unusedPoint.scatterPoint.UpdateInstantiated( unusedPoint.output );
|
|
|
|
usedPoints.Add( hash );
|
|
|
|
READ_ONLY_remappedPoints ++;
|
|
return;
|
|
}
|
|
}
|
|
|
|
var instantiatedOutput = p.Instantiate();
|
|
|
|
if ( instantiatedOutput == null )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var ip = new InstantiatedScatterPoint();
|
|
ip.hash = hash;
|
|
ip.output = instantiatedOutput;
|
|
ip.scatterPoint = p;
|
|
|
|
if ( _instantiatedPoints.ContainsKey( hash ) )
|
|
{
|
|
Nodes.RemoveAndDelete( _instantiatedPoints[ hash ].output );
|
|
}
|
|
|
|
_instantiatedPoints[ hash ] = ip;
|
|
usedPoints.Add( hash );
|
|
|
|
READ_ONLY_instantiatedPoints++;
|
|
}
|
|
);
|
|
|
|
|
|
Dictionaries.RemoveAll(
|
|
_instantiatedPoints, ( k, v ) =>
|
|
{
|
|
if ( usedPoints.Contains( k ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Nodes.RemoveAndDelete( v.output );
|
|
|
|
return true;
|
|
}
|
|
);
|
|
|
|
}
|
|
|
|
bool CanReuse( string hash, ScatterPoint sp )
|
|
{
|
|
if ( ! _instantiatedPoints.ContainsKey( hash ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var existing = _instantiatedPoints[ hash ];
|
|
|
|
var canBeReused = existing.scatterPoint.CanBeReusedBy( sp );
|
|
|
|
return canBeReused;
|
|
}
|
|
|
|
public List<ScatterPoint> Scatter( List<ScatterPoint> points )
|
|
{
|
|
var returnedPoints = _Scatter( points );
|
|
|
|
if ( removeDiscarded )
|
|
{
|
|
returnedPoints.RemoveAll( p => ! p.visible );
|
|
}
|
|
|
|
return returnedPoints;
|
|
}
|
|
|
|
protected bool IsChildEnabled( Scatterer s, bool childrenNeedToBeVisible, bool childrenNeedToBeProcessing )
|
|
{
|
|
var enabled = true;
|
|
|
|
if ( childrenNeedToBeVisible )
|
|
{
|
|
enabled = enabled && s.Visible;
|
|
}
|
|
|
|
if ( childrenNeedToBeProcessing )
|
|
{
|
|
enabled = enabled && ( s.ProcessMode != ProcessModeEnum.Disabled );
|
|
}
|
|
|
|
return enabled;
|
|
}
|
|
|
|
protected virtual List<ScatterPoint> _Scatter( List<ScatterPoint> points )
|
|
{
|
|
return points;
|
|
}
|
|
}
|
|
} |