commit d78ae93c97f614fe1e27144f3bd40a5ec61bb93e Author: Lachlan Leone Date: Sat Jan 20 20:00:35 2024 +1100 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..85673c6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,436 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + +# Workshop folder compiled dll +/WorkshopFolder/content/**/*.dll + +# Common IntelliJ Platform excludes + +# User specific +**/.idea/**/workspace.xml +**/.idea/**/tasks.xml +**/.idea/shelf/* +**/.idea/dictionaries +**/.idea/httpRequests/ + +# Sensitive or high-churn files +**/.idea/**/dataSources/ +**/.idea/**/dataSources.ids +**/.idea/**/dataSources.xml +**/.idea/**/dataSources.local.xml +**/.idea/**/sqlDataSources.xml +**/.idea/**/dynamic.xml + +# Rider +# Rider auto-generates .iml files, and contentModel.xml +**/.idea/**/*.iml +**/.idea/**/contentModel.xml +**/.idea/**/modules.xml +.idea/ + +*.suo +*.user +.vs/ +[Bb]in/ +[Oo]bj/ +_UpgradeReport_Files/ +[Pp]ackages/ + +Thumbs.db +Desktop.ini +.DS_Store \ No newline at end of file diff --git a/Components/CCurrentSpeed.cs b/Components/CCurrentSpeed.cs new file mode 100644 index 0000000..7b1394e --- /dev/null +++ b/Components/CCurrentSpeed.cs @@ -0,0 +1,9 @@ +using KitchenMods; + +namespace Pets.Components +{ + public struct CCurrentSpeed : IModComponent + { + public float speed; + } +} \ No newline at end of file diff --git a/Components/CDefaultState.cs b/Components/CDefaultState.cs new file mode 100644 index 0000000..e28db5c --- /dev/null +++ b/Components/CDefaultState.cs @@ -0,0 +1,15 @@ +using KitchenMods; +using Pets.Enums; + +namespace Pets.Components +{ + public struct CDefaultState : IModComponent + { + public CDefaultState(PetState state) + { + State = state; + } + + public readonly PetState State; + } +} \ No newline at end of file diff --git a/Components/CDisplayPet.cs b/Components/CDisplayPet.cs new file mode 100644 index 0000000..7aedf97 --- /dev/null +++ b/Components/CDisplayPet.cs @@ -0,0 +1,9 @@ +using KitchenMods; + +namespace Pets.Components +{ + public struct CDisplayPet : IModComponent + { + public int index; + } +} \ No newline at end of file diff --git a/Components/CHasDisplayPet.cs b/Components/CHasDisplayPet.cs new file mode 100644 index 0000000..d8ccf40 --- /dev/null +++ b/Components/CHasDisplayPet.cs @@ -0,0 +1,9 @@ +using KitchenMods; + +namespace Pets.Components +{ + public struct CHasDisplayPet : IModComponent + { + + } +} \ No newline at end of file diff --git a/Components/CPet.cs b/Components/CPet.cs new file mode 100644 index 0000000..090f3cf --- /dev/null +++ b/Components/CPet.cs @@ -0,0 +1,15 @@ +using Pets.Enums; +using Unity.Collections; +using Unity.Entities; + +namespace Pets.Components +{ + public struct CPet : IComponentData + { + public PetState State; + public Entity Owner; + public int PetLinkId; + public int PetType; + public FixedString64 PetName; + } +} \ No newline at end of file diff --git a/Components/CPetBed.cs b/Components/CPetBed.cs new file mode 100644 index 0000000..5eb382d --- /dev/null +++ b/Components/CPetBed.cs @@ -0,0 +1,10 @@ +using KitchenData; +using KitchenMods; + +namespace Pets.Components +{ + public struct CPetBed : IModComponent, IApplianceProperty + { + + } +} \ No newline at end of file diff --git a/Components/CRequestNameChange.cs b/Components/CRequestNameChange.cs new file mode 100644 index 0000000..8066966 --- /dev/null +++ b/Components/CRequestNameChange.cs @@ -0,0 +1,10 @@ +using KitchenMods; + +namespace Pets.Components +{ + public struct CRequestNameChange : IModComponent + { + public int Source; + public bool IsTriggered; + } +} \ No newline at end of file diff --git a/Components/CRequestStateChange.cs b/Components/CRequestStateChange.cs new file mode 100644 index 0000000..47e3a0d --- /dev/null +++ b/Components/CRequestStateChange.cs @@ -0,0 +1,10 @@ +using KitchenMods; + +namespace Pets.Components +{ + public struct CRequestStateChange : IModComponent + { + public int PlayerID; + public int StateID; + } +} \ No newline at end of file diff --git a/Components/Creation/CLinkedPet.cs b/Components/Creation/CLinkedPet.cs new file mode 100644 index 0000000..4e1fbcd --- /dev/null +++ b/Components/Creation/CLinkedPet.cs @@ -0,0 +1,12 @@ +using KitchenMods; +using Unity.Entities; + +namespace Pets.Components.Creation +{ + public struct CLinkedPet : IModComponent + { + public int PetType; + public Entity PetEntity; + public int PetLinkId; + } +} \ No newline at end of file diff --git a/Components/Creation/CRequestedPet.cs b/Components/Creation/CRequestedPet.cs new file mode 100644 index 0000000..5fcd66a --- /dev/null +++ b/Components/Creation/CRequestedPet.cs @@ -0,0 +1,10 @@ +using KitchenMods; + +namespace Pets.Components.Creation +{ + public struct CRequestedPet : IModComponent + { + public int player; + public int pet; + } +} \ No newline at end of file diff --git a/Components/Creation/CRequiresPet.cs b/Components/Creation/CRequiresPet.cs new file mode 100644 index 0000000..890248d --- /dev/null +++ b/Components/Creation/CRequiresPet.cs @@ -0,0 +1,9 @@ +using KitchenMods; + +namespace Pets.Components.Creation +{ + public struct CRequiresPet : IModComponent + { + public int PetType; + } +} \ No newline at end of file diff --git a/Components/Menu/CPetEditorInfo.cs b/Components/Menu/CPetEditorInfo.cs new file mode 100644 index 0000000..9c17e50 --- /dev/null +++ b/Components/Menu/CPetEditorInfo.cs @@ -0,0 +1,11 @@ +using Kitchen; +using KitchenMods; + +namespace Pets.Components.Menu +{ + public struct CPetEditorInfo : IModComponent + { + public InputIdentifier Player; + public bool IsComplete; + } +} \ No newline at end of file diff --git a/Components/Menu/CTriggerPetEditor.cs b/Components/Menu/CTriggerPetEditor.cs new file mode 100644 index 0000000..09f5d2b --- /dev/null +++ b/Components/Menu/CTriggerPetEditor.cs @@ -0,0 +1,11 @@ +using KitchenMods; +using Unity.Entities; + +namespace Pets.Components.Menu +{ + public struct CTriggerPetEditor : IModComponent + { + public bool IsTriggered; + public Entity TriggerEntity; + } +} \ No newline at end of file diff --git a/Components/Properties/CActivities.cs b/Components/Properties/CActivities.cs new file mode 100644 index 0000000..4b2e14f --- /dev/null +++ b/Components/Properties/CActivities.cs @@ -0,0 +1,10 @@ +using Pets.Interfaces; +using Unity.Collections; + +namespace Pets.Components.Properties +{ + public struct CActivities : IPetProperty + { + public FixedListInt64 Activities; + } +} \ No newline at end of file diff --git a/Components/Properties/CLonelyDistance.cs b/Components/Properties/CLonelyDistance.cs new file mode 100644 index 0000000..9227ca4 --- /dev/null +++ b/Components/Properties/CLonelyDistance.cs @@ -0,0 +1,14 @@ +using Pets.Interfaces; + +namespace Pets.Components.Properties +{ + public struct CLonelyDistance : IPetProperty + { + public float Distance; + + public CLonelyDistance() + { + Distance = 4.5f; + } + } +} \ No newline at end of file diff --git a/Components/Properties/CPreferredFoods.cs b/Components/Properties/CPreferredFoods.cs new file mode 100644 index 0000000..cd870ba --- /dev/null +++ b/Components/Properties/CPreferredFoods.cs @@ -0,0 +1,10 @@ +using Pets.Interfaces; +using Unity.Collections; + +namespace Pets.Components.Properties +{ + public struct CPreferredFoods : IPetProperty + { + public FixedListInt32 PreferredFoods; + } +} \ No newline at end of file diff --git a/Components/Properties/CRoamNearOwner.cs b/Components/Properties/CRoamNearOwner.cs new file mode 100644 index 0000000..0bd5e1b --- /dev/null +++ b/Components/Properties/CRoamNearOwner.cs @@ -0,0 +1,14 @@ +using Pets.Interfaces; + +namespace Pets.Components.Properties +{ + public struct CRoamNearOwner : IPetProperty + { + public float Distance; + + public CRoamNearOwner() + { + Distance = 3; + } + } +} \ No newline at end of file diff --git a/Components/Properties/CSleepingPositionOffset.cs b/Components/Properties/CSleepingPositionOffset.cs new file mode 100644 index 0000000..8e2724b --- /dev/null +++ b/Components/Properties/CSleepingPositionOffset.cs @@ -0,0 +1,10 @@ +using Pets.Interfaces; +using UnityEngine; + +namespace Pets.Components.Properties +{ + public struct CSleepingPositionOffset : IPetProperty + { + public Vector2 Offset; + } +} \ No newline at end of file diff --git a/Components/Properties/CStandBackFromFood.cs b/Components/Properties/CStandBackFromFood.cs new file mode 100644 index 0000000..2f84eff --- /dev/null +++ b/Components/Properties/CStandBackFromFood.cs @@ -0,0 +1,9 @@ +using Pets.Interfaces; + +namespace Pets.Components.Properties +{ + public struct CStandBackFromFood : IPetProperty + { + public float Distance; + } +} \ No newline at end of file diff --git a/Components/Properties/CStapleAppliances.cs b/Components/Properties/CStapleAppliances.cs new file mode 100644 index 0000000..e79850f --- /dev/null +++ b/Components/Properties/CStapleAppliances.cs @@ -0,0 +1,10 @@ +using Pets.Interfaces; +using Unity.Collections; + +namespace Pets.Components.Properties +{ + public struct CStapleAppliances : IPetProperty + { + public FixedListInt64 Appliances; + } +} \ No newline at end of file diff --git a/Components/SPetRequestView.cs b/Components/SPetRequestView.cs new file mode 100644 index 0000000..2542dbc --- /dev/null +++ b/Components/SPetRequestView.cs @@ -0,0 +1,9 @@ +using KitchenMods; + +namespace Pets.Components +{ + public struct SPetRequestView : IModComponent + { + + } +} \ No newline at end of file diff --git a/Components/Status/COccupiedByPet.cs b/Components/Status/COccupiedByPet.cs new file mode 100644 index 0000000..6516f18 --- /dev/null +++ b/Components/Status/COccupiedByPet.cs @@ -0,0 +1,9 @@ +using KitchenMods; + +namespace Pets.Components.Status +{ + public struct COccupiedByPet : IModComponent + { + + } +} \ No newline at end of file diff --git a/Components/Status/CPetInteractingWith.cs b/Components/Status/CPetInteractingWith.cs new file mode 100644 index 0000000..8e6af78 --- /dev/null +++ b/Components/Status/CPetInteractingWith.cs @@ -0,0 +1,13 @@ +using KitchenMods; +using Unity.Entities; + +namespace Pets.Components.Status +{ + public struct CPetInteractingWith : IComponentData, IModComponent + { + public Entity InteractingWith; + public long StartTime; + public long TimeToFinish; + public bool IsWaitingForDestination; + } +} \ No newline at end of file diff --git a/Customs/Appliances/PetBed.cs b/Customs/Appliances/PetBed.cs new file mode 100644 index 0000000..7538c62 --- /dev/null +++ b/Customs/Appliances/PetBed.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using KitchenData; +using KitchenLib.Customs; +using KitchenLib.Utils; +using Pets.Components; +using UnityEngine; + +namespace Pets.Customs +{ + public class PetBed : CustomAppliance + { + public override string UniqueNameID => "PetBed"; + public override GameObject Prefab => Mod.Bundle.LoadAsset("PetBed").AssignMaterialsByNames(); + public override string Name => "Pet Bed"; + public override List Properties => new List + { + new CPetBed() + }; + } +} \ No newline at end of file diff --git a/Customs/Appliances/PetLetter.cs b/Customs/Appliances/PetLetter.cs new file mode 100644 index 0000000..7db819c --- /dev/null +++ b/Customs/Appliances/PetLetter.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Kitchen; +using KitchenData; +using KitchenLib.Customs; +using KitchenLib.References; +using KitchenLib.Utils; +using UnityEngine; + +namespace Pets.Customs +{ + public class PetLetter : CustomAppliance + { + public override string UniqueNameID => "PetLetter"; + + public override GameObject Prefab => Mod.Bundle.LoadAsset("PetLetter").AssignMaterialsByNames(); + + public override List Properties => new List + { + new CFixedRotation(), + new CImmovable() + }; + + public override void OnRegister(Appliance gameDataObject) + { + base.OnRegister(gameDataObject); + LetterView view = gameDataObject.Prefab.AddComponent(); + Appliance Letter = GDOUtils.GetExistingGDO(ApplianceReferences.BlueprintLetter) as Appliance; + view.Animator = gameDataObject.Prefab.GetComponent(); + view.Letter = GameObjectUtils.GetChild(gameDataObject.Prefab, "Letter"); + view.MinDelay = 0; + view.MaxDelay = 2; + } + } +} \ No newline at end of file diff --git a/Customs/Cat.cs b/Customs/Cat.cs new file mode 100644 index 0000000..fe76130 --- /dev/null +++ b/Customs/Cat.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using KitchenLib.Utils; +using Pets.Components.Properties; +using Pets.Customs.Types; +using Pets.Enums; +using Pets.Interfaces; +using Unity.Collections; +using UnityEngine; + +namespace Pets.Customs +{ + public class Cat : CustomPet + { + public override string UniqueNameID => "Cat"; + public override GameObject Prefab => Mod.Bundle.LoadAsset("Cat").AssignMaterialsByNames(); + public override GameObject IconPrefab => Mod.Bundle.LoadAsset("CatIcon").AssignMaterialsByNames(); + public override PetState DefaultState => PetState.Follow; + + public override List Properties { get; protected set; } = new List() + { + new CActivities + { + Activities = new FixedListInt64 + { + (int)PetState.Follow, + (int)PetState.Eat, + (int)PetState.Sleep, + } + }, + new CRoamNearOwner(), + new CStapleAppliances + { + Appliances = new FixedListInt64 + { + GDOUtils.GetCustomGameDataObject().ID + } + } + }; + } +} \ No newline at end of file diff --git a/Customs/Chick.cs b/Customs/Chick.cs new file mode 100644 index 0000000..152d236 --- /dev/null +++ b/Customs/Chick.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using KitchenLib.Utils; +using Pets.Components.Properties; +using Pets.Customs.Types; +using Pets.Enums; +using Pets.Interfaces; +using Unity.Collections; +using UnityEngine; + +namespace Pets.Customs +{ + public class Chick : CustomPet + { + public override string UniqueNameID => "Chick"; + public override GameObject Prefab => Mod.Bundle.LoadAsset("Chick").AssignMaterialsByNames(); + public override GameObject IconPrefab => Mod.Bundle.LoadAsset("ChickIcon").AssignMaterialsByNames(); + public override PetState DefaultState => PetState.Follow; + + public override List Properties { get; protected set; } = new List() + { + new CActivities + { + Activities = new FixedListInt64 + { + (int)PetState.Follow, + (int)PetState.Eat, + (int)PetState.Sleep, + } + }, + new CRoamNearOwner(), + new CStapleAppliances + { + Appliances = new FixedListInt64 + { + GDOUtils.GetCustomGameDataObject().ID + } + } + }; + } +} \ No newline at end of file diff --git a/Customs/DogChihuahua.cs b/Customs/DogChihuahua.cs new file mode 100644 index 0000000..9cb6a75 --- /dev/null +++ b/Customs/DogChihuahua.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using KitchenLib.Utils; +using Pets.Components.Properties; +using Pets.Customs.Types; +using Pets.Enums; +using Pets.Interfaces; +using Unity.Collections; +using UnityEngine; + +namespace Pets.Customs +{ + public class DogChihuahua : CustomPet + { + public override string UniqueNameID => "DogChihuahua"; + public override GameObject Prefab => Mod.Bundle.LoadAsset("DogChihuahua").AssignMaterialsByNames(); + public override GameObject IconPrefab => Mod.Bundle.LoadAsset("DogChihuahuaIcon").AssignMaterialsByNames(); + public override PetState DefaultState => PetState.Follow; + + public override List Properties { get; protected set; } = new List() + { + new CActivities + { + Activities = new FixedListInt64 + { + (int)PetState.Follow, + (int)PetState.Eat + } + }, + new CRoamNearOwner() + }; + } +} \ No newline at end of file diff --git a/Customs/Elephant.cs b/Customs/Elephant.cs new file mode 100644 index 0000000..0fc602f --- /dev/null +++ b/Customs/Elephant.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using KitchenLib.Utils; +using Pets.Components.Properties; +using Pets.Customs.Types; +using Pets.Enums; +using Pets.Interfaces; +using Unity.Collections; +using UnityEngine; + +namespace Pets.Customs +{ + public class Elephant : CustomPet + { + public override string UniqueNameID => "Elephant"; + public override GameObject Prefab => Mod.Bundle.LoadAsset("Elephant").AssignMaterialsByNames(); + public override GameObject IconPrefab => Mod.Bundle.LoadAsset("ElephantIcon").AssignMaterialsByNames(); + public override PetState DefaultState => PetState.Follow; + + public override List Properties { get; protected set; } = new List() + { + new CActivities + { + Activities = new FixedListInt64 + { + (int)PetState.Follow, + (int)PetState.Eat + } + }, + new CRoamNearOwner(), + new CStandBackFromFood + { + Distance = 0.75f + } + }; + } +} \ No newline at end of file diff --git a/Customs/Goose.cs b/Customs/Goose.cs new file mode 100644 index 0000000..16c1750 --- /dev/null +++ b/Customs/Goose.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using KitchenLib.Utils; +using Pets.Components.Properties; +using Pets.Customs.Types; +using Pets.Enums; +using Pets.Interfaces; +using Unity.Collections; +using UnityEngine; + +namespace Pets.Customs +{ + public class Goose : CustomPet + { + public override string UniqueNameID => "Goose"; + public override GameObject Prefab => Mod.Bundle.LoadAsset("Goose").AssignMaterialsByNames(); + public override GameObject IconPrefab => Mod.Bundle.LoadAsset("GooseIcon").AssignMaterialsByNames(); + public override PetState DefaultState => PetState.Follow; + + public override List Properties { get; protected set; } = new List() + { + new CActivities + { + Activities = new FixedListInt64 + { + (int)PetState.Follow, + (int)PetState.Eat, + (int)PetState.Sleep, + } + }, + new CSleepingPositionOffset + { + Offset = new Vector2(-0.347f, 0.022f) + }, + new CRoamNearOwner(), + new CStapleAppliances + { + Appliances = new FixedListInt64 + { + GDOUtils.GetCustomGameDataObject().ID + } + } + }; + } +} \ No newline at end of file diff --git a/Customs/Penguin.cs b/Customs/Penguin.cs new file mode 100644 index 0000000..ca428b5 --- /dev/null +++ b/Customs/Penguin.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using KitchenLib.Utils; +using Pets.Components.Properties; +using Pets.Customs.Types; +using Pets.Enums; +using Pets.Interfaces; +using Unity.Collections; +using UnityEngine; + +namespace Pets.Customs +{ + public class Penguin : CustomPet + { + public override string UniqueNameID => "Penguin"; + public override GameObject Prefab => Mod.Bundle.LoadAsset("Penguin").AssignMaterialsByNames(); + public override GameObject IconPrefab => Mod.Bundle.LoadAsset("PenguinIcon").AssignMaterialsByNames(); + public override PetState DefaultState => PetState.Follow; + + public override List Properties { get; protected set; } = new List() + { + new CActivities + { + Activities = new FixedListInt64 + { + (int)PetState.Follow, + (int)PetState.Sleep, + } + }, + new CSleepingPositionOffset + { + Offset = new Vector2(0.445f, -0.236f) + }, + new CRoamNearOwner(), + new CStapleAppliances + { + Appliances = new FixedListInt64 + { + GDOUtils.GetCustomGameDataObject().ID + } + } + }; + } +} \ No newline at end of file diff --git a/Customs/Rabbit.cs b/Customs/Rabbit.cs new file mode 100644 index 0000000..02b33f5 --- /dev/null +++ b/Customs/Rabbit.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using KitchenLib.Utils; +using Pets.Components.Properties; +using Pets.Customs.Types; +using Pets.Enums; +using Pets.Interfaces; +using Unity.Collections; +using UnityEngine; + +namespace Pets.Customs +{ + public class Rabbit : CustomPet + { + public override string UniqueNameID => "Rabbit"; + public override GameObject Prefab => Mod.Bundle.LoadAsset("Rabbit").AssignMaterialsByNames(); + public override GameObject IconPrefab => Mod.Bundle.LoadAsset("RabbitIcon").AssignMaterialsByNames(); + public override PetState DefaultState => PetState.Follow; + + public override List Properties { get; protected set; } = new List() + { + new CActivities + { + Activities = new FixedListInt64 + { + (int)PetState.Follow, + (int)PetState.Eat, + (int)PetState.Sleep, + } + }, + new CSleepingPositionOffset + { + Offset = new Vector2(-0.443f, -0.123f) + }, + new CRoamNearOwner(), + new CStapleAppliances + { + Appliances = new FixedListInt64 + { + GDOUtils.GetCustomGameDataObject().ID + } + } + }; + } +} \ No newline at end of file diff --git a/Customs/Seal.cs b/Customs/Seal.cs new file mode 100644 index 0000000..2efb66d --- /dev/null +++ b/Customs/Seal.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using KitchenLib.Utils; +using Pets.Components.Properties; +using Pets.Customs.Types; +using Pets.Enums; +using Pets.Interfaces; +using Unity.Collections; +using UnityEngine; + +namespace Pets.Customs +{ + public class Seal : CustomPet + { + public override string UniqueNameID => "Seal"; + public override GameObject Prefab => Mod.Bundle.LoadAsset("Seal").AssignMaterialsByNames(); + public override GameObject IconPrefab => Mod.Bundle.LoadAsset("SealIcon").AssignMaterialsByNames(); + public override PetState DefaultState => PetState.Follow; + + public override List Properties { get; protected set; } = new List() + { + new CActivities + { + Activities = new FixedListInt64 + { + (int)PetState.Follow, + (int)PetState.Eat, + (int)PetState.Sleep, + } + }, + new CRoamNearOwner(), + new CStapleAppliances + { + Appliances = new FixedListInt64 + { + GDOUtils.GetCustomGameDataObject().ID + } + } + }; + } +} \ No newline at end of file diff --git a/Customs/Squirrel.cs b/Customs/Squirrel.cs new file mode 100644 index 0000000..0459f42 --- /dev/null +++ b/Customs/Squirrel.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using KitchenLib.Utils; +using Pets.Components.Properties; +using Pets.Customs.Types; +using Pets.Enums; +using Pets.Interfaces; +using Unity.Collections; +using UnityEngine; + +namespace Pets.Customs +{ + public class Squirrel : CustomPet + { + public override string UniqueNameID => "Squirrel"; + public override GameObject Prefab => Mod.Bundle.LoadAsset("Squirrel").AssignMaterialsByNames(); + public override GameObject IconPrefab => Mod.Bundle.LoadAsset("SquirrelIcon").AssignMaterialsByNames(); + public override PetState DefaultState => PetState.Follow; + + public override List Properties { get; protected set; } = new List() + { + new CActivities + { + Activities = new FixedListInt64 + { + (int)PetState.Follow, + (int)PetState.Eat, + (int)PetState.Sleep, + } + }, + new CSleepingPositionOffset + { + Offset = new Vector2(-0.458f, 0.041f) + }, + new CRoamNearOwner(), + new CStapleAppliances + { + Appliances = new FixedListInt64 + { + GDOUtils.GetCustomGameDataObject().ID + } + } + }; + } +} \ No newline at end of file diff --git a/Customs/Types/Pet.cs b/Customs/Types/Pet.cs new file mode 100644 index 0000000..ae1696d --- /dev/null +++ b/Customs/Types/Pet.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using Kitchen; +using KitchenData; +using KitchenLib.Customs; +using KitchenLib.Utils; +using Pets.Enums; +using Pets.Interfaces; +using Pets.Patches; +using Pets.Views; +using TMPro; +using UnityEngine; +using UnityEngine.AI; +using UnityEngine.VFX; + +namespace Pets.Customs.Types +{ + public class Pet : GameDataObject, IHasPrefab + { + protected override void InitialiseDefaults() + { + Properties = new List(); + } + + GameObject IHasPrefab.Prefab => Prefab; + public GameObject Prefab; + public GameObject IconPrefab; + public ViewType ViewType; + public PetState DefaultState = PetState.Follow; + public List Properties; + + public override void SetupForGame() + { + base.SetupForGame(); + LocalViewRouter_Patch.registeredPetViews.Add(ViewType, Prefab); + + PetView view = Prefab.AddComponent(); + view.agent = Prefab.GetComponentInChildren(); + view.animator = Prefab.GetComponentInChildren(); + view.vfx = Prefab.GetComponentInChildren(); + TextMeshPro tmp = Prefab.GetComponentInChildren(); + if (tmp != null) + { + tmp.transform.parent.gameObject.AddComponent(); + view.label = tmp; + } + + foreach (Transform transform in Prefab.transform) + { + if (transform.name != "Error") continue; + view.warningIcon = transform.gameObject; + break; + } + } + } + + public abstract class CustomPet : CustomGameDataObject + { + public virtual GameObject Prefab { get; protected set; } + public virtual GameObject IconPrefab { get; protected set; } + public virtual PetState DefaultState { get; protected set; } = PetState.Follow; + public virtual List Properties { get; protected set; } = new List(); + + public override void Convert(GameData gameData, out GameDataObject gameDataObject) + { + Pet result = ScriptableObject.CreateInstance(); + + result.ID = ID; + result.Prefab = Prefab; + result.IconPrefab = IconPrefab; + result.ViewType = (ViewType)VariousUtils.GetID(UniqueNameID); + result.Properties = Properties; + result.DefaultState = DefaultState; + + gameDataObject = result; + } + } +} \ No newline at end of file diff --git a/Enums/PetState.cs b/Enums/PetState.cs new file mode 100644 index 0000000..97ffdbd --- /dev/null +++ b/Enums/PetState.cs @@ -0,0 +1,12 @@ +namespace Pets.Enums +{ + public enum PetState + { + Idle = 1, + Follow = 2, + Eat = 3, + Sleep = 4, + Error = 98, + NameChange = 99 + } +} \ No newline at end of file diff --git a/Interfaces/IPetProperty.cs b/Interfaces/IPetProperty.cs new file mode 100644 index 0000000..569a4fa --- /dev/null +++ b/Interfaces/IPetProperty.cs @@ -0,0 +1,9 @@ +using KitchenMods; + +namespace Pets.Interfaces +{ + public interface IPetProperty : IModComponent + { + + } +} \ No newline at end of file diff --git a/Menus/EditorGridMenu.cs b/Menus/EditorGridMenu.cs new file mode 100644 index 0000000..085286c --- /dev/null +++ b/Menus/EditorGridMenu.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using Kitchen.Modules; +using UnityEngine; + +namespace Pets.Menus +{ + public class EditorGridMenu : GridMenu + { + public EditorGridMenu(List items, Transform container, int player, bool has_back) : base(items, container, player, has_back) + { + } + + protected override int ColumnLength => 1; + + protected override void SetupElement(GridItemOption item, GridMenuElement element) + { + element.Set(item); + } + + protected override void OnSelect(GridItemOption item) + { + item.DoCallback(); + } + } + + [Serializable] + public struct GridItemOption : IGridItem + { + public readonly int ActionID; + public Texture2D icon; + private Action SelectCallback; + + public GridItemOption(int ActionID, Action callback, Texture2D icon = null) + { + this.ActionID = ActionID; + this.icon = icon; + SelectCallback = callback; + } + + public int SnapshotKey => ActionID; + + public Texture2D GetSnapshot() + { + if (ActionID == 0) + { + return Mod.Bundle.LoadAsset("MenuBack"); + } + + return icon; + } + + public void DoCallback() + { + SelectCallback?.Invoke(ActionID); + } + } +} diff --git a/Menus/GridMenuEditorConfig.cs b/Menus/GridMenuEditorConfig.cs new file mode 100644 index 0000000..de72c6e --- /dev/null +++ b/Menus/GridMenuEditorConfig.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using Kitchen.Modules; +using UnityEngine; + +namespace Pets.Menus +{ + public class GridMenuEditorConfig : GridMenuConfig + { + public override GridMenu Instantiate(Transform container, int player, bool has_back) + { + return new EditorGridMenu(new List(), container, player, has_back); + } + + public virtual EditorGridMenu Instantiate(Action callback, Transform container, int player, bool has_back) + { + List gridAppliances = new List() + { + new GridItemOption(0, callback), + new GridItemOption(1, callback, Mod.Bundle.LoadAsset("Stop")), + new GridItemOption(2, callback, Mod.Bundle.LoadAsset("Activity")), + new GridItemOption(99, callback, Mod.Bundle.LoadAsset("Rename")) + }; + return new EditorGridMenu(gridAppliances, container, player, has_back); + } + } +} diff --git a/Menus/GridMenuPetConfig.cs b/Menus/GridMenuPetConfig.cs new file mode 100644 index 0000000..84f6597 --- /dev/null +++ b/Menus/GridMenuPetConfig.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Kitchen.Modules; +using Pets.Customs.Types; +using UnityEngine; + +namespace Pets.Menus +{ + public class GridMenuPetConfig : GridMenuConfig + { + public override GridMenu Instantiate(Transform container, int player, bool has_back) + { + return new PetGridMenu(Pets, container, player, has_back); + } + + public List Pets = new List(); + } +} \ No newline at end of file diff --git a/Menus/PetGridMenu.cs b/Menus/PetGridMenu.cs new file mode 100644 index 0000000..1d2cfe3 --- /dev/null +++ b/Menus/PetGridMenu.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Kitchen; +using Kitchen.Modules; +using Pets.Customs.Types; +using Pets.Views; +using UnityEngine; + +namespace Pets.Menus +{ + public class PetGridMenu : GridMenu + { + public PetGridMenu(List items, Transform container, int player, bool has_back) : base(items, container, player, has_back) + { + } + + protected override int ColumnLength => 3; + + protected override void SetupElement(Pet item, GridMenuElement element) + { + element.Set(PrefabSnapshot.GetSnapshot(item.IconPrefab)); + } + + protected override void OnSelect(Pet item) + { + if (Player != 0 && item != null) + { + PetRequestView.PlayerID = Player; + PetRequestView.PetID = item.ID; + } + } + } +} \ No newline at end of file diff --git a/Mod.cs b/Mod.cs new file mode 100644 index 0000000..9cd9275 --- /dev/null +++ b/Mod.cs @@ -0,0 +1,67 @@ +using KitchenLib; +using KitchenLib.Logging; +using KitchenLib.Logging.Exceptions; +using KitchenMods; +using System.Linq; +using System.Reflection; +using Kitchen.Modules; +using KitchenLib.Interfaces; +using KitchenLib.Utils; +using Pets.Components; +using Pets.Customs; +using Pets.Customs.Types; +using Pets.Menus; +using Pets.Views; +using UnityEngine; + +namespace Pets +{ + public class Mod : BaseMod, IAutoRegisterAll + { + public const string MOD_GUID = "com.starfluxgames.pets"; + public const string MOD_NAME = "Pets"; + public const string MOD_VERSION = "0.1.0"; + public const string MOD_AUTHOR = "StarFluxGames"; + public const string MOD_GAMEVERSION = ">=1.1.8"; + + public static AssetBundle Bundle; + public static KitchenLogger Logger; + + public static float MinimumSpeedThreshold = 0.1f; + + public Mod() : base(MOD_GUID, MOD_NAME, MOD_AUTHOR, MOD_VERSION, MOD_GAMEVERSION, Assembly.GetExecutingAssembly()) { } + + protected override void OnInitialise() + { + Logger.LogWarning($"{MOD_GUID} v{MOD_VERSION} in use!"); + + foreach (GridMenuNavigationConfig grid in Resources.FindObjectsOfTypeAll()) + { + if (grid.name == "Root") + { + GridMenuPetConfig config = new GridMenuPetConfig(); + config.Pets.Add(GDOUtils.GetCustomGameDataObject().GameDataObject as Pet); + config.Pets.Add(GDOUtils.GetCustomGameDataObject().GameDataObject as Pet); + config.Pets.Add(GDOUtils.GetCustomGameDataObject().GameDataObject as Pet); + config.Pets.Add(GDOUtils.GetCustomGameDataObject().GameDataObject as Pet); + config.Pets.Add(GDOUtils.GetCustomGameDataObject().GameDataObject as Pet); + config.Pets.Add(GDOUtils.GetCustomGameDataObject().GameDataObject as Pet); + config.Pets.Add(GDOUtils.GetCustomGameDataObject().GameDataObject as Pet); + config.Pets.Add(GDOUtils.GetCustomGameDataObject().GameDataObject as Pet); + config.Pets.Add(GDOUtils.GetCustomGameDataObject().GameDataObject as Pet); + config.Icon = Bundle.LoadAsset("PawPrint"); + grid.Links.Add(config); + } + } + } + + protected override void OnPostActivate(KitchenMods.Mod mod) + { + Bundle = mod.GetPacks().SelectMany(e => e.AssetBundles).FirstOrDefault() ?? throw new MissingAssetBundleException(MOD_GUID); + Logger = InitLogger(); + + ViewUtils.RegisterView("Pets.Views.PetRequestView", typeof(SPetRequestView), typeof(PetRequestView)); + } + } +} + diff --git a/Patches/LocalViewRouter_Patch.cs b/Patches/LocalViewRouter_Patch.cs new file mode 100644 index 0000000..26c3484 --- /dev/null +++ b/Patches/LocalViewRouter_Patch.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using HarmonyLib; +using Kitchen; +using UnityEngine; + +namespace Pets.Patches +{ + [HarmonyPatch(typeof(LocalViewRouter), "GetPrefab")] + public class LocalViewRouter_Patch + { + public static Dictionary registeredPetViews = new(); + + static bool Prefix(LocalViewRouter __instance, ViewType view_type, ref GameObject __result) + { + if (!registeredPetViews.TryGetValue(view_type, out GameObject petPrefab)) return true; + __result = petPrefab; + return false; + } + } +} \ No newline at end of file diff --git a/Patches/LocalViewRouter_Patch2.cs b/Patches/LocalViewRouter_Patch2.cs new file mode 100644 index 0000000..bad9f43 --- /dev/null +++ b/Patches/LocalViewRouter_Patch2.cs @@ -0,0 +1,48 @@ +using System.Reflection; +using HarmonyLib; +using Kitchen; +using KitchenLib.Utils; +using Pets.Menus; +using Pets.Views; +using UnityEngine; + +namespace Pets.Patches +{ + [HarmonyPatch(typeof(LocalViewRouter), "GetPrefab")] + public class LocalViewRouter2_Patch + { + public static GameObject container; + public static GameObject result; + + public static FieldInfo _AssetDirectory = AccessTools.Field(typeof(LocalViewRouter), "AssetDirectory"); + public static FieldInfo f_Container = typeof(CostumeChangeIndicator).GetField("Container", BindingFlags.NonPublic | BindingFlags.Instance); + + static bool Prefix(LocalViewRouter __instance, ViewType view_type, ref GameObject __result) + { + if (view_type != (ViewType)VariousUtils.GetID("com.starfluxgames.pets.PetEditorView")) return true; + + if (container == null) + { + container = new GameObject("temp"); + container.SetActive(false); + } + + if (result == null) + { + AssetDirectory AssetDirectory = (AssetDirectory)_AssetDirectory.GetValue(__instance); + result = GameObject.Instantiate(AssetDirectory.ViewPrefabs[ViewType.CostumeChangeInfo], container.transform); + CostumeChangeIndicator costumeChangeIndicator = result.GetComponent(); + if (costumeChangeIndicator != null) + { + PetEditorView upgradeIndicator = result.AddComponent(); + upgradeIndicator.container = (Transform)f_Container?.GetValue(costumeChangeIndicator); + upgradeIndicator.rootMenuConfig = new GridMenuEditorConfig(); + Component.DestroyImmediate(costumeChangeIndicator); + } + } + + __result = result; + return false; + } + } +} \ No newline at end of file diff --git a/Pets.csproj b/Pets.csproj new file mode 100644 index 0000000..5c4a368 --- /dev/null +++ b/Pets.csproj @@ -0,0 +1,40 @@ + + + + net472 + Release;Debug + $(MSBuildProjectName)-Workshop + latest + CS0114 + + + + $(ProjectDir)UnityProject - Pets\content\mod.assets + + + + + + + + + + + + + + + + + + + + + + + D:\Program Files (x86)\Steam\steamapps\common\PlateUp\PlateUp\PlateUp_Data\Managed\Kitchen.RestaurantMode.dll + RebuildingRestaurant + + + + diff --git a/Systems/Activities/PetEatActivity.cs b/Systems/Activities/PetEatActivity.cs new file mode 100644 index 0000000..51118e2 --- /dev/null +++ b/Systems/Activities/PetEatActivity.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; +using Kitchen; +using KitchenMods; +using Pets.Components.Properties; +using Pets.Components.Status; +using Pets.Enums; +using Unity.Collections; +using Unity.Entities; +using UnityEngine; +using Random = UnityEngine.Random; + +namespace Pets.Systems.Activities +{ + public class PetEatActivity : PetActivitySystem, IModSystem + { + protected override PetState StateForUpdate => PetState.Eat; + + private EntityQuery _food; + + protected override void Initialise() + { + base.Initialise(); + _food = GetEntityQuery(new QueryHelper().All(typeof(CItemProvider), typeof(CPosition)).None(typeof(COccupiedByPet))); + } + + protected override bool IsPossible(ActivityData data) + { + if (_food.CalculateEntityCount() == 0) return false; + + using NativeArray food = _food.ToEntityArray(Allocator.Temp); + + Dictionary ValidFood = GetAllEntitiesInRange(food, data.PetPosition); + + bool foundFood = false; + + foreach (float distance in ValidFood.Keys) + { + Entity foodEntity = ValidFood[distance]; + + float offset = 0; + + if (Require(data.Pet, out CStandBackFromFood cStandBackFromFood)) + offset = cStandBackFromFood.Distance; + + if (Require(data.Pet, out CPreferredFoods cPreferredFoods)) + { + if (Require(foodEntity, out CItemProvider cItemProvider)) + { + if (!cPreferredFoods.PreferredFoods.Contains(cItemProvider.ProvidedItem)) continue; + } + } + + if (!Require(foodEntity, out CPosition cFoodPosition)) continue; + + Vector3 targetPos = Vector3.zero; + + if (!CanGetTo(data.PetPosition, cFoodPosition, new Vector3(1 + offset, 0, 0), out targetPos)) + if (!CanGetTo(data.PetPosition, cFoodPosition, new Vector3(-1 - offset, 0, 0), out targetPos)) + if (!CanGetTo(data.PetPosition, cFoodPosition, new Vector3(0, 0, 1 + offset), out targetPos)) + if (!CanGetTo(data.PetPosition, cFoodPosition, new Vector3(0, 0, -1 - offset), out targetPos)) + continue; + + foundFood = true; + TargetPosition = targetPos; + TargetEntity = foodEntity; + TargetForward = cFoodPosition; + break; + } + + return foundFood; + } + + private Entity TargetEntity; + private CPosition TargetPosition; + private CPosition TargetForward; + + protected override bool Perform(ActivityData data) + { + if (!Require(TargetEntity, out CPosition cBedPosition)) return false; + + EntityManager.AddComponentData(data.Pet, new CMoveToLocation + { + Location = TargetPosition, + StoppingDistance = 0, + DesiredFacing = TargetForward + }); + + EntityManager.AddComponentData(TargetEntity, new COccupiedByPet()); + EntityManager.AddComponentData(data.Pet, new CPetInteractingWith + { + InteractingWith = TargetEntity, + TimeToFinish = Random.Range(5, 15), + IsWaitingForDestination = true + }); + + return HasComponent(data.Pet) && HasComponent(data.Pet) && HasComponent(TargetEntity); + } + } +} \ No newline at end of file diff --git a/Systems/Activities/PetFollowActivity.cs b/Systems/Activities/PetFollowActivity.cs new file mode 100644 index 0000000..86de81a --- /dev/null +++ b/Systems/Activities/PetFollowActivity.cs @@ -0,0 +1,77 @@ +using Kitchen; +using KitchenMods; +using Pets.Components; +using Pets.Components.Properties; +using Pets.Components.Status; +using Pets.Enums; +using Unity.Entities; +using UnityEngine; + +namespace Pets.Systems.Activities +{ + public class PetFollowActivity : PetActivitySystem, IModSystem + { + protected override PetState StateForUpdate => PetState.Follow; + + protected override bool IsPossible(ActivityData data) + { + maxDistance = 5; + + if (!Require(data.Pet, out CPet cPet)) return false; + if (cPet.Owner == Entity.Null) return false; + if (!Require(cPet.Owner, out TargetPosition)) return false; + if (Require(data.Pet, out CLonelyDistance cLonelyDistance)) + maxDistance = cLonelyDistance.Distance; + + currentDistance = Vector3.Distance(data.PetPosition, TargetPosition); + + return true; + } + + private float maxDistance; + private float currentDistance; + private CPosition TargetPosition; + + protected override bool Perform(ActivityData data) + { + if (currentDistance > maxDistance) + { + EntityManager.AddComponentData(data.Pet, new CMoveToLocation + { + Location = TargetPosition, + StoppingDistance = 1, + }); + } + else + { + if (!Require(data.Pet, out CRoamNearOwner cRoamNearOwner)) return true; + + if (!(Random.value <= 0.03f * Time.DeltaTime)) return true; + + if (!Require(data.Pet, out CCurrentSpeed cCurrentSpeed)) return true; + if (cCurrentSpeed.speed > Mod.MinimumSpeedThreshold) return true; + + Vector3 randomPosition = new Vector3(Random.Range(-cRoamNearOwner.Distance, cRoamNearOwner.Distance), 0, Random.Range(-cRoamNearOwner.Distance, cRoamNearOwner.Distance)); + Vector3 newTarget = TargetPosition + randomPosition; + float distance = Vector3.Distance(data.PetPosition, newTarget); + + if (!(distance <= maxDistance)) return true; + if (!CanGetTo(data.PetPosition, newTarget, Vector3.zero, out newTarget)) return true; + + EntityManager.AddComponentData(data.Pet, new CMoveToLocation + { + Location = newTarget, + StoppingDistance = 0 + }); + + EntityManager.AddComponentData(data.Pet, new CPetInteractingWith + { + TimeToFinish = 0, + IsWaitingForDestination = true + }); + } + + return true; + } + } +} \ No newline at end of file diff --git a/Systems/Activities/PetNameChangeActivity.cs b/Systems/Activities/PetNameChangeActivity.cs new file mode 100644 index 0000000..3e63bc4 --- /dev/null +++ b/Systems/Activities/PetNameChangeActivity.cs @@ -0,0 +1,31 @@ +using Kitchen; +using KitchenMods; +using Pets.Components; +using Pets.Enums; +using Unity.Entities; + +namespace Pets.Systems.Activities +{ + public class PetNameChangeActivity : PetActivitySystem, IModSystem + { + protected override PetState StateForUpdate => PetState.NameChange; + + protected override bool IsPossible(ActivityData data) + { + return Require(data.Pet, out CPet cPet) && cPet.Owner != Entity.Null && Has(cPet.Owner) && !Has(data.Pet); + } + + protected override bool Perform(ActivityData data) + { + if (!Require(data.Pet, out CPet cPet)) return false; + if (!Require(cPet.Owner, out CPlayer cPlayer)) return false; + + EntityManager.AddComponentData(data.Pet, new CRequestNameChange + { + Source = cPlayer.InputSource, + IsTriggered = false + }); + return true; + } + } +} \ No newline at end of file diff --git a/Systems/Activities/PetSleepActivity.cs b/Systems/Activities/PetSleepActivity.cs new file mode 100644 index 0000000..b0ad14c --- /dev/null +++ b/Systems/Activities/PetSleepActivity.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using Kitchen; +using KitchenMods; +using Pets.Components; +using Pets.Components.Properties; +using Pets.Components.Status; +using Pets.Enums; +using Unity.Collections; +using Unity.Entities; +using UnityEngine; +using Random = UnityEngine.Random; + +namespace Pets.Systems.Activities +{ + public class PetSleepActivity : PetActivitySystem, IModSystem + { + protected override PetState StateForUpdate => PetState.Sleep; + + private EntityQuery _petBeds; + + protected override void Initialise() + { + base.Initialise(); + _petBeds = GetEntityQuery(new QueryHelper().All(typeof(CPetBed), typeof(CPosition)).None(typeof(COccupiedByPet))); + } + + protected override bool IsPossible(ActivityData data) + { + if (_petBeds.CalculateEntityCount() == 0) return false; + + using NativeArray petBeds = _petBeds.ToEntityArray(Allocator.Temp); + + Dictionary ValidBeds = GetAllEntitiesInRange(petBeds, data.PetPosition); + + bool foundBed = false; + + foreach (float distance in ValidBeds.Keys) + { + Entity bed = ValidBeds[distance]; + CPosition bedPosition; + if (!Require(bed, out bedPosition)) continue; + if (Require(data.Pet, out CSleepingPositionOffset cSleepingPositionOffset)) + if (GetOffsetPosition(bedPosition.Forward(1), cSleepingPositionOffset.Offset, out Vector2 offsetPosition)) + bedPosition += offsetPosition; + + + + if (!CanGetTo(data.PetPosition, bedPosition, Vector3.zero, out Vector3 targetDestination)) continue; + + foundBed = true; + TargetPosition = targetDestination; + TargetEntity = bed; + break; + } + + return foundBed; + } + + private Entity TargetEntity; + private CPosition TargetPosition; + + protected override bool Perform(ActivityData data) + { + if (!Require(TargetEntity, out CPosition cBedPosition)) return false; + + EntityManager.AddComponentData(data.Pet, new CMoveToLocation + { + Location = TargetPosition, + StoppingDistance = 0, + DesiredFacing = cBedPosition.Forward(-10) + }); + + EntityManager.AddComponentData(TargetEntity, new COccupiedByPet()); + EntityManager.AddComponentData(data.Pet, new CPetInteractingWith + { + InteractingWith = TargetEntity, + StartTime = DateTimeOffset.Now.ToUnixTimeSeconds(), + TimeToFinish = Random.Range(5, 15), + IsWaitingForDestination = true + }); + + return HasComponent(data.Pet) && HasComponent(data.Pet) && HasComponent(TargetEntity); + } + } +} \ No newline at end of file diff --git a/Systems/Activities/StopInteraction.cs b/Systems/Activities/StopInteraction.cs new file mode 100644 index 0000000..c8ad700 --- /dev/null +++ b/Systems/Activities/StopInteraction.cs @@ -0,0 +1,61 @@ +using System; +using Kitchen; +using KitchenMods; +using Pets.Components; +using Pets.Components.Status; +using Pets.Enums; +using Unity.Collections; +using Unity.Entities; +using UnityEngine; + +namespace Pets.Systems.Activities +{ + public class StopInteraction : GameSystemBase, IModSystem + { + private EntityQuery _pets; + + protected override void Initialise() + { + base.Initialise(); + _pets = GetEntityQuery(new QueryHelper().All(typeof(CPet), typeof(CPetInteractingWith))); + } + + protected override void OnUpdate() + { + if (_pets.CalculateEntityCount() == 0) return; + + NativeArray pets = _pets.ToEntityArray(Allocator.Temp); + + for (int i = 0; i < pets.Length; i++) + { + Entity pet = pets[i]; + if (!Require(pet, out CPetInteractingWith cPetInteractingWith)) continue; + if (!Require(pet, out CMoveToLocation cMoveToLocation)) continue; + if (!Require(pet, out CPosition cPosition)) continue; + if (!Require(pet, out CCurrentSpeed cCurrentSpeed)) continue; + if (cPetInteractingWith.IsWaitingForDestination) + { + if (Vector3.Distance(cPosition, cMoveToLocation.Location) < 0.1f && cCurrentSpeed.speed < Mod.MinimumSpeedThreshold) + { + cPetInteractingWith.IsWaitingForDestination = false; + cPetInteractingWith.StartTime = DateTimeOffset.Now.ToUnixTimeSeconds(); + EntityManager.AddComponentData(pet, cPetInteractingWith); + } + continue; + } + + if (!Require(pet, out CPet cPet)) continue; + if (cPetInteractingWith.StartTime + cPetInteractingWith.TimeToFinish > DateTimeOffset.Now.ToUnixTimeSeconds()) continue; + + EntityManager.RemoveComponent(pet); + EntityManager.RemoveComponent(cPetInteractingWith.InteractingWith); + EntityManager.RemoveComponent(pet); + cPet.State = PetState.Follow; + EntityManager.AddComponentData(pet, cPet); + + } + + pets.Dispose(); + } + } +} \ No newline at end of file diff --git a/Systems/Creation/CleanPetlessPlayers.cs b/Systems/Creation/CleanPetlessPlayers.cs new file mode 100644 index 0000000..66ac406 --- /dev/null +++ b/Systems/Creation/CleanPetlessPlayers.cs @@ -0,0 +1,37 @@ +using Kitchen; +using KitchenMods; +using Pets.Components.Creation; +using Unity.Collections; +using Unity.Entities; + +namespace Pets.Systems +{ + [UpdateAfter(typeof(EnsureLinkedPets))] + public class CleanPetlessPlayers : GameSystemBase, IModSystem + { + private EntityQuery _players; + protected override void Initialise() + { + base.Initialise(); + _players = GetEntityQuery(new QueryHelper().All(typeof(CPlayer), typeof(CLinkedPet))); + } + + protected override void OnUpdate() + { + NativeArray players = _players.ToEntityArray(Allocator.Temp); + + for (int i = 0; i < players.Length; i++) + { + Entity player = players[i]; + if (!Require(player, out CLinkedPet cLinkedPet)) continue; + if (cLinkedPet.PetEntity != Entity.Null) continue; + + Mod.Logger.LogInfo($"Removing petless player"); + + EntityManager.RemoveComponent(player); + } + + players.Dispose(); + } + } +} \ No newline at end of file diff --git a/Systems/Creation/EnsureCorrectPet.cs b/Systems/Creation/EnsureCorrectPet.cs new file mode 100644 index 0000000..51f61f9 --- /dev/null +++ b/Systems/Creation/EnsureCorrectPet.cs @@ -0,0 +1,39 @@ +using Kitchen; +using KitchenMods; +using Pets.Components.Creation; +using Unity.Collections; +using Unity.Entities; + +namespace Pets.Systems +{ + public class EnsureCorrectPet : GameSystemBase, IModSystem + { + private EntityQuery _players; + + protected override void Initialise() + { + base.Initialise(); + _players = GetEntityQuery(typeof(CPlayer), typeof(CLinkedPet), typeof(CRequiresPet)); + } + + protected override void OnUpdate() + { + NativeArray players = _players.ToEntityArray(Allocator.Temp); + + for (int i = 0; i < players.Length; i++) + { + Entity player = players[i]; + if (!Require(player, out CLinkedPet cLinkedPet)) continue; + if (!Require(player, out CRequiresPet cRequiresPet)) continue; + + if (cLinkedPet.PetType != cRequiresPet.PetType && cLinkedPet.PetEntity != Entity.Null) + { + EntityManager.DestroyEntity(cLinkedPet.PetEntity); + EntityManager.RemoveComponent(player); + } + } + + players.Dispose(); + } + } +} \ No newline at end of file diff --git a/Systems/Creation/EnsureLinkedPets.cs b/Systems/Creation/EnsureLinkedPets.cs new file mode 100644 index 0000000..adc5f0b --- /dev/null +++ b/Systems/Creation/EnsureLinkedPets.cs @@ -0,0 +1,69 @@ +using Kitchen; +using KitchenMods; +using Pets.Components; +using Pets.Components.Creation; +using Unity.Collections; +using Unity.Entities; + +namespace Pets.Systems +{ + [UpdateBefore(typeof(CleanPetlessPlayers))] + public class EnsureLinkedPets : GameSystemBase, IModSystem + { + private EntityQuery _pets; + private EntityQuery _playersWithLink; + + + protected override void Initialise() + { + base.Initialise(); + _pets = GetEntityQuery(new QueryHelper().All(typeof(CPet))); + _playersWithLink = GetEntityQuery(new QueryHelper().All(typeof(CLinkedPet))); + } + + protected override void OnUpdate() + { + NativeArray pets = _pets.ToEntityArray(Allocator.Temp); + NativeArray playersWithLink = _playersWithLink.ToEntityArray(Allocator.Temp); + + foreach (Entity player in playersWithLink) + { + if (!Require(player, out CLinkedPet cLinkedPet)) continue; + if ((cLinkedPet.PetEntity == Entity.Null || cLinkedPet.PetEntity.Index == 0) || (cLinkedPet.PetEntity != Entity.Null && !EntityManager.HasComponent(cLinkedPet.PetEntity))) + { + foreach (Entity pet in pets) + { + if (!Require(pet, out CPet cPet)) continue; + if (cLinkedPet.PetLinkId != cPet.PetLinkId) continue; + cLinkedPet.PetEntity = pet; + cPet.Owner = player; + EntityManager.SetComponentData(player, cLinkedPet); + EntityManager.SetComponentData(pet, cPet); + break; + } + } + } + + foreach (Entity pet in pets) + { + if (!Require(pet, out CPet cPet)) continue; + if ((cPet.Owner == Entity.Null || cPet.Owner.Index == 0) || (cPet.Owner != Entity.Null && !EntityManager.HasComponent(cPet.Owner))) + { + foreach (Entity player in playersWithLink) + { + if (!Require(player, out CLinkedPet cLinkedPet)) continue; + if (cLinkedPet.PetLinkId != cPet.PetLinkId) continue; + cLinkedPet.PetEntity = pet; + cPet.Owner = player; + EntityManager.SetComponentData(player, cLinkedPet); + EntityManager.SetComponentData(pet, cPet); + break; + } + } + } + + pets.Dispose(); + playersWithLink.Dispose(); + } + } +} \ No newline at end of file diff --git a/Systems/Creation/PetSelector.cs b/Systems/Creation/PetSelector.cs new file mode 100644 index 0000000..023ebab --- /dev/null +++ b/Systems/Creation/PetSelector.cs @@ -0,0 +1,56 @@ +using Kitchen; +using KitchenMods; +using Pets.Components.Creation; +using Unity.Collections; +using Unity.Entities; + +namespace Pets.Systems +{ + public class PetSelector : GameSystemBase, IModSystem + { + public static PetSelector Main; + + private EntityQuery _players; + private EntityQuery _requestedPets; + + protected override void Initialise() + { + base.Initialise(); + Main = this; + _players = GetEntityQuery(new QueryHelper().All(typeof(CPlayer))); + _requestedPets = GetEntityQuery(new QueryHelper().All(typeof(CRequestedPet))); + } + + protected override void OnUpdate() + { + using NativeArray requestedPets = _requestedPets.ToEntityArray(Allocator.Temp); + using NativeArray players = _players.ToEntityArray(Allocator.Temp); + + for (int i = 0; i < requestedPets.Length; i++) + { + Entity requestedPet = requestedPets[i]; + if (!Require(requestedPet, out CRequestedPet cRequestedPet)) continue; + foreach (Entity player in players) + { + if (!Require(player, out CPlayer cPlayer)) continue; + if (cPlayer.ID != cRequestedPet.player) continue; + EntityManager.AddComponentData(player, new CRequiresPet + { + PetType = cRequestedPet.pet + }); + EntityManager.DestroyEntity(requestedPet); + } + } + } + + public void CreatePlayerRequest(int player, int pet) + { + Entity entity = EntityManager.CreateEntity(); + EntityManager.AddComponentData(entity, new CRequestedPet + { + pet = pet, + player = player + }); + } + } +} \ No newline at end of file diff --git a/Systems/Creation/SpawnPets.cs b/Systems/Creation/SpawnPets.cs new file mode 100644 index 0000000..02a7d55 --- /dev/null +++ b/Systems/Creation/SpawnPets.cs @@ -0,0 +1,81 @@ +using Kitchen; +using KitchenData; +using KitchenMods; +using Pets.Components; +using Pets.Components.Creation; +using Pets.Customs.Types; +using Pets.Enums; +using Pets.Interfaces; +using Unity.Collections; +using Unity.Entities; + +namespace Pets.Systems.Creation +{ + [UpdateAfter(typeof(EnsureLinkedPets))] + public class SpawnPets : GameSystemBase, IModSystem + { + private EntityQuery _players; + + protected override void Initialise() + { + base.Initialise(); + _players = GetEntityQuery(new QueryHelper().All(typeof(CPlayer), typeof(CRequiresPet)).None(typeof(CLinkedPet))); + } + + protected override void OnUpdate() + { + NativeArray players = _players.ToEntityArray(Allocator.Temp); + + foreach (Entity player in players) + { + if (!Require(player, out CRequiresPet cRequiresPet)) continue; + if (!Require(player, out CPosition cPosition)) continue; + if (!GameData.Main.TryGet(cRequiresPet.PetType, out Pet petType)) continue; + + Entity pet = EntityManager.CreateEntity(); + + int LinkID = UnityEngine.Random.Range(-100000, 100000); + + EntityManager.AddComponentData(pet, new CPet + { + Owner = player, + State = petType.DefaultState, + PetLinkId = LinkID, + PetType = petType.ID + }); + EntityManager.AddComponentData(pet, new CPosition(cPosition)); + + EntityManager.AddComponentData(pet, new CRequiresView + { + Type = petType.ViewType, + PhysicsDriven = true + }); + EntityManager.AddComponentData(pet, new CDoNotPersist()); + EntityManager.AddComponentData(pet, new CIsInteractive()); + EntityManager.AddComponentData(pet, new CCanBePetted()); + EntityManager.AddComponentData(pet, new CPersistThroughSceneChanges()); + + + EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.Temp); + foreach (IPetProperty property in petType.Properties) + { + ecb.AddComponent(pet, (dynamic)property); + } + + ecb.AddComponent(pet, new CDefaultState(petType.DefaultState)); + + ecb.Playback(EntityManager); + + EntityManager.AddComponentData(player, new CLinkedPet + { + PetType = cRequiresPet.PetType, + PetEntity = pet, + PetLinkId = LinkID + }); + + } + + players.Dispose(); + } + } +} \ No newline at end of file diff --git a/Systems/Creation/TransitionFix.cs b/Systems/Creation/TransitionFix.cs new file mode 100644 index 0000000..80b6488 --- /dev/null +++ b/Systems/Creation/TransitionFix.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using Kitchen; +using KitchenMods; +using Pets.Components.Creation; +using Unity.Collections; +using Unity.Entities; + +namespace Pets.Systems +{ + public class TransitionFix : GameSystemBase, IModSystem + { + private EntityQuery _players; + private static Dictionary _requiresPet = new Dictionary(); + private static Dictionary _linkedPet = new Dictionary(); + + protected override void Initialise() + { + base.Initialise(); + _players = GetEntityQuery(new QueryHelper().All(typeof(CPlayer))); + } + + protected override void OnUpdate() + { + NativeArray players = _players.ToEntityArray(Allocator.Temp); + + _requiresPet.Clear(); + _linkedPet.Clear(); + + foreach (Entity player in players) + { + if (!Require(player, out CPlayer cPlayer)) continue; + if (Require(player, out CRequiresPet cRequiresPet)) + { + _requiresPet.Add(cPlayer.ID, cRequiresPet); + } + if (Require(player, out CLinkedPet cLinkedPet)) + { + _linkedPet.Add(cPlayer.ID, cLinkedPet); + } + } + + players.Dispose(); + } + + public override void AfterLoading(SaveSystemType system_type) + { + base.AfterLoading(system_type); + if (_requiresPet == null) return; + + NativeArray players = _players.ToEntityArray(Allocator.Temp); + + for (int i = 0; i < players.Length; i++) + { + Entity player = players[i]; + if (Has(player)) + { + EntityManager.RemoveComponent(player); + } + + if (!Require(player, out CPlayer cPlayer)) continue; + + if (_linkedPet.TryGetValue(cPlayer.ID, out CLinkedPet cLinkedPet)) + { + EntityManager.AddComponentData(player, cLinkedPet); + } + + if (_requiresPet.TryGetValue(cPlayer.ID, out CRequiresPet cRequiresPet)) + { + EntityManager.AddComponentData(player, cRequiresPet); + } + } + + _requiresPet.Clear(); + players.Dispose(); + } + } +} \ No newline at end of file diff --git a/Systems/EditorMenu/ActivatePetEditorDuringDay.cs b/Systems/EditorMenu/ActivatePetEditorDuringDay.cs new file mode 100644 index 0000000..9991eeb --- /dev/null +++ b/Systems/EditorMenu/ActivatePetEditorDuringDay.cs @@ -0,0 +1,24 @@ +using Kitchen; +using KitchenMods; +using Pets.Components; +using Pets.Components.Menu; + +namespace Pets.Systems.EditorMenu +{ + public class ActivatePetEditorDuringDay : ItemInteractionSystem, IModSystem + { + protected override bool IsPossible(ref InteractionData data) + { + return Require(data.Target, out CPet cPet) && cPet.Owner == data.Interactor; + } + + protected override void Perform(ref InteractionData data) + { + EntityManager.AddComponentData(data.Target, new CTriggerPetEditor + { + IsTriggered = true, + TriggerEntity = data.Interactor + }); + } + } +} diff --git a/Systems/EditorMenu/ActivatePetEditorDuringNight.cs b/Systems/EditorMenu/ActivatePetEditorDuringNight.cs new file mode 100644 index 0000000..6e54279 --- /dev/null +++ b/Systems/EditorMenu/ActivatePetEditorDuringNight.cs @@ -0,0 +1,24 @@ +using Kitchen; +using KitchenMods; +using Pets.Components; +using Pets.Components.Menu; + +namespace Pets.Systems.EditorMenu +{ + public class ActivatePetEditorDuringNight : ApplianceInteractionSystem, IModSystem + { + protected override bool IsPossible(ref InteractionData data) + { + return Require(data.Target, out CPet cPet) && cPet.Owner == data.Interactor; + } + + protected override void Perform(ref InteractionData data) + { + EntityManager.AddComponentData(data.Target, new CTriggerPetEditor + { + IsTriggered = true, + TriggerEntity = data.Interactor + }); + } + } +} diff --git a/Systems/EditorMenu/ManagePetEditorIndicators.cs b/Systems/EditorMenu/ManagePetEditorIndicators.cs new file mode 100644 index 0000000..70143fa --- /dev/null +++ b/Systems/EditorMenu/ManagePetEditorIndicators.cs @@ -0,0 +1,52 @@ +using Kitchen; +using KitchenLib.Utils; +using KitchenMods; +using Pets.Components; +using Pets.Components.Menu; +using Unity.Entities; + +namespace Pets.Systems.EditorMenu +{ + public class ManagePetEditorIndicators : IndicatorManager, IModSystem + { + protected override ViewType ViewType => (ViewType)VariousUtils.GetID("com.starfluxgames.pets.PetEditorView"); + + protected override EntityQuery GetSearchQuery() + { + return GetEntityQuery(typeof(CPet), typeof(CPosition)); + } + + protected override bool ShouldHaveIndicator(Entity candidate) + { + if (Require(candidate, out CHasIndicator comp)) + return Require(comp.Indicator, out CPetEditorInfo cPetEditorInfo) && !cPetEditorInfo.IsComplete; + + if (!Has(candidate)) return false; + if (!Require(candidate, out CTriggerPetEditor trigger)) return false; + if (!Has(trigger.TriggerEntity)) return false; + if (!trigger.IsTriggered) return false; + + trigger.IsTriggered = false; + Set(candidate, trigger); + return true; + + } + + protected override Entity CreateIndicator(Entity source) + { + if (!Require(source, out CPosition position)) return default(Entity); + if (!Require(source, out CPet cPet)) return default(Entity); + if (!Require(source, out CTriggerPetEditor trigger)) return default(Entity); + if (!Require(trigger.TriggerEntity, out CPlayer player)) return default(Entity); + + Entity entity = base.CreateIndicator(source); + EntityManager.AddComponentData(entity, new CPosition(position)); + EntityManager.AddComponentData(entity, new CPetEditorInfo + { + Player = player + }); + return entity; + + } + } +} diff --git a/Systems/FillStateChangeRequests.cs b/Systems/FillStateChangeRequests.cs new file mode 100644 index 0000000..ebad283 --- /dev/null +++ b/Systems/FillStateChangeRequests.cs @@ -0,0 +1,45 @@ +using Kitchen; +using KitchenMods; +using Pets.Components; +using Pets.Components.Creation; +using Pets.Enums; +using Unity.Collections; +using Unity.Entities; + +namespace Pets.Systems +{ + public class FillStateChangeRequests : GameSystemBase, IModSystem + { + private EntityQuery _players; + private EntityQuery _stateChangeRequests; + protected override void Initialise() + { + base.Initialise(); + _players = GetEntityQuery(typeof(CPlayer)); + _stateChangeRequests = GetEntityQuery(typeof(CRequestStateChange)); + } + + protected override void OnUpdate() + { + using NativeArray stateChangeRequests = _stateChangeRequests.ToEntityArray(Allocator.Temp); + using NativeArray players = _players.ToEntityArray(Allocator.Temp); + + for (int i = 0; i < stateChangeRequests.Length; i++) + { + Entity request = stateChangeRequests[i]; + if (!Require(request, out CRequestStateChange cRequestStateChange)) continue; + + foreach (Entity player in players) + { + if (!Require(player, out CPlayer cPlayer)) continue; + if (cPlayer.ID != cRequestStateChange.PlayerID) continue; + if (!Require(player, out CLinkedPet cLinkedPet)) continue; + if (!Require(cLinkedPet.PetEntity, out CPet cPet)) continue; + cPet.State = (PetState)cRequestStateChange.StateID; + EntityManager.AddComponentData(cLinkedPet.PetEntity, cPet); + EntityManager.DestroyEntity(request); + } + } + } + } +} \ No newline at end of file diff --git a/Systems/PetActivitySystem.cs b/Systems/PetActivitySystem.cs new file mode 100644 index 0000000..06dbcef --- /dev/null +++ b/Systems/PetActivitySystem.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using System.Linq; +using Kitchen; +using KitchenData; +using Pets.Components; +using Pets.Components.Status; +using Pets.Customs.Types; +using Pets.Enums; +using Unity.Collections; +using Unity.Entities; +using UnityEngine; +using UnityEngine.AI; + +namespace Pets.Systems +{ + public abstract class PetActivitySystem : GameSystemBase + { + protected abstract bool IsPossible(ActivityData data); + protected abstract bool Perform(ActivityData data); + + protected abstract PetState StateForUpdate { get; } + + private EntityQuery _petsWaitingForActivity; + private NavMeshPath Path = new NavMeshPath(); + + protected override void Initialise() + { + base.Initialise(); + _petsWaitingForActivity = GetEntityQuery(new QueryHelper().All(typeof(CPet)).None(typeof(CPetInteractingWith))); + } + + protected override void OnUpdate() + { + using NativeArray petsWaitingForActivity = _petsWaitingForActivity.ToEntityArray(Allocator.Temp); + petsWaitingForActivity.ShuffleInPlace(); + + if (petsWaitingForActivity.Length == 0) return; + + Entity pet = petsWaitingForActivity[0]; + + if (!Require(pet, out CPet cPet)) return; + if (!GameData.Main.TryGet(cPet.PetType, out Pet petType)) return; + if (!Require(pet, out CPosition cPosition)) return; + if (!Require(pet, out CDefaultState cDefaultState)) return; + if (cPet.State != StateForUpdate) return; + + ActivityData data = new ActivityData + { + Pet = pet, + PetPosition = cPosition, + PetType = petType, + State = cPet.State + }; + + + if (IsPossible(data)) + { + if (Perform(data)) + { + return; + } + } + + + cPet.State = cDefaultState.State; + EntityManager.SetComponentData(pet, cPet); + } + + protected Dictionary GetAllEntitiesInRange(NativeArray entities, Vector3 startingPosition, float maxDistance = float.MaxValue, bool sortByDistance = true) + { + Dictionary entitiesInRange = new(); + + foreach (Entity entity in entities) + { + if (!Require(entity, out CPosition cPosition)) continue; + float distance = Vector3.Distance(startingPosition, cPosition); + if (distance > maxDistance) continue; + if (entitiesInRange.ContainsKey(distance)) continue; + entitiesInRange.Add(distance, entity); + } + + if (sortByDistance) + entitiesInRange = entitiesInRange.OrderBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); + + return entitiesInRange; + } + + protected bool CanGetTo(Vector3 startingPosition, Vector3 targetPosition, Vector3 targetOffset, out Vector3 targetDestination) + { + targetDestination = Vector3.zero; + CLayoutRoomTile tile1 = GetTile(targetPosition); + CLayoutRoomTile tile2 = GetTile(targetPosition + targetOffset); + if (tile1.RoomID != tile2.RoomID) return false; + + NavMesh.CalculatePath(startingPosition, targetPosition + targetOffset, NavMesh.AllAreas, Path); + + if (Path.status == NavMeshPathStatus.PathComplete) + targetDestination = targetPosition + targetOffset; + + return Path.status == NavMeshPathStatus.PathComplete; + } + + protected bool GetOffsetPosition(Vector3 forward, Vector2 offset, out Vector2 success) + { + success = Vector2.zero; + float rotation = Mathf.Atan2(forward.x, forward.z) * Mathf.Rad2Deg; + Mod.Logger.LogInfo("GetOffsetPosition " + rotation); + if (rotation == 0) + success = offset; + if (rotation == 90) + success = new Vector2(offset.y, -offset.x); + if (rotation == 180) + success = -offset; + if (rotation == 270) + success = new Vector2(-offset.y, offset.x); + return success != Vector2.zero; + } + } + + public struct ActivityData + { + public Entity Pet; + public CPosition PetPosition; + public Pet PetType; + public PetState State; + } +} \ No newline at end of file diff --git a/Systems/ProvidePetStaples.cs b/Systems/ProvidePetStaples.cs new file mode 100644 index 0000000..d2e31bc --- /dev/null +++ b/Systems/ProvidePetStaples.cs @@ -0,0 +1,97 @@ +using System.Collections.Generic; +using Kitchen; +using Kitchen.Layouts; +using KitchenData; +using KitchenLib.Utils; +using KitchenMods; +using Pets.Components.Properties; +using Pets.Customs; +using Unity.Collections; +using Unity.Entities; +using UnityEngine; + +namespace Pets.Systems +{ + public class ProvidePetStaples : StartOfNightSystem, IModSystem + { + private EntityQuery _staplePetAppliances; + protected override void Initialise() + { + base.Initialise(); + _staplePetAppliances = GetEntityQuery(typeof(CStapleAppliances)); + } + + protected override void OnUpdate() + { + + using NativeArray staplePetAppliances = _staplePetAppliances.ToEntityArray(Allocator.Temp); + + foreach (Entity staplePetAppliance in staplePetAppliances) + { + if (!Require(staplePetAppliance, out CStapleAppliances cStapleAppliances)) continue; + + foreach (int applianceID in cStapleAppliances.Appliances) + { + if (!(Random.value <= 0.3f * Time.DeltaTime)) continue; + + List postTiles = GetPostTiles(); + int num = 0; + Vector3 position = FindTile(ref num, postTiles); + CreateBlueprintLetter(EntityManager, position, applianceID, 0, 0, true); + } + } + } + + public Vector3 FindTile(ref int placed_tile, List floor_tiles) + { + Vector3 vector = default; + bool flag = false; + while (!flag && placed_tile < floor_tiles.Count) + { + int num = placed_tile; + placed_tile = num + 1; + vector = floor_tiles[num]; + if (GetOccupant(vector) != default) continue; + flag = true; + foreach (LayoutPosition pos in LayoutHelpers.Directions) + { + Entity occupant = GetOccupant(new Vector3(vector.x + pos.x, vector.y, vector.z + pos.y)); + if (occupant == default || !Has(occupant)) continue; + flag = false; + break; + } + } + + return !flag ? GetFallbackTile() : vector; + } + + public static Entity CreateBlueprintLetter(EntityManager em, Vector3 position, int appliance_id, float price_multiplier = 1f, int force_price = -1, bool use_red = false) + { + Entity entity = em.CreateEntity(); + em.AddComponentData(entity, new CCreateAppliance + { + ID = GDOUtils.GetCustomGameDataObject().ID + }); + em.AddComponentData(entity, new CPosition(position)); + em.AddComponentData(entity, default(CLetter)); + int num = 0; + Appliance appliance; + if (force_price >= 0) + { + num = force_price; + } + else if (GameData.Main.TryGet(appliance_id, out appliance, true)) + { + num = appliance.PurchaseCost; + } + em.AddComponentData(entity, new CLetterBlueprint + { + BlueprintID = AssetReference.Blueprint, + ApplianceID = appliance_id, + Price = Mathf.CeilToInt((float)num * price_multiplier) + }); + em.AddComponentData(entity, default(CShopEntity)); + return entity; + } + } +} \ No newline at end of file diff --git a/Systems/SelectActivity.cs b/Systems/SelectActivity.cs new file mode 100644 index 0000000..293e277 --- /dev/null +++ b/Systems/SelectActivity.cs @@ -0,0 +1,44 @@ +using Kitchen; +using KitchenMods; +using Pets.Components; +using Pets.Components.Properties; +using Pets.Components.Status; +using Pets.Enums; +using Unity.Collections; +using Unity.Entities; +using UnityEngine; + +namespace Pets.Systems +{ + public class SelectActivity : GameSystemBase, IModSystem + { + private EntityQuery _pets; + protected override void Initialise() + { + base.Initialise(); + _pets = GetEntityQuery(new QueryHelper().All(typeof(CPet)).None(typeof(CPetInteractingWith))); + } + + protected override void OnUpdate() + { + NativeArray pets = _pets.ToEntityArray(Allocator.Temp); + + foreach (Entity pet in pets) + { + if (!Require(pet, out CPet cPet)) continue; + if (!Require(pet, out CDefaultState cDefaultState)) continue; + if (cPet.State != cDefaultState.State) continue; + if (!Require(pet, out CActivities cActivities)) continue; + if (!(Random.value <= 0.03f * Time.DeltaTime)) continue; + + int activity = Random.Range(0, cActivities.Activities.Length); + activity = cActivities.Activities[activity]; + + cPet.State = (PetState)activity; + EntityManager.SetComponentData(pet, cPet); + } + + pets.Dispose(); + } + } +} \ No newline at end of file diff --git a/Systems/TeleportPetsToOwners.cs b/Systems/TeleportPetsToOwners.cs new file mode 100644 index 0000000..a9793e6 --- /dev/null +++ b/Systems/TeleportPetsToOwners.cs @@ -0,0 +1,40 @@ +using Kitchen; +using KitchenMods; +using Pets.Components; +using Unity.Collections; +using Unity.Entities; + +namespace Pets.Systems +{ + [UpdateInGroup(typeof(PostTransitionGroup))] + public class TeleportPetsToOwners : RestaurantSystem, IModSystem + { + private EntityQuery _pets; + protected override void Initialise() + { + base.Initialise(); + RequireSingletonForUpdate(); + _pets = GetEntityQuery(typeof(CPet)); + } + + protected override void OnUpdate() + { + using NativeArray pets = _pets.ToEntityArray(Allocator.Temp); + + foreach (Entity pet in pets) + { + if (!Require(pet, out CPet cPet)) continue; + if (cPet.Owner == Entity.Null) continue; + if (!Require(cPet.Owner, out CPosition cPosition)) continue; + if (!Require(pet, out CPosition cPetPosition)) continue; + + cPetPosition = new CPosition + { + Position = cPosition.Position, + ForceSnap = true + }; + EntityManager.SetComponentData(pet, cPetPosition); + } + } + } +} \ No newline at end of file diff --git a/UnityProject - Pets/ReadMe.txt b/UnityProject - Pets/ReadMe.txt new file mode 100644 index 0000000..a0d2de1 --- /dev/null +++ b/UnityProject - Pets/ReadMe.txt @@ -0,0 +1 @@ +Note : Due to licensing, I am required to omit the Unity Project from the Github Repository. \ No newline at end of file diff --git a/Utility/PetSnapshot.cs b/Utility/PetSnapshot.cs new file mode 100644 index 0000000..5339a8c --- /dev/null +++ b/Utility/PetSnapshot.cs @@ -0,0 +1,16 @@ +using Kitchen; +using UnityEngine; + +namespace Pets.Utility +{ + public static class PetSnapshot + { + public static Texture2D GetApplianceSnapshot(GameObject prefab) + { + int instanceID = prefab.GetInstanceID(); + Quaternion rotation = Quaternion.LookRotation(new Vector3(-1f, 1f, -1f), new Vector3(0f, 1f, 1f)); + SnapshotTexture snapshotTexture = Snapshot.RenderPrefabToTexture(512, 512, prefab, rotation, 0.5f, 0.5f, -10f, 10f, 1f, -0.25f * new Vector3(0f, 0, 1f)); + return snapshotTexture.Snapshot; + } + } +} \ No newline at end of file diff --git a/Views/PetEditorView.cs b/Views/PetEditorView.cs new file mode 100644 index 0000000..f5a26bc --- /dev/null +++ b/Views/PetEditorView.cs @@ -0,0 +1,202 @@ +using System.Collections.Generic; +using Controllers; +using Kitchen; +using Kitchen.Modules; +using KitchenMods; +using MessagePack; +using Pets.Components; +using Pets.Components.Menu; +using Pets.Menus; +using Unity.Collections; +using Unity.Entities; +using UnityEngine; + +namespace Pets.Views +{ + public class PetEditorView : ResponsiveObjectView, IInputConsumer + { + public class UpdateView : ResponsiveViewSystemBase, IModSystem + { + EntityQuery Views; + protected override void Initialise() + { + base.Initialise(); + Views = GetEntityQuery(typeof(CPetEditorInfo), typeof(CLinkedView)); + } + + protected override void OnUpdate() + { + using NativeArray entities = Views.ToEntityArray(Allocator.Temp); + using NativeArray views = Views.ToComponentDataArray(Allocator.Temp); + using NativeArray infos = Views.ToComponentDataArray(Allocator.Temp); + + foreach (Entity entity in entities) + { + if (!Require(entity, out CLinkedView cLinkedView)) continue; + if (!Require(entity, out CPetEditorInfo cPetEditorInfo)) continue; + + SendUpdate(cLinkedView.Identifier, new ViewData + { + Player = cPetEditorInfo.Player.PlayerID + }); + + ResponseData result = default(ResponseData); + + if (ApplyUpdates(cLinkedView, (data) => { result = data; }, only_final_update: true)) + { + cPetEditorInfo.IsComplete = result.IsComplete; + Set(entity, cPetEditorInfo); + + Entity stateRequest = EntityManager.CreateEntity(); + EntityManager.AddComponentData(stateRequest, new CRequestStateChange + { + PlayerID = result.PlayerID, + StateID = result.Option + }); + } + } + } + } + + [MessagePackObject(false)] + public struct ViewData : IViewData, IViewResponseData, IViewData.ICheckForChanges + { + [Key(0)] + public int Player; + + public bool IsChangedFrom(ViewData check) + { + return Player != check.Player; + } + } + + [MessagePackObject(false)] + public struct ResponseData : IResponseData, IViewResponseData + { + [Key(0)] + public bool IsComplete; + [Key(1)] + public int Option; + [Key(2)] + public int PlayerID; + } + + private struct MenuStackElement + { + public GridMenuEditorConfig Config; + + public int Index; + } + + public GridMenuEditorConfig rootMenuConfig; + public Transform container; + private EditorGridMenu _gridMenu; + private int _playerID; + private InputLock.Lock _lock; + private bool _isComplete; + private readonly Stack _menuStack = new Stack(); + private int _option; + + private void CloseMenu() + { + if (_menuStack.Count > 1) + { + int index = _menuStack.Pop().Index; + MenuStackElement menuStackElement = _menuStack.Pop(); + SetNewMenu(menuStackElement.Config, index, menuStackElement.Index); + } + else + { + Remove(); + } + } + + private void SetNewMenu(GridMenuEditorConfig menu, int newIndex, int previousIndex) + { + _gridMenu?.Destroy(); + _gridMenu = menu.Instantiate(delegate (int result) + { + _option = result; + CloseMenu(); + }, container, _playerID, _menuStack.Count > 0); + _gridMenu.OnRequestMenu += delegate (GridMenuConfig c) + { + if (c is GridMenuEditorConfig cApp) + SetNewMenu(cApp, 0, _gridMenu?.SelectedIndex() ?? 0); + }; + _gridMenu.OnGoBack += CloseMenu; + _gridMenu.SelectByIndex(newIndex); + _menuStack.Push(new MenuStackElement + { + Config = menu, + Index = previousIndex + }); + } + + protected override void UpdateData(ViewData data) + { + if (InputSourceIdentifier.DefaultInputSource == null) return; + if (!Players.Main.Get(data.Player).IsLocalUser) + { + gameObject.SetActive(value: false); + return; + } + gameObject.SetActive(value: true); + _option = 0; + InitialiseForPlayer(data.Player); + } + + private void InitialiseForPlayer(int player) + { + LocalInputSourceConsumers.Register(this); + if (_lock.Type != 0) + InputSourceIdentifier.DefaultInputSource.ReleaseLock(_playerID, _lock); + _playerID = player; + SetNewMenu(rootMenuConfig, 0, 0); + _lock = InputSourceIdentifier.DefaultInputSource.SetInputLock(_playerID, PlayerLockState.NonPause); + } + + public override void Remove() + { + _isComplete = true; + InputSourceIdentifier.DefaultInputSource.ReleaseLock(_playerID, _lock); + base.Remove(); + } + + private void OnDestroy() + { + LocalInputSourceConsumers.Remove(this); + } + + public InputConsumerState TakeInput(int playerID, InputState state) + { + if (_playerID == 0 || playerID != _playerID) return InputConsumerState.NotConsumed; + if (state.MenuTrigger == ButtonState.Pressed) + { + _isComplete = true; + InputSourceIdentifier.DefaultInputSource.ReleaseLock(_playerID, _lock); + return InputConsumerState.Terminated; + } + if (_gridMenu != null && !_gridMenu.HandleInteraction(state) && state.MenuCancel == ButtonState.Pressed) + { + CloseMenu(); + } + return !_isComplete ? InputConsumerState.Consumed : InputConsumerState.Terminated; + } + + public override bool HasStateUpdate(out IResponseData state) + { + state = null; + if (_isComplete) + { + state = new ResponseData + { + IsComplete = _isComplete, + Option = _option, + PlayerID = _playerID + }; + } + return _isComplete; + } + } +} diff --git a/Views/PetRequestView.cs b/Views/PetRequestView.cs new file mode 100644 index 0000000..4da5253 --- /dev/null +++ b/Views/PetRequestView.cs @@ -0,0 +1,88 @@ +using System; +using Kitchen; +using KitchenMods; +using MessagePack; +using Pets.Components; +using Pets.Systems; +using Unity.Collections; +using Unity.Entities; + +namespace Pets.Views +{ + public class PetRequestView : UpdatableObjectView, ISpecificViewResponse + { + public class UpdateView : ResponsiveViewSystemBase, IModSystem + { + EntityQuery Query; + protected override void Initialise() + { + base.Initialise(); + Query = GetEntityQuery(typeof(CLinkedView), typeof(SPetRequestView)); + } + + protected override void OnUpdate() + { + using NativeArray linkedViews = Query.ToComponentDataArray(Allocator.Temp); + + foreach (CLinkedView view in linkedViews) + { + SendUpdate(view.Identifier, new ViewData()); + if (ApplyUpdates(view.Identifier, PerformUpdateWithResponse, only_final_update: false)) { } + } + } + + private void PerformUpdateWithResponse(ResponseData data) + { + PetSelector.Main.CreatePlayerRequest(data.PlayerID, data.PetID); + } + } + + [MessagePackObject(false)] + public class ViewData : ISpecificViewData, IViewData.ICheckForChanges + { + public IUpdatableObject GetRelevantSubview(IObjectView view) + { + return view.GetSubView(); + } + + public bool IsChangedFrom(ViewData check) + { + return true; + } + } + + [MessagePackObject(false)] + public class ResponseData : IResponseData, IViewResponseData + { + [Key(0)] + public int PlayerID; + [Key(1)] + public int PetID; + } + + private Action Callback; + + public static int PlayerID = 0; + public static int PetID = 0; + + public ResponseData Cache; + + protected override void UpdateData(ViewData data) + { + Cache ??= new ResponseData(); + + if (Cache.PlayerID != PlayerID || Cache.PetID != PetID) + { + Cache.PlayerID = PlayerID; + Cache.PetID = PetID; + if (Callback != null) + Callback.Invoke(Cache, typeof(ResponseData)); + } + } + + public void SetCallback(Action callback) + { + Callback = callback; + } + } +} diff --git a/Views/PetView.cs b/Views/PetView.cs new file mode 100644 index 0000000..e508ee2 --- /dev/null +++ b/Views/PetView.cs @@ -0,0 +1,231 @@ +using System; +using Controllers; +using Kitchen; +using KitchenData; +using KitchenMods; +using MessagePack; +using Pets.Components; +using Pets.Enums; +using TMPro; +using Unity.Collections; +using Unity.Entities; +using UnityEngine; +using UnityEngine.AI; +using UnityEngine.VFX; + +namespace Pets.Views +{ + public class PetView : UpdatableObjectView, ISpecificViewResponse + { + public NavMeshAgent agent; + public Animator animator; + public VisualEffect vfx; + public GameObject warningIcon; + public TextMeshPro label; + + public override void SetPosition(UpdateViewPositionData pos) + { + if (!pos.Force && !((transform.localPosition - pos.Position).Chebyshev() > 0.5f)) return; + base.SetPosition(pos); + agent.Warp(pos.Position); + } + + protected override void UpdatePosition() { } + + public class UpdateView : ResponsiveViewSystemBase, IModSystem + { + private EntityQuery _pets; + + protected override void Initialise() + { + base.Initialise(); + _pets = GetEntityQuery(typeof(CLinkedView), typeof(CPet)); + } + + protected override void OnUpdate() + { + NativeArray pets = _pets.ToEntityArray(Allocator.Temp); + + foreach (Entity pet in pets) + { + if (!Require(pet, out CLinkedView cLinkedView) || !Require(pet, out CPet cPet) || !Require(pet, out CPosition cPosition)) continue; + + Vector3 TargetPosition = Vector3.zero; + Vector3 PreferedFacingDirection = Vector3.zero; + float StopDistance = 0; + bool ShouldMove = false; + int RequestingInputSource = 0; + + if (Require(pet, out CMoveToLocation cMoveToLocation)) + { + TargetPosition = cMoveToLocation.Location; + PreferedFacingDirection = cMoveToLocation.DesiredFacing; + StopDistance = cMoveToLocation.StoppingDistance; + ShouldMove = true; + } + + + if (Require(pet, out CRequestNameChange cRequestNameChange) && !cRequestNameChange.IsTriggered) + { + RequestingInputSource = cRequestNameChange.Source; + cRequestNameChange.IsTriggered = true; + EntityManager.AddComponentData(pet, cRequestNameChange); + } + + + SendUpdate(cLinkedView, new ViewData + { + TargetPosition = TargetPosition, + StopDistance = StopDistance, + IsMoving = ShouldMove, + PreferedFacingDirection = PreferedFacingDirection, + State = cPet.State, + RequestingInputSource = RequestingInputSource, + PetName = cPet.PetName.Value + }); + if (ApplyUpdates(cLinkedView, (data) => + { + EntityManager.AddComponentData(pet, new CCurrentSpeed + { + speed = data.Speed + }); + + if (data.UpdateName) + { + if (!Require(pet, out CPet cPet)) return; + cPet.PetName = data.PetName; + if (Require(pet, out CDefaultState cDefaultState)) + cPet.State = cDefaultState.State; + + EntityManager.AddComponentData(pet, cPet); + } + + if (Has(pet)) + { + EntityManager.RemoveComponent(pet); + } + }, only_final_update: false)) { } + } + + pets.Dispose(); + } + } + + [MessagePackObject(false)] + public class ViewData : ISpecificViewData, IViewData.ICheckForChanges + { + public IUpdatableObject GetRelevantSubview(IObjectView view) + { + return view.GetSubView(); + } + + public bool IsChangedFrom(ViewData check) + { + return true; + } + + [Key(0)] public bool IsMoving; + [Key(1)] public Vector3 TargetPosition; + [Key(2)] public float StopDistance; + [Key(3)] public Vector3 PreferedFacingDirection; + [Key(4)] public PetState State; + [Key(5)] public int RequestingInputSource; + [Key(6)] public string PetName; + } + + [MessagePackObject(false)] + public class ResponseData : IResponseData, IViewResponseData + { + [Key(0)] public float Speed; + [Key(1)] public string PetName; + [Key(2)] public bool UpdateName; + } + + private static readonly int Speed = Animator.StringToHash("Speed"); + private static readonly int Eating = Animator.StringToHash("Eating"); + private static readonly int Sleeping = Animator.StringToHash("Sleeping"); + + private ViewData Data; + + protected override void UpdateData(ViewData viewData) + { + Data = viewData; + + if (Data == null) return; + + if (Data.RequestingInputSource == InputSourceIdentifier.Identifier) + { + TextInputView.RequestTextInput(base.Localisation["INPUT_TITLE_RENAME_RESTAURANT"], "", 24, HandleNewName); + } + } + + private void HandleNewName(TextInputView.TextInputState state, string result) + { + if (state != TextInputView.TextInputState.TextEntryComplete) return; + + Cache ??= new ResponseData(); + Cache.PetName = result; + Cache.UpdateName = true; + if (Callback != null) + Callback?.Invoke(Cache, typeof(ResponseData)); + } + + private Action Callback; + public void SetCallback(Action callback) + { + Callback = callback; + } + + public ResponseData Cache; + + private void Update() + { + if (Data == null) return; + + Cache ??= new ResponseData(); + + if (Data.PetName == Cache.PetName) + Cache.UpdateName = false; + + if (agent != null) + { + if (Cache.Speed != agent.velocity.magnitude) + { + Cache.Speed = agent.velocity.magnitude; + if (Callback != null) + Callback.Invoke(Cache, typeof(ResponseData)); + } + + if (Data.TargetPosition != Vector3.zero && Data.IsMoving) + { + agent.stoppingDistance = Data.StopDistance; + agent.SetDestination(Data.TargetPosition); + } + + if (agent.remainingDistance <= agent.stoppingDistance && Data.PreferedFacingDirection != Vector3.zero) + { + transform.rotation = Quaternion.LookRotation(Data.PreferedFacingDirection - transform.position, Vector3.up); + } + } + + if (animator != null && agent != null) + { + animator.SetFloat(Speed, agent.velocity.magnitude); + animator.SetBool(Eating, Data.State == PetState.Eat && agent.velocity.magnitude < Mod.MinimumSpeedThreshold); + animator.SetBool(Sleeping, Data.State == PetState.Sleep && agent.velocity.magnitude < Mod.MinimumSpeedThreshold); + } + + if (vfx != null) + vfx.enabled = Data.State == PetState.Sleep && agent.velocity.magnitude < Mod.MinimumSpeedThreshold; + + if (warningIcon != null) + warningIcon.SetActive(Data.State is PetState.Error); + + if (label != null) + { + label.font = GameData.Main.GlobalLocalisation.Fonts[KitchenData.Font.Default]; + label.text = Data.PetName; + } + } + } +} \ No newline at end of file