riversong code showcase
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
using Unity.Properties;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class BuildingPanelModel : UIModel
|
||||
{
|
||||
private Building _building;
|
||||
|
||||
private string _buildingName;
|
||||
|
||||
private string _buildingDescription;
|
||||
|
||||
private Sprite _buildingIcon;
|
||||
|
||||
private bool _showNoHouseNearbyWarning;
|
||||
|
||||
public Building Building
|
||||
{
|
||||
get => _building;
|
||||
private set => SetProperty(ref _building, value);
|
||||
}
|
||||
|
||||
[CreateProperty]
|
||||
public string BuildingDescription
|
||||
{
|
||||
get => _buildingDescription;
|
||||
private set => SetProperty(ref _buildingDescription, value);
|
||||
}
|
||||
|
||||
[CreateProperty]
|
||||
public string BuildingName
|
||||
{
|
||||
get => _buildingName;
|
||||
private set => SetProperty(ref _buildingName, value);
|
||||
}
|
||||
|
||||
[CreateProperty]
|
||||
public Sprite BuildingIcon
|
||||
{
|
||||
get => _buildingIcon;
|
||||
private set => SetProperty(ref _buildingIcon, value);
|
||||
}
|
||||
|
||||
[CreateProperty]
|
||||
public bool ShowNoHouseNearbyWarning
|
||||
{
|
||||
get => _showNoHouseNearbyWarning;
|
||||
set => SetProperty(ref _showNoHouseNearbyWarning, value);
|
||||
}
|
||||
|
||||
public HousePanelModel HouseModel { get; } = new();
|
||||
|
||||
public StoragePanelModel StorageModel { get; } = new();
|
||||
|
||||
public void SetBuilding(Building building)
|
||||
{
|
||||
Building = building;
|
||||
BuildingName = Building?.Definition.BuildingName;
|
||||
BuildingDescription = Building?.Definition.BuildingDescription;
|
||||
BuildingIcon = Building?.Definition.Icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class BuildingPanelUIController : UIControllerSystem<BuildingPanelUIView>, IDisposable, IUpdatable
|
||||
{
|
||||
[InjectService]
|
||||
private ISignalBus _signalBus;
|
||||
|
||||
[InjectService]
|
||||
private IProductCatalog _productCatalog;
|
||||
|
||||
[InjectService]
|
||||
private UIState _uiState;
|
||||
|
||||
[InjectService]
|
||||
private World _world;
|
||||
|
||||
private BuildingPanelModel _model;
|
||||
|
||||
private List<IBuildingPanelSectionPresenter> _sectionPresenters;
|
||||
|
||||
public BuildingPanelUIController(IServiceLocator serviceLocator) : base(serviceLocator)
|
||||
{
|
||||
}
|
||||
|
||||
protected override BuildingPanelUIView View => UIRoot.GetView<BuildingPanelUIView>();
|
||||
|
||||
public override async UniTask InitializeAsync()
|
||||
{
|
||||
await base.InitializeAsync();
|
||||
|
||||
_model = new BuildingPanelModel();
|
||||
_sectionPresenters = new List<IBuildingPanelSectionPresenter>
|
||||
{
|
||||
new HouseBuildingPanelSectionPresenter(_productCatalog),
|
||||
new StorageBuildingPanelSectionPresenter(_productCatalog)
|
||||
};
|
||||
|
||||
View.SetModel(_model);
|
||||
View.Show(false);
|
||||
|
||||
_signalBus.Subscribe<SelectedBuildingChangedSignal>(OnSelectedBuildingChanged);
|
||||
_signalBus.Subscribe<BuildingUpgradedSignal>(OnBuildingUpgraded);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_signalBus.Unsubscribe<SelectedBuildingChangedSignal>(OnSelectedBuildingChanged);
|
||||
_signalBus.Unsubscribe<BuildingUpgradedSignal>(OnBuildingUpgraded);
|
||||
}
|
||||
|
||||
private void OnSelectedBuildingChanged(SelectedBuildingChangedSignal signal)
|
||||
{
|
||||
var selectedBuilding = signal.NewSelection;
|
||||
|
||||
if (selectedBuilding != null)
|
||||
{
|
||||
_model.SetBuilding(selectedBuilding);
|
||||
InitializeSections(selectedBuilding);
|
||||
UpdateWorkerHousingWarning(selectedBuilding);
|
||||
}
|
||||
|
||||
View.Show(selectedBuilding != null, true);
|
||||
}
|
||||
|
||||
private void InitializeSections(Building building)
|
||||
{
|
||||
foreach (var sectionPresenter in _sectionPresenters)
|
||||
{
|
||||
if (!sectionPresenter.IsSectionRelevant(building)) continue;
|
||||
sectionPresenter.InitializeSection(_model, building);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
var building = _model.Building;
|
||||
if (building == null) return;
|
||||
|
||||
foreach (var sectionPresenter in _sectionPresenters)
|
||||
{
|
||||
if (!sectionPresenter.IsSectionRelevant(building)) continue;
|
||||
sectionPresenter.UpdateSection(_model, building);
|
||||
}
|
||||
|
||||
UpdateWorkerHousingWarning(building);
|
||||
}
|
||||
|
||||
private void OnBuildingUpgraded(BuildingUpgradedSignal signal)
|
||||
{
|
||||
if (signal.Building != _uiState.SelectedBuilding) return;
|
||||
|
||||
InitializeSections(signal.Building);
|
||||
}
|
||||
|
||||
private void UpdateWorkerHousingWarning(Building building)
|
||||
{
|
||||
_model.ShowNoHouseNearbyWarning = false;
|
||||
|
||||
if (building == null || _world.TimeState.DayNightCycleStep != DayNightCycleStep.Day) return;
|
||||
|
||||
ref var sleepState = ref building.GetSleepStateRW();
|
||||
_model.ShowNoHouseNearbyWarning = sleepState.HasHomelessWorkers;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
[UIView("building-panel")]
|
||||
public class BuildingPanelUIView : UIView<BuildingPanelModel>
|
||||
{
|
||||
private VisualElement _noHouseNearbyWarning;
|
||||
|
||||
private HousePanelUIView _housePanel;
|
||||
|
||||
private StoragePanelUIView _storagePanel;
|
||||
|
||||
public override async UniTask InitializeAsync(UIService uiService, VisualElement rootElement)
|
||||
{
|
||||
await base.InitializeAsync(uiService, rootElement);
|
||||
|
||||
_noHouseNearbyWarning = rootElement.Q<VisualElement>(className: "building-panel__no-house-nearby-warning");
|
||||
|
||||
_housePanel = (HousePanelUIView)await uiService.CreateView(typeof(HousePanelUIView), rootElement.Q(className: "building-panel__house-panel"));
|
||||
_storagePanel = (StoragePanelUIView)await uiService.CreateView(typeof(StoragePanelUIView), rootElement.Q(className: "building-panel__storage-panel"));
|
||||
}
|
||||
|
||||
protected override void OnNewModel(BuildingPanelModel model)
|
||||
{
|
||||
base.OnNewModel(model);
|
||||
|
||||
_housePanel.SetModel(model.HouseModel);
|
||||
_storagePanel.SetModel(model.StorageModel);
|
||||
}
|
||||
|
||||
protected override void OnModelPropertyChanged(object sender, BindablePropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnModelPropertyChanged(sender, e);
|
||||
|
||||
switch (e.propertyName)
|
||||
{
|
||||
case nameof(BuildingPanelModel.Building):
|
||||
_housePanel.Show(Model.Building != null && Model.Building.Definition.IsHouse);
|
||||
_storagePanel.Show(Model.Building != null && Model.Building.Definition.IsStorage);
|
||||
|
||||
UpdateNoHouseNearbyWarning();
|
||||
break;
|
||||
|
||||
case nameof(BuildingPanelModel.ShowNoHouseNearbyWarning):
|
||||
UpdateNoHouseNearbyWarning();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateNoHouseNearbyWarning()
|
||||
{
|
||||
_noHouseNearbyWarning.style.display = Model.Building != null && Model.ShowNoHouseNearbyWarning ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class HouseBuildingPanelSectionPresenter : IBuildingPanelSectionPresenter
|
||||
{
|
||||
private readonly IProductCatalog _productCatalog;
|
||||
|
||||
public HouseBuildingPanelSectionPresenter(IProductCatalog productCatalog)
|
||||
{
|
||||
_productCatalog = productCatalog;
|
||||
}
|
||||
|
||||
public bool IsSectionRelevant(Building building)
|
||||
{
|
||||
return building.Definition.IsHouse;
|
||||
}
|
||||
|
||||
public void InitializeSection(BuildingPanelModel model, Building building)
|
||||
{
|
||||
var tiers = building.Definition.HouseTiers;
|
||||
var tierIndex = building.TierIndex;
|
||||
var maxTier = math.min(tierIndex, tiers.Count - 1);
|
||||
ref var needsState = ref building.GetNeedsStateRW();
|
||||
|
||||
model.HouseModel.Needs.Clear();
|
||||
|
||||
var rowIndex = 0;
|
||||
for (var i = 0; i <= maxTier; i++)
|
||||
{
|
||||
var tier = tiers[i];
|
||||
|
||||
foreach (var need in tier.Needs)
|
||||
{
|
||||
var needModel = new HousePanelNeedModel();
|
||||
|
||||
switch (need.Type)
|
||||
{
|
||||
case PopulationNeedType.Product:
|
||||
needModel.Initialize(rowIndex++, need.Product.ProductName, need.Product.Icon, 0, need.YieldOnFetch);
|
||||
break;
|
||||
}
|
||||
|
||||
model.HouseModel.Needs.Add(needModel);
|
||||
}
|
||||
}
|
||||
|
||||
model.HouseModel.AllNeedsMet = needsState.AllNeedsMet;
|
||||
model.HouseModel.UpgradeState = needsState.UpgradeState;
|
||||
|
||||
model.HouseModel.UpgradeMaterials.Clear();
|
||||
if (tierIndex < tiers.Count)
|
||||
foreach (var productAmount in tiers[tierIndex].UpgradeMaterials)
|
||||
model.HouseModel.UpgradeMaterials.Add(new HousePanelUpgradeMaterialModel(productAmount));
|
||||
|
||||
model.HouseModel.NotifyChanged();
|
||||
}
|
||||
|
||||
public void UpdateSection(BuildingPanelModel model, Building building)
|
||||
{
|
||||
ref var needsState = ref building.GetNeedsStateRW();
|
||||
ref var storage = ref building.GetStorageRW();
|
||||
|
||||
for (var i = 0; i < needsState.Needs.Length; i++)
|
||||
{
|
||||
var need = needsState.Needs[i];
|
||||
if (need.TierIndex > building.TierIndex) break;
|
||||
|
||||
var needModel = model.HouseModel.Needs[i];
|
||||
|
||||
switch (need.Type)
|
||||
{
|
||||
case PopulationNeedType.Product:
|
||||
needModel.UpdateValue(need.Current);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
model.HouseModel.AllNeedsMet = needsState.AllNeedsMet;
|
||||
model.HouseModel.UpgradeState = needsState.UpgradeState;
|
||||
|
||||
foreach (var upgradeMaterialModel in model.HouseModel.UpgradeMaterials)
|
||||
{
|
||||
var productHandle = _productCatalog.GetHandle(upgradeMaterialModel.Product);
|
||||
upgradeMaterialModel.Remaining = math.max(upgradeMaterialModel.Needed - storage.AvailableNow(productHandle), 0);
|
||||
|
||||
upgradeMaterialModel.Done &= needsState.UpgradeState != TierUpgradeState.NotReady;
|
||||
upgradeMaterialModel.Done |= upgradeMaterialModel.Remaining <= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class HousePanelModel : UIModel
|
||||
{
|
||||
private bool _allNeedsMet;
|
||||
|
||||
private TierUpgradeState _upgradeState;
|
||||
|
||||
public List<HousePanelNeedModel> Needs { get; } = new();
|
||||
|
||||
public bool AllNeedsMet
|
||||
{
|
||||
get => _allNeedsMet;
|
||||
set => SetProperty(ref _allNeedsMet, value);
|
||||
}
|
||||
|
||||
public TierUpgradeState UpgradeState
|
||||
{
|
||||
get => _upgradeState;
|
||||
set => SetProperty(ref _upgradeState, value);
|
||||
}
|
||||
|
||||
public List<HousePanelUpgradeMaterialModel> UpgradeMaterials { get; } = new();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Unity.Properties;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class HousePanelNeedModel : UIModel
|
||||
{
|
||||
private int _value;
|
||||
|
||||
private int _max;
|
||||
|
||||
public int RowIndex { get; set; }
|
||||
|
||||
[CreateProperty] public string Name { get; set; }
|
||||
|
||||
[CreateProperty] public Sprite Icon { get; set; }
|
||||
|
||||
[CreateProperty] public int Value { get; set; }
|
||||
|
||||
[CreateProperty] public int Max { get; set; }
|
||||
|
||||
[CreateProperty] public string ValueString => $"{Mathf.RoundToInt(100 * Mathf.Clamp01(Value / (float)Max))}%";
|
||||
|
||||
public void Initialize(int rowIndex, string name, Sprite icon, int value, int max)
|
||||
{
|
||||
RowIndex = rowIndex;
|
||||
Name = name;
|
||||
Icon = icon;
|
||||
Value = value;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public void UpdateValue(int value)
|
||||
{
|
||||
if (Value == value) return;
|
||||
|
||||
Value = value;
|
||||
|
||||
NotifyPropertyChanged(nameof(Value));
|
||||
NotifyPropertyChanged(nameof(ValueString));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class HousePanelNeedUIView : UIView<HousePanelNeedModel>
|
||||
{
|
||||
private VisualElement _valueBarFill;
|
||||
|
||||
public override UniTask InitializeAsync(UIService uiService, VisualElement rootElement)
|
||||
{
|
||||
base.InitializeAsync(uiService, rootElement);
|
||||
|
||||
_valueBarFill = rootElement.Q<VisualElement>(className: "house-panel__need-value-bar-fill");
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
protected override void OnNewModel(HousePanelNeedModel model)
|
||||
{
|
||||
base.OnNewModel(model);
|
||||
|
||||
if (model.RowIndex % 2 == 0) RootElement.Q(className: "house-panel__need").AddToClassList("alt");
|
||||
|
||||
UpdateValueBar();
|
||||
}
|
||||
|
||||
protected override void OnModelPropertyChanged(object sender, BindablePropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnModelPropertyChanged(sender, e);
|
||||
|
||||
switch (e.propertyName)
|
||||
{
|
||||
case nameof(HousePanelNeedModel.Value):
|
||||
UpdateValueBar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateValueBar()
|
||||
{
|
||||
var fillPercent = math.clamp((float)Model.Value / Model.Max, 0, 1) * 100;
|
||||
_valueBarFill.style.width = Length.Percent(fillPercent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class HousePanelUIView : UIView<HousePanelModel>
|
||||
{
|
||||
private VisualElement _needs;
|
||||
|
||||
private Label _notReadyNeedsNotMetLabel;
|
||||
|
||||
private Label _notReadyNeedsMetLabel;
|
||||
|
||||
private Label _fetchingMaterialsLabel;
|
||||
|
||||
private Label _maxedOutLabel;
|
||||
|
||||
private VisualElement _upgradeMaterials;
|
||||
|
||||
public override UniTask InitializeAsync(UIService uiService, VisualElement rootElement)
|
||||
{
|
||||
base.InitializeAsync(uiService, rootElement);
|
||||
|
||||
_needs = rootElement.Q<VisualElement>(className: "house-panel__needs");
|
||||
_notReadyNeedsNotMetLabel = rootElement.Q<Label>(className: "house-panel__not-ready-needs-not-met");
|
||||
_notReadyNeedsMetLabel = rootElement.Q<Label>(className: "house-panel__not-ready-needs-met");
|
||||
_fetchingMaterialsLabel = rootElement.Q<Label>(className: "house-panel__fetching-materials");
|
||||
_maxedOutLabel = rootElement.Q<Label>(className: "house-panel__maxed-out");
|
||||
_upgradeMaterials = rootElement.Q<VisualElement>(className: "house-panel__upgrade-materials");
|
||||
|
||||
_ = AnimateHouseUpgradeStatusAsync();
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
protected override void OnModelChanged()
|
||||
{
|
||||
base.OnModelChanged();
|
||||
|
||||
_ = CreateNeedViewsAsync();
|
||||
_ = CreateUpgradeMaterialViewsAsync();
|
||||
UpdateUpgradeState();
|
||||
}
|
||||
|
||||
private async UniTask CreateNeedViewsAsync()
|
||||
{
|
||||
var template = UIService.TemplateLibrary.BuildingPanel.Need;
|
||||
await UIService.CreateViews<HousePanelNeedModel, HousePanelNeedUIView>(Model.Needs, _needs, template);
|
||||
}
|
||||
|
||||
private async UniTask CreateUpgradeMaterialViewsAsync()
|
||||
{
|
||||
var template = UIService.TemplateLibrary.BuildingPanel.UpgradeMaterial;
|
||||
await UIService.CreateViews<HousePanelUpgradeMaterialModel, HousePanelUpgradeMaterialUIView>(Model.UpgradeMaterials, _upgradeMaterials, template);
|
||||
}
|
||||
|
||||
private void UpdateUpgradeState()
|
||||
{
|
||||
_notReadyNeedsNotMetLabel.style.display = DisplayStyle.None;
|
||||
_notReadyNeedsMetLabel.style.display = DisplayStyle.None;
|
||||
_fetchingMaterialsLabel.style.display = DisplayStyle.None;
|
||||
_maxedOutLabel.style.display = DisplayStyle.None;
|
||||
|
||||
switch (Model.UpgradeState)
|
||||
{
|
||||
case TierUpgradeState.NotReady:
|
||||
_notReadyNeedsNotMetLabel.style.display = Model.AllNeedsMet ? DisplayStyle.None : DisplayStyle.Flex;
|
||||
_notReadyNeedsMetLabel.style.display = Model.AllNeedsMet ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
break;
|
||||
|
||||
case TierUpgradeState.FetchingMaterials:
|
||||
case TierUpgradeState.AllMaterialsFetched:
|
||||
_fetchingMaterialsLabel.style.display = DisplayStyle.Flex;
|
||||
break;
|
||||
|
||||
case TierUpgradeState.MaxedOut:
|
||||
_maxedOutLabel.style.display = DisplayStyle.Flex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnModelPropertyChanged(object sender, BindablePropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnModelPropertyChanged(sender, e);
|
||||
|
||||
switch (e.propertyName)
|
||||
{
|
||||
case nameof(HousePanelModel.AllNeedsMet):
|
||||
case nameof(HousePanelModel.UpgradeState):
|
||||
UpdateUpgradeState();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask AnimateHouseUpgradeStatusAsync()
|
||||
{
|
||||
_fetchingMaterialsLabel.text = _fetchingMaterialsLabel.text.Replace(".", string.Empty);
|
||||
|
||||
var i = 0;
|
||||
|
||||
while (_fetchingMaterialsLabel.panel != null)
|
||||
{
|
||||
await UniTask.WaitForSeconds(1, true);
|
||||
|
||||
var text = _fetchingMaterialsLabel.text;
|
||||
|
||||
text = text.Substring(0, text.Length - i);
|
||||
|
||||
i = (i + 1) % 4;
|
||||
if (i > 0) text += new string('.', i);
|
||||
|
||||
_fetchingMaterialsLabel.text = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using Unity.Properties;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class HousePanelUpgradeMaterialModel : UIModel
|
||||
{
|
||||
private int _remaining;
|
||||
|
||||
private bool _done;
|
||||
|
||||
public HousePanelUpgradeMaterialModel(ProductDefinition product, int needed)
|
||||
{
|
||||
Product = product;
|
||||
Needed = needed;
|
||||
}
|
||||
|
||||
public HousePanelUpgradeMaterialModel(IProductAmount productAmount) : this(productAmount.Product, productAmount.Amount)
|
||||
{
|
||||
}
|
||||
|
||||
public ProductDefinition Product { get; }
|
||||
|
||||
[CreateProperty] public Sprite Icon => Product.Icon;
|
||||
|
||||
[CreateProperty]
|
||||
public int Remaining
|
||||
{
|
||||
get => _remaining;
|
||||
set => SetProperty(ref _remaining, value);
|
||||
}
|
||||
|
||||
[CreateProperty] public int Needed { get; }
|
||||
|
||||
[CreateProperty]
|
||||
public bool Done
|
||||
{
|
||||
get => _done;
|
||||
set => SetProperty(ref _done, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class HousePanelUpgradeMaterialUIView : UIView<HousePanelUpgradeMaterialModel>
|
||||
{
|
||||
private VisualElement _remaining;
|
||||
|
||||
private VisualElement _checkIcon;
|
||||
|
||||
public override UniTask InitializeAsync(UIService uiService, VisualElement rootElement)
|
||||
{
|
||||
base.InitializeAsync(uiService, rootElement);
|
||||
|
||||
_remaining = rootElement.Q<VisualElement>(className: "house-panel__remaining");
|
||||
|
||||
_checkIcon = rootElement.Q<VisualElement>(className: "house-panel__upgrade-material-check");
|
||||
_checkIcon.style.display = DisplayStyle.None;
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
protected override void OnModelPropertyChanged(object sender, BindablePropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnModelPropertyChanged(sender, e);
|
||||
|
||||
switch (e.propertyName)
|
||||
{
|
||||
case nameof(HousePanelUpgradeMaterialModel.Done):
|
||||
_remaining.style.display = Model.Done ? DisplayStyle.None : DisplayStyle.Flex;
|
||||
_checkIcon.style.display = Model.Done ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public interface IBuildingPanelSectionPresenter
|
||||
{
|
||||
bool IsSectionRelevant(Building building);
|
||||
|
||||
void InitializeSection(BuildingPanelModel model, Building building);
|
||||
|
||||
void UpdateSection(BuildingPanelModel model, Building building);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class StorageBuildingPanelSectionPresenter : IBuildingPanelSectionPresenter
|
||||
{
|
||||
private const int RequestedAmountLargeDelta = 5;
|
||||
|
||||
private readonly IProductCatalog _productCatalog;
|
||||
|
||||
public StorageBuildingPanelSectionPresenter(IProductCatalog productCatalog)
|
||||
{
|
||||
_productCatalog = productCatalog;
|
||||
}
|
||||
|
||||
public bool IsSectionRelevant(Building building)
|
||||
{
|
||||
return building.Definition.IsStorage;
|
||||
}
|
||||
|
||||
public void InitializeSection(BuildingPanelModel model, Building building)
|
||||
{
|
||||
model.StorageModel.Products.Clear();
|
||||
|
||||
for (var productHandle = 0; productHandle < _productCatalog.ProductTypeCount; productHandle++)
|
||||
{
|
||||
var productModel = new StoragePanelProductModel();
|
||||
|
||||
productModel.Initialize(
|
||||
productHandle,
|
||||
productHandle,
|
||||
_productCatalog.GetProduct(productHandle),
|
||||
() => ToggleAllowTaking(building, productModel),
|
||||
() => ToggleCanFulfillRequests(building, productModel),
|
||||
() => ChangeRequestedAmount(building, productModel, Keyboard.current.shiftKey.isPressed ? -RequestedAmountLargeDelta : -1),
|
||||
() => ChangeRequestedAmount(building, productModel, Keyboard.current.shiftKey.isPressed ? RequestedAmountLargeDelta : 1));
|
||||
|
||||
model.StorageModel.Products.Add(productModel);
|
||||
}
|
||||
|
||||
UpdateSection(model, building);
|
||||
|
||||
model.StorageModel.NotifyChanged();
|
||||
}
|
||||
|
||||
public void UpdateSection(BuildingPanelModel model, Building building)
|
||||
{
|
||||
ref var storage = ref building.GetStorageRW();
|
||||
ref var storagePolicy = ref building.GetProductStoragePolicyRW();
|
||||
|
||||
foreach (var productModel in model.StorageModel.Products)
|
||||
{
|
||||
var productHandle = productModel.ProductHandle;
|
||||
|
||||
productModel.AvailableNow = storage.AvailableNow(productHandle);
|
||||
productModel.InputBlocked = !storagePolicy.IsTakingAllowed(productHandle);
|
||||
productModel.CanFulfillRequests = storagePolicy.CanFulfillRequests(productHandle);
|
||||
productModel.RequestedAmount = storagePolicy.GetRequestedAmount(productHandle);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ToggleAllowTaking(Building building, StoragePanelProductModel productModel)
|
||||
{
|
||||
ref var storagePolicy = ref building.GetProductStoragePolicyRW();
|
||||
|
||||
var isTakingAllowed = storagePolicy.IsTakingAllowed(productModel.ProductHandle);
|
||||
|
||||
storagePolicy.SetAllowTaking(productModel.ProductHandle, !isTakingAllowed);
|
||||
productModel.InputBlocked = isTakingAllowed;
|
||||
}
|
||||
|
||||
private static void ToggleCanFulfillRequests(Building building, StoragePanelProductModel productModel)
|
||||
{
|
||||
ref var storagePolicy = ref building.GetProductStoragePolicyRW();
|
||||
|
||||
var canFulfillRequests = storagePolicy.CanFulfillRequests(productModel.ProductHandle);
|
||||
|
||||
storagePolicy.SetCanFulfillRequests(productModel.ProductHandle, !canFulfillRequests);
|
||||
productModel.CanFulfillRequests = !canFulfillRequests;
|
||||
}
|
||||
|
||||
private static void ChangeRequestedAmount(Building building, StoragePanelProductModel productModel, int delta)
|
||||
{
|
||||
ref var storage = ref building.GetStorageRW();
|
||||
ref var storagePolicy = ref building.GetProductStoragePolicyRW();
|
||||
|
||||
var requestedAmount = storagePolicy.GetRequestedAmount(productModel.ProductHandle) + delta;
|
||||
requestedAmount = Mathf.Clamp(requestedAmount, 0, storage.Capacity);
|
||||
|
||||
storagePolicy.SetRequestedAmount(productModel.ProductHandle, requestedAmount);
|
||||
productModel.RequestedAmount = requestedAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class StoragePanelModel : UIModel
|
||||
{
|
||||
public List<StoragePanelProductModel> Products { get; } = new();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using Unity.Properties;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class StoragePanelProductModel : UIModel
|
||||
{
|
||||
private int _availableNow;
|
||||
|
||||
private bool _inputBlocked;
|
||||
|
||||
private bool _canFulfillRequests;
|
||||
|
||||
private int _requestedAmount;
|
||||
|
||||
public int RowIndex { get; set; }
|
||||
|
||||
public int ProductHandle { get; private set; }
|
||||
|
||||
[CreateProperty] public string Name { get; private set; }
|
||||
|
||||
[CreateProperty] public Sprite Icon { get; private set; }
|
||||
|
||||
[CreateProperty]
|
||||
public int AvailableNow
|
||||
{
|
||||
get => _availableNow;
|
||||
set => SetProperty(ref _availableNow, value);
|
||||
}
|
||||
|
||||
public bool InputBlocked
|
||||
{
|
||||
get => _inputBlocked;
|
||||
set => SetProperty(ref _inputBlocked, value);
|
||||
}
|
||||
|
||||
public bool CanFulfillRequests
|
||||
{
|
||||
get => _canFulfillRequests;
|
||||
set => SetProperty(ref _canFulfillRequests, value);
|
||||
}
|
||||
|
||||
[CreateProperty]
|
||||
public int RequestedAmount
|
||||
{
|
||||
get => _requestedAmount;
|
||||
set => SetProperty(ref _requestedAmount, value);
|
||||
}
|
||||
|
||||
public Action ToggleInputBlockedCallback { get; private set; }
|
||||
|
||||
public Action ToggleCanFulfillRequestsCallback { get; private set; }
|
||||
|
||||
public Action DecreaseRequestedAmountCallback { get; private set; }
|
||||
|
||||
public Action IncreaseRequestedAmountCallback { get; private set; }
|
||||
|
||||
public void Initialize(int rowIndex,
|
||||
int productHandle,
|
||||
ProductDefinition product,
|
||||
Action toggleAllowTakingCallback,
|
||||
Action toggleCanFulfillRequestsCallback,
|
||||
Action decreaseRequestedAmountCallback,
|
||||
Action increaseRequestedAmountCallback)
|
||||
{
|
||||
RowIndex = rowIndex;
|
||||
ProductHandle = productHandle;
|
||||
Name = product.ProductName;
|
||||
Icon = product.Icon;
|
||||
ToggleInputBlockedCallback = toggleAllowTakingCallback;
|
||||
ToggleCanFulfillRequestsCallback = toggleCanFulfillRequestsCallback;
|
||||
DecreaseRequestedAmountCallback = decreaseRequestedAmountCallback;
|
||||
IncreaseRequestedAmountCallback = increaseRequestedAmountCallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class StoragePanelProductUIView : UIView<StoragePanelProductModel>
|
||||
{
|
||||
private VisualElement _inputBlockedButton;
|
||||
|
||||
private VisualElement _fulfillRequestsButton;
|
||||
|
||||
private Button _decreaseRequestedAmountButton;
|
||||
|
||||
private Button _increaseRequestedAmountButton;
|
||||
|
||||
public override UniTask InitializeAsync(UIService uiService, VisualElement rootElement)
|
||||
{
|
||||
base.InitializeAsync(uiService, rootElement);
|
||||
|
||||
_inputBlockedButton = rootElement.Q(className: "storage-panel__product-input-block-button");
|
||||
_fulfillRequestsButton = rootElement.Q(className: "storage-panel__product-fulfill-requests-button");
|
||||
_decreaseRequestedAmountButton = rootElement.Q<Button>(className: "storage-panel__product-requested-amount-button-minus");
|
||||
_increaseRequestedAmountButton = rootElement.Q<Button>(className: "storage-panel__product-requested-amount-button-plus");
|
||||
|
||||
_inputBlockedButton.RegisterCallback<ClickEvent>(OnInputBlockedClick);
|
||||
_fulfillRequestsButton.RegisterCallback<ClickEvent>(OnFulfillRequestsClick);
|
||||
_decreaseRequestedAmountButton.RegisterCallback<ClickEvent>(OnDecreaseRequestedAmountClick);
|
||||
_increaseRequestedAmountButton.RegisterCallback<ClickEvent>(OnIncreaseRequestedAmountClick);
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
protected override void OnNewModel(StoragePanelProductModel model)
|
||||
{
|
||||
base.OnNewModel(model);
|
||||
|
||||
if (model.RowIndex % 2 == 0) RootElement.Q(className: "storage-panel__product").AddToClassList("alt");
|
||||
|
||||
UpdateSelectedState();
|
||||
}
|
||||
|
||||
protected override void OnModelPropertyChanged(object sender, BindablePropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnModelPropertyChanged(sender, e);
|
||||
|
||||
switch (e.propertyName)
|
||||
{
|
||||
case nameof(StoragePanelProductModel.InputBlocked):
|
||||
case nameof(StoragePanelProductModel.CanFulfillRequests):
|
||||
UpdateSelectedState();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInputBlockedClick(ClickEvent evt)
|
||||
{
|
||||
Model.ToggleInputBlockedCallback?.Invoke();
|
||||
}
|
||||
|
||||
private void OnFulfillRequestsClick(ClickEvent evt)
|
||||
{
|
||||
Model.ToggleCanFulfillRequestsCallback?.Invoke();
|
||||
}
|
||||
|
||||
private void OnDecreaseRequestedAmountClick(ClickEvent evt)
|
||||
{
|
||||
Model.DecreaseRequestedAmountCallback?.Invoke();
|
||||
}
|
||||
|
||||
private void OnIncreaseRequestedAmountClick(ClickEvent evt)
|
||||
{
|
||||
Model.IncreaseRequestedAmountCallback?.Invoke();
|
||||
}
|
||||
|
||||
private void UpdateSelectedState()
|
||||
{
|
||||
UpdateSelected(_inputBlockedButton, Model.InputBlocked);
|
||||
UpdateSelected(_fulfillRequestsButton, Model.CanFulfillRequests);
|
||||
}
|
||||
|
||||
private static void UpdateSelected(VisualElement element, bool isSelected)
|
||||
{
|
||||
if (isSelected)
|
||||
element.AddToClassList("selected");
|
||||
else
|
||||
element.RemoveFromClassList("selected");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class StoragePanelUIView : UIView<StoragePanelModel>
|
||||
{
|
||||
private VisualElement _products;
|
||||
|
||||
public override UniTask InitializeAsync(UIService uiService, VisualElement rootElement)
|
||||
{
|
||||
base.InitializeAsync(uiService, rootElement);
|
||||
|
||||
_products = rootElement.Q<VisualElement>(className: "storage-panel__products");
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
protected override void OnModelChanged()
|
||||
{
|
||||
base.OnModelChanged();
|
||||
|
||||
var template = UIService.TemplateLibrary.BuildingPanel.StorageProduct;
|
||||
_ = UIService.CreateViews<StoragePanelProductModel, StoragePanelProductUIView>(Model.Products, _products, template);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user