riversong code showcase

This commit is contained in:
Daniele Marotta
2026-05-21 15:52:18 +02:00
commit 4c9eea1c02
462 changed files with 23406 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Cysharp.Threading.Tasks;
using Unity.Mathematics;
using UnityEngine;
namespace DanieleMarotta.RiversongCodeShowcase
{
[Service(typeof(IAoERenderingService))]
[GameSystemGroup(typeof(LateGameSystemGroup))]
public class AoERenderingSystem : GameSystem, IInitializable, IDisposable, IUpdatable, IAoERenderingService
{
private const int MaxAoECount = 16;
private static readonly int AoESourcesPropertyID = Shader.PropertyToID("_AoE_Sources");
private static readonly int AoECountPropertyID = Shader.PropertyToID("_AoE_Count");
[InjectService]
private GameConfig _config;
[InjectService]
private IBuildingVisualizationCollection _buildingVisualizationCollection;
private ComputeBuffer _aoeBuffer;
private List<AoE> _data = new(MaxAoECount);
public AoERenderingSystem(IServiceLocator serviceLocator) : base(serviceLocator)
{
}
public UniTask InitializeAsync()
{
_aoeBuffer = new ComputeBuffer(MaxAoECount, sizeof(int) + sizeof(float) * 4, ComputeBufferType.Structured, ComputeBufferMode.Dynamic);
return UniTask.CompletedTask;
}
public void Dispose()
{
_aoeBuffer.Dispose();
}
public void Update()
{
_aoeBuffer.SetData(_data);
var material = _config.Vfx.AoEMaterial;
material.SetBuffer(AoESourcesPropertyID, _aoeBuffer);
material.SetInt(AoECountPropertyID, _data.Count);
_data.Clear();
}
public void Add(int layer, TileRect rect)
{
_data.Add(
new AoE
{
Layer = layer,
Rect = new float4(rect.Min, rect.Max)
});
}
[StructLayout(LayoutKind.Sequential)]
private struct AoE
{
public int Layer;
public float4 Rect;
}
}
}

View File

@@ -0,0 +1,43 @@
using System;
using Cysharp.Threading.Tasks;
using UnityEngine;
namespace DanieleMarotta.RiversongCodeShowcase
{
[GameSystemGroup(typeof(LateGameSystemGroup))]
public class GlobalShaderParametersSystem : GameSystem, IInitializable, IDisposable, IUpdatable
{
[InjectService]
private World _world;
[InjectService]
private ISignalBus _signalBus;
public GlobalShaderParametersSystem(IServiceLocator serviceLocator) : base(serviceLocator)
{
}
public UniTask InitializeAsync()
{
_signalBus.Subscribe<WorldReadySignal>(OnWorldReady);
return UniTask.CompletedTask;
}
public void Dispose()
{
_signalBus.Unsubscribe<WorldReadySignal>(OnWorldReady);
}
public void Update()
{
var t = Time.unscaledTime;
Shader.SetGlobalVector(ShaderProperties.UnscaledTime, new Vector4(t / 20, t, t * 2, t * 3));
}
private void OnWorldReady(WorldReadySignal signal)
{
Shader.SetGlobalVector(ShaderProperties.WorldSize, new Vector4(_world.Size.x, _world.Size.y, 0, 0));
Shader.SetGlobalVector(ShaderProperties.InverseWorldSize, new Vector2(1 / (float)_world.Size.x, 1 / (float)_world.Size.y));
}
}
}

View File

@@ -0,0 +1,7 @@
namespace DanieleMarotta.RiversongCodeShowcase
{
public interface IAoERenderingService
{
void Add(int layer, TileRect rect);
}
}

View File

@@ -0,0 +1,132 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;
namespace DanieleMarotta.RiversongCodeShowcase
{
public class MaterialReplacementCache
{
private static readonly int BaseMapPropertyId = Shader.PropertyToID("_BaseMap");
private static readonly int MainTexPropertyId = Shader.PropertyToID("_MainTex");
private static readonly int MainTexturePropertyId = Shader.PropertyToID("_Main_Texture");
private HashSet<int> _gameObjects = new();
private List<(Renderer, Material, int, MaterialPropertyBlock)> _cache = new();
private List<MaterialPropertyBlock> _propertyBlockPool = new();
private int _propertyBlockPoolIndex;
private MaterialPropertyBlock _propertyBlock;
public static void ReplaceRendererMaterials(Renderer renderer, Material material, MaterialPropertyBlock propertyBlock)
{
var materials = renderer.sharedMaterials;
for (var i = 0; i < materials.Length; i++)
{
var originalMaterial = materials[i];
materials[i] = material;
ReplaceTexture(renderer, originalMaterial, i, propertyBlock, null);
}
renderer.sharedMaterials = materials;
}
public void ReplaceMaterials(GameObject gameObject, Material material)
{
if (!_gameObjects.Add(gameObject.GetInstanceID())) return;
using var renderersScope = ListPool<Renderer>.Get(out var renderers);
gameObject.GetComponentsInChildren(renderers);
foreach (var renderer in renderers) ReplaceMaterials(renderer, material);
}
public void ReplaceMaterials(List<GameObject> gameObjects, Material material)
{
if (gameObjects.Count == 0) return;
using var renderersScope = ListPool<Renderer>.Get(out var renderers);
foreach (var gameObject in gameObjects)
{
if (!_gameObjects.Add(gameObject.GetInstanceID())) continue;
renderers.Clear();
gameObject.GetComponentsInChildren(renderers);
foreach (var renderer in renderers) ReplaceMaterials(renderer, material);
}
}
public void RestoreMaterials()
{
foreach (var (renderer, material, i, propertyBlock) in _cache)
{
if (!renderer) continue;
var materials = renderer.sharedMaterials;
materials[i] = material;
renderer.sharedMaterials = materials;
renderer.SetPropertyBlock(propertyBlock, i);
}
_gameObjects.Clear();
_cache.Clear();
_propertyBlockPoolIndex = 0;
}
private void ReplaceMaterials(Renderer renderer, Material material)
{
var materials = renderer.sharedMaterials;
_propertyBlock ??= new MaterialPropertyBlock();
for (var i = 0; i < materials.Length; i++)
{
var currentPropertyBlock = GetPooledPropertyBlock();
renderer.GetPropertyBlock(currentPropertyBlock, i);
_cache.Add((renderer, materials[i], i, currentPropertyBlock));
var originalMaterial = materials[i];
materials[i] = material;
ReplaceTexture(renderer, originalMaterial, i, _propertyBlock, currentPropertyBlock);
}
renderer.sharedMaterials = materials;
}
private MaterialPropertyBlock GetPooledPropertyBlock()
{
if (_propertyBlockPoolIndex >= _propertyBlockPool.Count) _propertyBlockPool.Add(new MaterialPropertyBlock());
var propertyBlock = _propertyBlockPool[_propertyBlockPoolIndex++];
propertyBlock.Clear();
return propertyBlock;
}
private static void ReplaceTexture(Renderer renderer, Material material, int materialIndex, MaterialPropertyBlock propertyBlock, MaterialPropertyBlock sourcePropertyBlock)
{
var texture = GetMainTexture(material);
if (!texture) texture = sourcePropertyBlock?.GetTexture(MainTexturePropertyId);
if (!texture) return;
propertyBlock.Clear();
propertyBlock.SetTexture(MainTexturePropertyId, texture);
renderer.SetPropertyBlock(propertyBlock, materialIndex);
}
private static Texture GetMainTexture(Material material)
{
if (material.HasProperty(BaseMapPropertyId)) return material.GetTexture(BaseMapPropertyId);
if (material.HasProperty(MainTexPropertyId)) return material.GetTexture(MainTexPropertyId);
return material.HasProperty(MainTexturePropertyId) ? material.GetTexture(MainTexturePropertyId) : null;
}
}
}

View File

@@ -0,0 +1,16 @@
namespace DanieleMarotta.RiversongCodeShowcase
{
[GameSystemGroup(typeof(EarlyGameSystemGroup))]
public class RenderingInitializationGameSystem : GameSystem, IServiceProvider
{
public RenderingInitializationGameSystem(IServiceLocator serviceLocator) : base(serviceLocator)
{
}
public void RegisterServices(IServiceLocator serviceLocator)
{
serviceLocator.RegisterService(new WorldRenderingState());
}
}
}

View File

@@ -0,0 +1,19 @@
using UnityEngine;
namespace DanieleMarotta.RiversongCodeShowcase
{
public static class ShaderProperties
{
public static readonly int Color = Shader.PropertyToID("_Color");
public static readonly int Amount = Shader.PropertyToID("_Amount");
public static readonly int UnscaledTime = Shader.PropertyToID("_Unscaled_Time");
public static readonly int WorldSize = Shader.PropertyToID("_World_Size");
public static readonly int InverseWorldSize = Shader.PropertyToID("_Inverse_World_Size");
public static readonly int NightBlend = Shader.PropertyToID("_Night_Blend");
}
}

View File

@@ -0,0 +1,19 @@
using System.Collections.Generic;
namespace DanieleMarotta.RiversongCodeShowcase
{
public class WorldRenderingState
{
/// <summary>
/// All terrain chunks. Use <see cref="AddTerrainChunk" /> to register new chunks with the rendering state.
/// </summary>
public List<TerrainChunk> TerrainChunks { get; } = new();
public TileHighlight TileHighlight { get; } = new();
public void AddTerrainChunk(TerrainChunk chunk)
{
TerrainChunks.Add(chunk);
}
}
}