riversong code showcase
This commit is contained in:
9
Source/Riversong/Game/Unlocks/IUnlocksService.cs
Normal file
9
Source/Riversong/Game/Unlocks/IUnlocksService.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public interface IUnlocksService
|
||||
{
|
||||
void Unlock(UnlockDefinition unlock);
|
||||
|
||||
void UnlockAll();
|
||||
}
|
||||
}
|
||||
22
Source/Riversong/Game/Unlocks/UnlockCondition.cs
Normal file
22
Source/Riversong/Game/Unlocks/UnlockCondition.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using Sirenix.OdinInspector;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
[Serializable]
|
||||
public class UnlockCondition
|
||||
{
|
||||
public UnlockConditionType Type;
|
||||
|
||||
[ShowIf("Type", UnlockConditionType.BuildingPlaced)]
|
||||
public BuildingDefinition Building;
|
||||
|
||||
[ShowIf("Type", UnlockConditionType.HouseCountAtTierOrAbove)]
|
||||
[LabelText("Count")]
|
||||
public int HouseCount;
|
||||
|
||||
[ShowIf("Type", UnlockConditionType.HouseCountAtTierOrAbove)]
|
||||
[LabelText("Tier")]
|
||||
public int MinHouseTierIndex;
|
||||
}
|
||||
}
|
||||
11
Source/Riversong/Game/Unlocks/UnlockConditionType.cs
Normal file
11
Source/Riversong/Game/Unlocks/UnlockConditionType.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public enum UnlockConditionType
|
||||
{
|
||||
None,
|
||||
|
||||
BuildingPlaced,
|
||||
|
||||
HouseCountAtTierOrAbove
|
||||
}
|
||||
}
|
||||
22
Source/Riversong/Game/Unlocks/UnlockDefinition.cs
Normal file
22
Source/Riversong/Game/Unlocks/UnlockDefinition.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
[CreateAssetMenu(fileName = "UnlockDefinition", menuName = "Riversong Code Showcase/Unlock Definition")]
|
||||
public class UnlockDefinition : GameDataAsset
|
||||
{
|
||||
public UnlockType Type;
|
||||
|
||||
[ShowIf("Type", UnlockType.UnlockBuilding)]
|
||||
public BuildingDefinition Building;
|
||||
|
||||
[ShowIf("Type", UnlockType.UnlockBuilding)]
|
||||
public List<BuildingDefinition> TeasedBuildings;
|
||||
|
||||
[TitleGroup("Conditions")]
|
||||
[ShowIf("@this.Type != UnlockType.None")]
|
||||
public List<UnlockCondition> Conditions;
|
||||
}
|
||||
}
|
||||
9
Source/Riversong/Game/Unlocks/UnlockType.cs
Normal file
9
Source/Riversong/Game/Unlocks/UnlockType.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public enum UnlockType
|
||||
{
|
||||
None,
|
||||
|
||||
UnlockBuilding
|
||||
}
|
||||
}
|
||||
12
Source/Riversong/Game/Unlocks/UnlockUnlockedSignal.cs
Normal file
12
Source/Riversong/Game/Unlocks/UnlockUnlockedSignal.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public struct UnlockUnlockedSignal
|
||||
{
|
||||
public UnlockDefinition Unlock;
|
||||
|
||||
public UnlockUnlockedSignal(UnlockDefinition unlock)
|
||||
{
|
||||
Unlock = unlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
155
Source/Riversong/Game/Unlocks/UnlocksManagerSystem.cs
Normal file
155
Source/Riversong/Game/Unlocks/UnlocksManagerSystem.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
[Service(typeof(IUnlocksService))]
|
||||
[InitializeAfter(typeof(HouseTierCountTrackingSystem))]
|
||||
public class UnlocksManagerSystem : GameSystem, IInitializable, IDisposable, IUnlocksService
|
||||
{
|
||||
[InjectService]
|
||||
private IGameDatabase _gameDatabase;
|
||||
|
||||
[InjectService]
|
||||
private ISignalBus _signalBus;
|
||||
|
||||
[InjectService]
|
||||
private IEntityCollection _entityCollection;
|
||||
|
||||
[InjectService]
|
||||
private World _world;
|
||||
|
||||
private List<UnlockDefinition> _unlocks;
|
||||
|
||||
public UnlocksManagerSystem(IServiceLocator serviceLocator) : base(serviceLocator)
|
||||
{
|
||||
}
|
||||
|
||||
public UniTask InitializeAsync()
|
||||
{
|
||||
_unlocks = _gameDatabase.OfType<UnlockDefinition>();
|
||||
|
||||
foreach (var unlock in _unlocks)
|
||||
if (unlock.Building)
|
||||
_world.UnlocksState.AddBuildingUnlock(unlock.Building, unlock.RuntimeId);
|
||||
|
||||
_signalBus.Subscribe<WorldReadySignal>(OnWorldReady);
|
||||
_signalBus.Subscribe<BuildingCreatedSignal>(OnBuildingCreated);
|
||||
_signalBus.Subscribe<BuildingUpgradedSignal>(OnBuildingUpgraded);
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_signalBus.Unsubscribe<WorldReadySignal>(OnWorldReady);
|
||||
_signalBus.Unsubscribe<BuildingCreatedSignal>(OnBuildingCreated);
|
||||
_signalBus.Unsubscribe<BuildingUpgradedSignal>(OnBuildingUpgraded);
|
||||
}
|
||||
|
||||
private void OnWorldReady(WorldReadySignal signal)
|
||||
{
|
||||
_ = GrantFreeUnlocksWithDelayAsync();
|
||||
}
|
||||
|
||||
private async UniTask GrantFreeUnlocksWithDelayAsync()
|
||||
{
|
||||
await UniTask.WaitForSeconds(2, true);
|
||||
|
||||
foreach (var unlock in _unlocks)
|
||||
if (unlock.Conditions.Count <= 0)
|
||||
Unlock(unlock);
|
||||
}
|
||||
|
||||
private void OnBuildingCreated(BuildingCreatedSignal signal)
|
||||
{
|
||||
TryUnlockAvailableUnlocks();
|
||||
}
|
||||
|
||||
private void OnBuildingUpgraded(BuildingUpgradedSignal signal)
|
||||
{
|
||||
TryUnlockAvailableUnlocks();
|
||||
}
|
||||
|
||||
private void TryUnlockAvailableUnlocks()
|
||||
{
|
||||
foreach (var unlock in _unlocks)
|
||||
if (CanUnlock(unlock))
|
||||
Unlock(unlock);
|
||||
}
|
||||
|
||||
private bool CanUnlock(UnlockDefinition unlock)
|
||||
{
|
||||
if (_world.UnlocksState.Unlocked.Contains(unlock.RuntimeId)) return false;
|
||||
|
||||
foreach (var condition in unlock.Conditions)
|
||||
if (!IsConditionSatisfied(condition))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Unlock(UnlockDefinition unlock)
|
||||
{
|
||||
if (!_world.UnlocksState.Unlocked.Add(unlock.RuntimeId)) return;
|
||||
|
||||
switch (unlock.Type)
|
||||
{
|
||||
case UnlockType.UnlockBuilding:
|
||||
UnlockBuilding(unlock);
|
||||
break;
|
||||
|
||||
case UnlockType.None:
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
_signalBus.Raise(new UnlockUnlockedSignal(unlock));
|
||||
}
|
||||
|
||||
public void UnlockAll()
|
||||
{
|
||||
foreach (var unlock in _unlocks) Unlock(unlock);
|
||||
}
|
||||
|
||||
private void UnlockBuilding(UnlockDefinition unlock)
|
||||
{
|
||||
var unlocksState = _world.UnlocksState;
|
||||
var unlockedId = unlock.Building.RuntimeId;
|
||||
|
||||
unlocksState.UnlockedBuildings.Add(unlockedId);
|
||||
unlocksState.TeasedBuildings.Remove(unlockedId);
|
||||
|
||||
foreach (var teased in unlock.TeasedBuildings)
|
||||
{
|
||||
if (unlocksState.UnlockedBuildings.Contains(teased.RuntimeId)) continue;
|
||||
|
||||
unlocksState.TeasedBuildings.Add(teased.RuntimeId);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsConditionSatisfied(UnlockCondition condition)
|
||||
{
|
||||
switch (condition.Type)
|
||||
{
|
||||
case UnlockConditionType.BuildingPlaced:
|
||||
foreach (Building building in _entityCollection.GetInternalEntityList(typeof(Building)))
|
||||
if (building.Definition.RuntimeId == condition.Building.RuntimeId)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
case UnlockConditionType.HouseCountAtTierOrAbove:
|
||||
var houseCount = 0;
|
||||
var houseCountsByTier = _world.PopulationState.HouseCountsByTier;
|
||||
for (var i = condition.MinHouseTierIndex; i < WorldPopulationState.MaxBuildingTier; i++) houseCount += houseCountsByTier[i];
|
||||
|
||||
return houseCount >= condition.HouseCount;
|
||||
|
||||
case UnlockConditionType.None:
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Source/Riversong/Game/Unlocks/UnlocksState.cs
Normal file
25
Source/Riversong/Game/Unlocks/UnlocksState.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class UnlocksState
|
||||
{
|
||||
private Dictionary<int, int> _buildingUnlockLookup = new();
|
||||
|
||||
public HashSet<int> Unlocked { get; } = new();
|
||||
|
||||
public HashSet<int> UnlockedBuildings { get; } = new();
|
||||
|
||||
public HashSet<int> TeasedBuildings { get; } = new();
|
||||
|
||||
public void AddBuildingUnlock(BuildingDefinition building, int unlockId)
|
||||
{
|
||||
_buildingUnlockLookup.Add(building.RuntimeId, unlockId);
|
||||
}
|
||||
|
||||
public bool TryGetBuildingUnlock(BuildingDefinition building, out int unlockId)
|
||||
{
|
||||
return _buildingUnlockLookup.TryGetValue(building.RuntimeId, out unlockId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user