added forge addon
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 21s
Create tag and build when new code gets to main / Test (push) Successful in 6m56s
Create tag and build when new code gets to main / Export (push) Successful in 9m3s

This commit is contained in:
2026-02-08 15:16:01 +01:00
parent 2b74c9e70c
commit c4be97e0de
163 changed files with 6975 additions and 141 deletions

View File

@@ -0,0 +1,312 @@
// Copyright © Gamesmiths Guild.
using System.Collections.Generic;
using Gamesmiths.Forge.Core;
using Gamesmiths.Forge.Effects;
using Gamesmiths.Forge.Godot.Nodes;
using Godot;
namespace Gamesmiths.Forge.Godot.Core;
internal sealed class EffectApplier
{
private record struct EffectKey(EffectData EffectData, EffectOwnership EffectOwnership, int Level);
private readonly List<EffectData> _effects = [];
private readonly Dictionary<IForgeEntity, List<ActiveEffectHandle>> _effectInstances = [];
private readonly Dictionary<EffectKey, Effect> _effectsCache = [];
public EffectApplier(Node node)
{
foreach (Node child in node.GetChildren())
{
if (child is ForgeEffect effectNode && effectNode.EffectData is not null)
{
_effects.Add(effectNode.EffectData.GetEffectData());
}
}
}
public void ApplyEffects(
Node node,
IForgeEntity? effectOwner,
IForgeEntity? effectSource,
int level = 1)
{
if (node is IForgeEntity forgeEntity)
{
ApplyEffects(forgeEntity, effectOwner, effectSource, level);
return;
}
foreach (Node? child in node.GetChildren())
{
if (child is IForgeEntity forgeEntityChild)
{
ApplyEffects(forgeEntityChild, effectOwner, effectSource, level);
return;
}
}
}
public void ApplyEffects<TData>(
Node node,
TData contextData,
IForgeEntity? effectOwner,
IForgeEntity? effectSource,
int level = 1)
{
if (node is IForgeEntity forgeEntity)
{
ApplyEffects(forgeEntity, contextData, effectOwner, effectSource, level);
return;
}
foreach (Node? child in node.GetChildren())
{
if (child is IForgeEntity forgeEntityChild)
{
ApplyEffects(forgeEntityChild, contextData, effectOwner, effectSource, level);
return;
}
}
}
public void AddEffects(
Node node,
IForgeEntity? effectOwner,
IForgeEntity? effectSource,
int level)
{
if (node is IForgeEntity forgeEntity)
{
AddEffects(forgeEntity, effectOwner, effectSource, level);
return;
}
foreach (Node? child in node.GetChildren())
{
if (child is IForgeEntity forgeEntityChild)
{
AddEffects(forgeEntityChild, effectOwner, effectSource, level);
return;
}
}
}
public void AddEffects<TData>(
Node node,
TData contextData,
IForgeEntity? effectOwner,
IForgeEntity? effectSource,
int level)
{
if (node is IForgeEntity forgeEntity)
{
AddEffects(forgeEntity, contextData, effectOwner, effectSource, level);
return;
}
foreach (Node? child in node.GetChildren())
{
if (child is IForgeEntity forgeEntityChild)
{
AddEffects(forgeEntityChild, contextData, effectOwner, effectSource, level);
return;
}
}
}
public void RemoveEffects(Node node)
{
if (node is IForgeEntity forgeEntity)
{
RemoveEffects(forgeEntity);
return;
}
foreach (Node? child in node.GetChildren())
{
if (child is IForgeEntity forgeEntityChild)
{
RemoveEffects(forgeEntityChild);
return;
}
}
}
private void ApplyEffects(
IForgeEntity forgeEntity,
IForgeEntity? effectOwner,
IForgeEntity? effectSource,
int level)
{
var effectOwnership = new EffectOwnership(effectOwner, effectSource);
foreach (EffectData effectData in _effects)
{
var key = new EffectKey(effectData, effectOwnership, level);
if (_effectsCache.TryGetValue(key, out Effect? cachedEffect))
{
forgeEntity.EffectsManager.ApplyEffect(cachedEffect);
continue;
}
var effect = new Effect(
effectData,
new EffectOwnership(effectOwner, effectSource),
level);
_effectsCache[key] = effect;
forgeEntity.EffectsManager.ApplyEffect(effect);
}
}
private void ApplyEffects<TData>(
IForgeEntity forgeEntity,
TData contextData,
IForgeEntity? effectOwner,
IForgeEntity? effectSource,
int level)
{
var effectOwnership = new EffectOwnership(effectOwner, effectSource);
foreach (EffectData effectData in _effects)
{
var key = new EffectKey(effectData, effectOwnership, level);
if (_effectsCache.TryGetValue(key, out Effect? cachedEffect))
{
forgeEntity.EffectsManager.ApplyEffect(cachedEffect);
continue;
}
var effect = new Effect(
effectData,
new EffectOwnership(effectOwner, effectSource),
level);
_effectsCache[key] = effect;
forgeEntity.EffectsManager.ApplyEffect(effect, contextData);
}
}
private void AddEffects(
IForgeEntity forgeEntity,
IForgeEntity?
effectOwner,
IForgeEntity? effectSource,
int level)
{
var instanceEffects = new List<ActiveEffectHandle>();
if (!_effectInstances.TryAdd(forgeEntity, instanceEffects))
{
instanceEffects = _effectInstances[forgeEntity];
}
var effectOwnership = new EffectOwnership(effectOwner, effectSource);
foreach (EffectData effectData in _effects)
{
var key = new EffectKey(effectData, effectOwnership, level);
ActiveEffectHandle? handle;
if (_effectsCache.TryGetValue(key, out Effect? cachedEffect))
{
handle = forgeEntity.EffectsManager.ApplyEffect(cachedEffect);
if (handle is null)
{
continue;
}
instanceEffects.Add(handle);
continue;
}
var effect = new Effect(
effectData,
new EffectOwnership(effectOwner, effectSource),
level);
handle = forgeEntity.EffectsManager.ApplyEffect(effect);
if (handle is null)
{
continue;
}
instanceEffects.Add(handle);
}
}
private void AddEffects<TData>(
IForgeEntity forgeEntity,
TData contextData,
IForgeEntity? effectOwner,
IForgeEntity? effectSource,
int level)
{
var instanceEffects = new List<ActiveEffectHandle>();
if (!_effectInstances.TryAdd(forgeEntity, instanceEffects))
{
instanceEffects = _effectInstances[forgeEntity];
}
var effectOwnership = new EffectOwnership(effectOwner, effectSource);
foreach (EffectData effectData in _effects)
{
var key = new EffectKey(effectData, effectOwnership, level);
ActiveEffectHandle? handle;
if (_effectsCache.TryGetValue(key, out Effect? cachedEffect))
{
handle = forgeEntity.EffectsManager.ApplyEffect(cachedEffect);
if (handle is null)
{
continue;
}
instanceEffects.Add(handle);
continue;
}
var effect = new Effect(
effectData,
new EffectOwnership(effectOwner, effectSource),
level);
handle = forgeEntity.EffectsManager.ApplyEffect(effect, contextData);
if (handle is null)
{
continue;
}
instanceEffects.Add(handle);
}
}
private void RemoveEffects(IForgeEntity forgeEntity)
{
if (!_effectInstances.TryGetValue(forgeEntity, out List<ActiveEffectHandle>? value))
{
return;
}
foreach (ActiveEffectHandle handle in value)
{
forgeEntity.EffectsManager.RemoveEffect(handle);
}
_effectInstances[forgeEntity] = [];
}
}

View File

@@ -0,0 +1 @@
uid://bs52uo5esaiu2

View File

@@ -0,0 +1,14 @@
// Copyright © Gamesmiths Guild.
using Godot;
namespace Gamesmiths.Forge.Godot.Core;
public partial class ForgeBootstrap : Node
{
public override void _Ready()
{
ForgeData pluginData = ResourceLoader.Load<ForgeData>("uid://8j4xg16o3qnl");
_ = new ForgeManagers(pluginData);
}
}

View File

@@ -0,0 +1 @@
uid://ba8fquhtwu5mu

View File

@@ -0,0 +1,21 @@
// Copyright © Gamesmiths Guild.
using Gamesmiths.Forge.Core;
using Godot;
namespace Gamesmiths.Forge.Godot.Core;
public readonly struct ForgeCurve(Curve? curve) : ICurve
{
private readonly Curve? _curve = curve;
public float Evaluate(float value)
{
if (_curve is null)
{
return 1;
}
return _curve.Sample(value);
}
}

View File

@@ -0,0 +1 @@
uid://cei2cgvy84iy6

View File

@@ -0,0 +1,13 @@
// Copyright © Gamesmiths Guild.
using Godot;
using Godot.Collections;
namespace Gamesmiths.Forge.Godot.Core;
[Tool]
public partial class ForgeData : Resource
{
[Export]
public Array<string> RegisteredTags { get; set; } = [];
}

View File

@@ -0,0 +1 @@
uid://bq4vlbfx00hea

View File

@@ -0,0 +1,30 @@
// Copyright © Gamesmiths Guild.
using Gamesmiths.Forge.Core;
using Gamesmiths.Forge.Cues;
using Gamesmiths.Forge.Tags;
namespace Gamesmiths.Forge.Godot.Core;
public class ForgeManagers
{
public static ForgeManagers Instance { get; private set; } = null!;
public TagsManager TagsManager { get; private set; }
public CuesManager CuesManager { get; private set; }
public ForgeManagers(ForgeData pluginData)
{
Instance = this;
#if DEBUG
Validation.Enabled = true;
#else
Validation.Enabled = false;
#endif
TagsManager = new TagsManager([.. pluginData.RegisteredTags]);
CuesManager = new CuesManager();
}
}

View File

@@ -0,0 +1 @@
uid://djeiinm1gclh4

View File

@@ -0,0 +1,98 @@
// Copyright © Gamesmiths Guild.
using System;
using Gamesmiths.Forge.Core;
using Godot;
namespace Gamesmiths.Forge.Godot.Core;
public class ForgeRandom : IRandom, IDisposable
{
private readonly RandomNumberGenerator _randomNumberGenerator;
public ForgeRandom()
{
_randomNumberGenerator = new RandomNumberGenerator();
_randomNumberGenerator.Randomize();
}
public void NextBytes(byte[] buffer)
{
for (var i = 0; i < buffer.Length; i++)
{
buffer[i] = (byte)_randomNumberGenerator.RandiRange(0, 255);
}
}
public void NextBytes(Span<byte> buffer)
{
for (var i = 0; i < buffer.Length; i++)
{
buffer[i] = (byte)_randomNumberGenerator.RandiRange(0, 255);
}
}
public double NextDouble()
{
return _randomNumberGenerator.Randf();
}
public int NextInt()
{
return (int)_randomNumberGenerator.Randi();
}
public int NextInt(int maxValue)
{
return _randomNumberGenerator.RandiRange(0, maxValue - 1);
}
public int NextInt(int minValue, int maxValue)
{
return _randomNumberGenerator.RandiRange(minValue, maxValue - 1);
}
public long NextInt64()
{
unchecked
{
var high = _randomNumberGenerator.Randi();
var low = _randomNumberGenerator.Randi();
return ((long)high << 32) | low;
}
}
public long NextInt64(long maxValue)
{
return NextInt64(0, maxValue);
}
public long NextInt64(long minValue, long maxValue)
{
if (minValue >= maxValue)
{
throw new ArgumentOutOfRangeException(nameof(minValue), "minValue must be less than maxValue.");
}
var range = (ulong)(maxValue - minValue);
var rand = (ulong)NextInt64();
return (long)(rand % range) + minValue;
}
public float NextSingle()
{
return _randomNumberGenerator.Randf();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
_randomNumberGenerator.Dispose();
}
}

View File

@@ -0,0 +1 @@
uid://dap6x2ddf6baj

View File

@@ -0,0 +1,7 @@
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://8j4xg16o3qnl"]
[ext_resource type="Script" uid="uid://bq4vlbfx00hea" path="res://addons/forge/core/ForgeData.cs" id="1_x0pne"]
[resource]
script = ExtResource("1_x0pne")
RegisteredTags = Array[String](["effect.fire", "effect.wet", "cue.floating.text", "cue.vfx.fire", "cue.vfx.wet", "cue.vfx.regen", "cooldown.enemy.attack", "set_by_caller.damage", "event.damage", "cooldown", "cooldown.skill.projectile", "cooldown.skill.shield", "cooldown.skill.dash", "movement.block", "immunity.damage", "effect.mana_shield", "cue.vfx.shield", "event.damage.taken", "event.damage.dealt", "event", "set_by_caller", "trait.flammable", "trait.healable", "trait.damageable", "trait.wettable", "cue.vfx.reflect", "cue.vfx", "cooldown.skill", "cooldown.skill.reflect"])