Initial commit.
This commit is contained in:
commit
0aad97fa48
20
.gitattributes
vendored
Normal file
20
.gitattributes
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
*.psd filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.spine filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.dds filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.bank filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.wav filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.dll filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.lib filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.a filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.prx filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.exe filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.elf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ogv filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.gif filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.xcf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.font filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.gnf filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.vcxproj.filters merge=union
|
352
.gitignore
vendored
Normal file
352
.gitignore
vendored
Normal file
@ -0,0 +1,352 @@
|
|||||||
|
## 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/master/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/
|
||||||
|
[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/
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.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
|
||||||
|
|
||||||
|
# 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 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/
|
||||||
|
|
||||||
|
# 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/
|
||||||
|
*.gqs
|
||||||
|
docs/
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Tim Ambrogi
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
220
README.md
Normal file
220
README.md
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
# SquidTasks 0.2.0
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
About Squid::Tasks
|
||||||
|
=================
|
||||||
|
|
||||||
|
Squid::Tasks is a header-only C++ library that implements high-level coroutine-based tasks. It was originally designed for use in video game development, but has uses within various other problem domains.
|
||||||
|
|
||||||
|
Squid::Tasks was written by Tim Ambrogi Saxon and Elliott Mahler at Giant Squid Studios, and is freely available under the MIT license.
|
||||||
|
|
||||||
|
Overview of Squid::Tasks
|
||||||
|
========================
|
||||||
|
|
||||||
|
Squid::Tasks is a header-only library consisting of several top-level headers within the include directory.
|
||||||
|
|
||||||
|
- ```Task.h``` - Task-handles and standard awaiters [REQUIRED]
|
||||||
|
- ```TaskManager.```h - Manager that runs and resumes a collection of tasks
|
||||||
|
- ```TokenList.h``` - Data structure for tracking decentralized state across multiple tasks
|
||||||
|
- ```FunctionGuard.h``` - Scope guard that calls a function as it leaves scope
|
||||||
|
- ```TaskFSM.h``` - Finite state machine that implements states using task factories
|
||||||
|
|
||||||
|
Sample projects can be found under the @c /samples directory.
|
||||||
|
|
||||||
|
Integrating Squid::Tasks
|
||||||
|
========================
|
||||||
|
|
||||||
|
Including the Headers
|
||||||
|
-------------------
|
||||||
|
To integrate the Squid::Tasks library into your project, we recommend first copying the entire include directory into your project. You must then add the path of the include directory to the list of include directories in your project.
|
||||||
|
|
||||||
|
In __Visual Studio__, this is done by right-clicking your project and selecting Properties. Then navigate to Configuration Properties -> C/C++ -> General, and add the the path to the include directory to “Additional Include Directories”.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Enabling Coroutines for C++14/17 (skip this step if using C++20)
|
||||||
|
----------------------------------------------------------------
|
||||||
|
C++ coroutines were only formally added to the standard with C++20. In order to use them with earlier standards (C++14 or C++17), you must enable coroutines using a special compiler-specific compile flag.
|
||||||
|
|
||||||
|
In __Visual Studio__, this is done by right-clicking your project and selecting Properties. Then navigate to Configuration Properties -> C/C++ -> Command Line, and add ```/await:strict``` to “Additional Options”:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
If you are using __Clang__, you will need to add -fcoroutines-ts to your compiler command-line compilation parameters.
|
||||||
|
|
||||||
|
If you are using the __Clang Platform Toolset__ from within Visual Studio, you will need to add -Xclang -fcoroutines-ts to your compiler command-line compilation parameters.
|
||||||
|
|
||||||
|
Configure Squid::Tasks with TasksConfig.h
|
||||||
|
-----------------------------------------
|
||||||
|
The Squid::Tasks library can be configured in a variety of important ways. This is done by enabling and disabling preprocessor values within the include/TasksConfig.h file:
|
||||||
|
|
||||||
|
- **SQUID_ENABLE_TASK_DEBUG**: Enables Task debug callstack tracking and debug names via Task::GetDebugStack() and Task::GetDebugName()
|
||||||
|
- **SQUID_ENABLE_DOUBLE_PRECISION_TIME**: Switches time representation from 32-bit single-precision floats to 64-bit double-precision floats
|
||||||
|
- **SQUID_ENABLE_NAMESPACE**: Enables a Squid:: namespace around all classes in the Squid::Tasks library
|
||||||
|
- **SQUID_USE_EXCEPTIONS**: Enables experimental (largely-untested) exception-handling, and replaces all asserts with runtime_error exceptions
|
||||||
|
- **SQUID_ENABLE_GLOBAL_TIME**: Enables global time support (alleviating the need to specify a time stream for time-sensitive awaiters) **[see Appendix A for more details]**
|
||||||
|
|
||||||
|
An Example First Task
|
||||||
|
=====================
|
||||||
|
|
||||||
|
To get started using Squid::Tasks, the first step is to write and execute your first task from within your project. Many modern C++ game engines feature some sort of "actor" class - a game entity that exists within the scene and is updated each frame. Our example code assume this class exists, but the same principles will apply for projects that are written under a different paradigm.
|
||||||
|
|
||||||
|
The first step is to identify an actor class that would benefit from coroutine support, such as an enemy actor. Here is an example Enemy class from a hypothetical 2D game:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Enemy : public Actor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void SetRotation(float in_degrees); // Set the rotation of the enemy
|
||||||
|
float GetRotation() const; // Get the rotation of the enemy
|
||||||
|
void SetPosition(Vec2f in_pos); // Set the position of the enemy
|
||||||
|
Vec2f GetPosition() const; // Get the position of th enemy
|
||||||
|
void MoveToward(Vec2f in_pos, float in_speed, float in_dt) const; // Move toward a target position at a given speed
|
||||||
|
void FireProjectileAt(Vec2f in_pos); // Fire a simple projectile to a target position
|
||||||
|
std::shared_ptr<Player> GetPlayer() const; // Get the location of the player actor
|
||||||
|
float GameTime() const; // Get the current game time (in seconds)
|
||||||
|
float DeltaTime() const; // Get the current frame's delta-time (in seconds)
|
||||||
|
|
||||||
|
virtual void OnInitialize() override // Automatically called when this enemy enters the scene
|
||||||
|
{
|
||||||
|
Actor::OnInitialize(); // Call the base Actor function
|
||||||
|
}
|
||||||
|
virtual void Tick(float in_dt) override // Automatically called every frame
|
||||||
|
{
|
||||||
|
Actor::Tick(in_dt); // Call the base Actor function
|
||||||
|
}
|
||||||
|
virtual void OnDestroy() override // Automatically called when this enemy leaves the scene
|
||||||
|
{
|
||||||
|
Actor::OnDestroy(); // Call the base Actor function
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
We want to try writing a simple enemy AI using Squid::Tasks. Conventionally, the ```Tick()``` function would be responsible for performing all AI logic calculations, so we will use that as the entry-point into our first task coroutine. First, we will create a ```TaskManager``` as a private member m_taskMgr. Then, we call ```m_taskMgr.Update()``` from within ```Tick()```. Lastly, we need to make sure all of tasks stop running as soon as the enemy leaves the scene, so we call ```m_taskMgr.KillAllTasks()``` from within ```OnDestroy()```.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Enemy : public Actor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// ...
|
||||||
|
|
||||||
|
virtual void Tick(float in_dt) override // Automatically called every frame
|
||||||
|
{
|
||||||
|
Actor::Tick(in_dt); // Call the base Actor function
|
||||||
|
m_taskMgr.Update(); // Resume all active tasks once per tick
|
||||||
|
}
|
||||||
|
virtual void OnDestroy() override // Automatically called when this enemy leaves the scene
|
||||||
|
{
|
||||||
|
m_taskMgr.KillAllTasks(); // Kill all active tasks when we leave the scene
|
||||||
|
Actor::OnDestroy(); // Call the base Actor function
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TaskManage m_taskMgr;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Now that we have the task manager hooked up, we can write and run our first task. Let's make our first task very simple, and just have it print out a string and then terminate. To create a task, we simply write a member function with returns type ```Task<>```, and make sure to use at least one co_await or co_return keyword within the function body. This tells the compiler to compile the function as a coroutine with Task<> as the handle type for the coroutine.
|
||||||
|
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Enemy : public Actor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// ...
|
||||||
|
|
||||||
|
virtual void OnInitialize() override // Automatically called when this enemy enters the scene
|
||||||
|
{
|
||||||
|
Actor::OnInitialize(); // Call the base Actor function
|
||||||
|
m_taskMgr.RunManaged(ManageEnemyAI()); // Run our task as a fire-and-forget "managed task"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
Task<> ManageEnemyAI()
|
||||||
|
{
|
||||||
|
TASK_NAME(__FUNCTION__); // Gives the task a name for debugging purposes
|
||||||
|
|
||||||
|
printf("Hello, enemy AI!\n");
|
||||||
|
co_return; // Return from this task
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
With these changes, any enemy instance that enters the scene will print "Hello, enemy AI!". Note that we actually run the task from within ```OnInitialize()```. This line is what actually instantiates the task and tells the task manager to update it every frame. Now that we have the complete scaffolding in, we can try to write an actual enemy behavior. Let's try writing a simple chase AI that chases the player if they get too close to the enemy.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Enemy : public Actor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// ...
|
||||||
|
|
||||||
|
Task<> ManageEnemyAI()
|
||||||
|
{
|
||||||
|
TASK_NAME(__FUNCTION__); // Gives the task a name for debugging purposes
|
||||||
|
|
||||||
|
while(true) // This "infinite loop" means this task should run for the enemy's lifetime
|
||||||
|
{
|
||||||
|
// Wait until player gets within a 100-pixel radius
|
||||||
|
co_await WaitUntil([&] {
|
||||||
|
return Distance(GetPlayer()->GetPosition(), GetPosition()) < 100.0f;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move toward the player as long as they are within a 100-pixel radius
|
||||||
|
while(Distance(GetPlayer()->GetPosition(), GetPosition()) < 100.0f)
|
||||||
|
{
|
||||||
|
MoveToward(GetPlayer()->GetPosition(), 100.0f, DeltaTime());
|
||||||
|
co_await Suspend();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cool-down for 2 seconds before following again
|
||||||
|
co_await WaitSeconds(2.0f, GameTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Our chase enemy AI is complete! One advantage of coroutines is that they tend to be fairly straightforward to read, so hopefully you can guess at what some of the above logic means. Regardless, let's break down how this works. The first thing we do is create a while(true) loop around our logic. This is a common coroutine pattern, but it can be confusing the first time you see it. In a normal function, an infinite loop would result in the thread soft-locking. However, in coroutines this pattern essentially means "this coroutine will run for the lifetime of the object running it", which is the desired behavior for our enemy AI task.
|
||||||
|
|
||||||
|
The next thing we see is the new ```co_await``` keyword. The ```co_await <awaiter>``` expression, when evaluated, will suspend the current task until the awaiter is ready to be resumed again. In this example we use 3 of the most versatile and powerful awaiters in Squid::Tasks:
|
||||||
|
|
||||||
|
- Suspend() -> Waits until the next time the task is resumed (usually a single frame)
|
||||||
|
- WaitSeconds() -> Waits until N seconds have passed in a given time-stream
|
||||||
|
- WaitUntil() -> Waits until a given function returns true
|
||||||
|
|
||||||
|
With these 3 awaiters, it is possible to implement enormously complex state machines with relatively straightforward code. (To learn about the other awaiters that come with Squid::Tasks, refer to the \ref Awaiters documentation.)
|
||||||
|
|
||||||
|
Next Steps
|
||||||
|
==========
|
||||||
|
|
||||||
|
Hopefully, this brief tutorial has given you an outline of the steps required to integrate coroutines into your own projects. From here, we recommend exploring the "GeneriQuest" sample project under ```samples/Sample_TextGame```. It demonstrates both simple and complex applications of coroutines in a simple text-based game example.
|
||||||
|
|
||||||
|
This is the end of the tutorial documentation (for now)! If you made it this far, please contact us at tim@giantsquidstudios.com to let us know any ways in which our documentation could have been more useful for you in learning to use Squid::Tasks!
|
||||||
|
|
||||||
|
Thank you for being one of our "early readers!" We appreciate your help in making this library a success. :)
|
||||||
|
|
||||||
|
Appendices
|
||||||
|
==========
|
||||||
|
|
||||||
|
APPENDIX A: Enabling Global Time Support
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
Every game project has its own method of updating and measuring game time. Most games feature multiple different "time-streams", such as "game time", "real time", "editor time", "paused time", "audio time", etc... Because of this, the Squid::Tasks library requires each time-sensitive awaiter (e.g. ```WaitSeconds()```, ```Timeout()```, etc) to be presented with a time-stream function that returns the current time in the desired time-stream. By convention, these time-streams are passed as functions into the final argument of time-sensitive awaiters.
|
||||||
|
|
||||||
|
A final (optional) step of integrating Squid::Tasks is to enable global time support and implement a global Squid::GetTime() function.
|
||||||
|
|
||||||
|
For less-complex projects it can be desirable to default to a "global time-stream" that removes the requirement to explicitly pass a time-stream function into time-sensitive awaiters. To enable this functionality, the user must set ```SQUID_ENABLE_GLOBAL_TIME``` in TasksConfig.h and implement a special function called Squid::GetTime(). Failure to define this function will result in a linker error.
|
||||||
|
|
||||||
|
The Squid::GetTime() function should return a floating-point value representing the number of seconds since the program started running. Here is an example Squid::GetTime() function implementation from within the ```main.cpp``` file of a sample project:
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.cpp
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
tTaskTime GetTime()
|
||||||
|
{
|
||||||
|
return (tTaskTime)TimeSystem::GetTime();
|
||||||
|
}
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
It is recommended to save off the current time value at the start of each game frame, returning that saved value from within ```Squid::GetTime()```. The reason for this is that, within a single frame, you likely want all of the tasks to behave as if they are updating at the same time. By providing the same exact time value to all Tasks that are resumed within a given update, the software is more likely to behave in a stable and predictable manner.
|
3
images/setup01.png
Normal file
3
images/setup01.png
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:32d4bd5fbf3b3fde29e4ef61a333c95d6bd3ecc4a6e397eaa948f53e11713b1c
|
||||||
|
size 14467
|
3
images/setup02.png
Normal file
3
images/setup02.png
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:b6eb86da0d21d6dd2688ca22d2456cb49a24fde6bf109d891b9d826a1f3f0d49
|
||||||
|
size 17307
|
128
include/FunctionGuard.h
Normal file
128
include/FunctionGuard.h
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @defgroup FunctionGuard Function Guard
|
||||||
|
/// @brief Scope guard that calls a function as it leaves scope.
|
||||||
|
/// @{
|
||||||
|
///
|
||||||
|
/// A FunctionGuard is an scope guard object that stores a functor that will be called from its destructor. By
|
||||||
|
/// convention, scope guards are move-only objects that are intended for allocation on the stack, to ensure that certain
|
||||||
|
/// operations are performed exactly once (when their scope collapses).
|
||||||
|
///
|
||||||
|
/// Because tasks can be canceled while suspended (and thus do not reach the end of the function), any cleanup code at
|
||||||
|
/// the end of a task isn't guaranteed to execute. Because FunctionGuard is an RAII object, it gives programmers an
|
||||||
|
/// opportunity to schedule guaranteed cleanup code, no matter how a task terminates.
|
||||||
|
///
|
||||||
|
/// Consider the following example of a task that manages a character's "charge attack" in a combat-oriented game:
|
||||||
|
///
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||||
|
///
|
||||||
|
/// class Character : public Actor
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
/// Task<> ChargeAttackState()
|
||||||
|
/// {
|
||||||
|
/// bool bIsFullyCharged = false;
|
||||||
|
/// if(Input->IsAttackButtonPressed())
|
||||||
|
/// {
|
||||||
|
/// StartCharging(); // Start playing charge effects
|
||||||
|
/// auto stopChargingGuard = MakeFnGuard([&]{
|
||||||
|
/// StopCharging(); // Stop playing charge effects
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// // Wait for N seconds (canceling if button is no longer held)
|
||||||
|
/// bIsFullyCharged = co_await WaitSeconds(chargeTime).CancelIf([&] {
|
||||||
|
/// return !Input->IsAttackButtonPressed();
|
||||||
|
/// });
|
||||||
|
/// } // <-- This is when StopCharging() will be called
|
||||||
|
/// FireShot(bIsFullyCharged);
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
///
|
||||||
|
/// In the above example, we can guarantee that StopCharging will logically be called exactly once for every call to
|
||||||
|
/// StartCharging(), even the ChargeAttackState() task is killed or canceled. Furthermore, we know that StopCharging()
|
||||||
|
/// will always be called prior to the call to FireShot().
|
||||||
|
///
|
||||||
|
/// In practice, it is often desirable to create more domain-specific scope guards for specific use cases, but
|
||||||
|
/// FunctionGuard provides a simple general-purpose tool for writing robust, water-tight coroutine logic without the
|
||||||
|
/// overhead of creating bespoke support classes.
|
||||||
|
|
||||||
|
//--- User configuration header ---//
|
||||||
|
#include "TasksConfig.h"
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
|
||||||
|
template <typename tFn = TFunction<void()>>
|
||||||
|
class FunctionGuard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FunctionGuard() = default; /// Default constructor
|
||||||
|
FunctionGuard(nullptr_t) /// Null-pointer constructor
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FunctionGuard(tFn in_fn) /// Functor constructor
|
||||||
|
: m_fn(MoveTemp(in_fn))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~FunctionGuard() /// Destructor
|
||||||
|
{
|
||||||
|
Execute();
|
||||||
|
}
|
||||||
|
FunctionGuard(FunctionGuard&& in_other) noexcept /// Move constructor
|
||||||
|
: m_fn(MoveTemp(in_other.m_fn))
|
||||||
|
{
|
||||||
|
in_other.Forget();
|
||||||
|
}
|
||||||
|
FunctionGuard& operator=(FunctionGuard<tFn>&& in_other) noexcept /// Move assignment operator
|
||||||
|
{
|
||||||
|
m_fn = MoveTemp(in_other.m_fn);
|
||||||
|
in_other.Forget();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
FunctionGuard& operator=(nullptr_t) noexcept /// Null-pointer assignment operator (calls Forget() to clear the functor)
|
||||||
|
{
|
||||||
|
Forget();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
operator bool() const /// Convenience conversion operator that calls IsBound()
|
||||||
|
{
|
||||||
|
return IsBound();
|
||||||
|
}
|
||||||
|
bool IsBound() noexcept /// Returns whether functor has been bound to this FunctionGuard
|
||||||
|
{
|
||||||
|
return m_fn;
|
||||||
|
}
|
||||||
|
void Execute() /// Executes and clears the functor (if bound)
|
||||||
|
{
|
||||||
|
if(m_fn)
|
||||||
|
{
|
||||||
|
m_fn.GetValue()();
|
||||||
|
Forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Forget() noexcept /// Clear the functor (without calling it)
|
||||||
|
{
|
||||||
|
m_fn.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TOptional<tFn> m_fn; // The function to call when this scope guard is destroyed
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create a function guard (directly stores the concretely-typed functor in the FunctionGuard)
|
||||||
|
template <typename tFn>
|
||||||
|
FunctionGuard<tFn> MakeFnGuard(tFn in_fn)
|
||||||
|
{
|
||||||
|
return FunctionGuard<tFn>(MoveTemp(in_fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a generic function guard (preferable when re-assigning new functor values to the same variable)
|
||||||
|
inline FunctionGuard<> MakeGenericFnGuard(TFunction<void()> in_fn)
|
||||||
|
{
|
||||||
|
return FunctionGuard<>(MoveTemp(in_fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
|
||||||
|
///@} end of FunctionGuard group
|
220
include/Private/TaskFSMPrivate.h
Normal file
220
include/Private/TaskFSMPrivate.h
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
// WARNING: This is an internal implementation header, which must be included from a specific location/namespace
|
||||||
|
// That is the reason that this header does not contain a #pragma once, nor namespace guards
|
||||||
|
|
||||||
|
// Helper struct representing a transition event to a new FSM state
|
||||||
|
struct TransitionEvent
|
||||||
|
{
|
||||||
|
Task<> newTask;
|
||||||
|
StateId newStateId;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base class for defining links between states
|
||||||
|
class LinkBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~LinkBase() = default;
|
||||||
|
virtual TOptional<TransitionEvent> EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Type-safe link handle
|
||||||
|
class LinkHandle
|
||||||
|
{
|
||||||
|
bool IsOnCompleteLink() const
|
||||||
|
{
|
||||||
|
return m_linkType == eType::OnComplete;
|
||||||
|
}
|
||||||
|
bool HasCondition() const
|
||||||
|
{
|
||||||
|
return m_isConditionalLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Link-type enum
|
||||||
|
enum class eType
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
OnComplete,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Friends
|
||||||
|
template<class, class> friend class StateHandle;
|
||||||
|
friend class ::TaskFSM;
|
||||||
|
|
||||||
|
// Constructors (friend-only)
|
||||||
|
LinkHandle() = delete;
|
||||||
|
LinkHandle(TSharedPtr<LinkBase> in_link, eType in_linkType, bool in_isConditional)
|
||||||
|
: m_link(MoveTemp(in_link))
|
||||||
|
, m_linkType(in_linkType)
|
||||||
|
, m_isConditionalLink(in_isConditional)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
TOptional<TransitionEvent> EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const
|
||||||
|
{
|
||||||
|
return m_link->EvaluateLink(in_onTransitionFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TSharedPtr<LinkBase> m_link; // The underlying link
|
||||||
|
eType m_linkType; // Whether the link is normal or OnComplete
|
||||||
|
bool m_isConditionalLink; // Whether the link has an associated condition predicate
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal FSM state object
|
||||||
|
template<class tStateInput, class tStateConstructorFn>
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
State(tStateConstructorFn in_stateCtorFn, StateId in_stateId, FString in_debugName)
|
||||||
|
: stateCtorFn(in_stateCtorFn)
|
||||||
|
, stateId(in_stateId)
|
||||||
|
, debugName(in_debugName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
tStateConstructorFn stateCtorFn;
|
||||||
|
StateId stateId;
|
||||||
|
FString debugName;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal FSM state object (exit state specialization)
|
||||||
|
template<>
|
||||||
|
struct State<void, void>
|
||||||
|
{
|
||||||
|
State(StateId in_stateId, FString in_debugName)
|
||||||
|
: stateId(in_stateId)
|
||||||
|
, debugName(in_debugName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
StateId stateId;
|
||||||
|
FString debugName;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal link definition object
|
||||||
|
template<class ReturnT, class tStateConstructorFn, class tPredicateFn>
|
||||||
|
class Link : public LinkBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Link(TSharedPtr<State<ReturnT, tStateConstructorFn>> in_targetState, tPredicateFn in_predicate)
|
||||||
|
: m_targetState(MoveTemp(in_targetState))
|
||||||
|
, m_predicate(in_predicate)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual TOptional<TransitionEvent> EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const final
|
||||||
|
{
|
||||||
|
TOptional<TransitionEvent> result;
|
||||||
|
if(TOptional<ReturnT> payload = m_predicate())
|
||||||
|
{
|
||||||
|
if(in_onTransitionFn)
|
||||||
|
{
|
||||||
|
in_onTransitionFn();
|
||||||
|
}
|
||||||
|
result = TransitionEvent{ m_targetState->stateCtorFn(payload.GetValue()), m_targetState->stateId };
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedPtr<State<ReturnT, tStateConstructorFn>> m_targetState;
|
||||||
|
tPredicateFn m_predicate;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal link definition object (no-payload specialization)
|
||||||
|
template<class tStateConstructorFn, class tPredicateFn>
|
||||||
|
class Link<void, tStateConstructorFn, tPredicateFn> : public LinkBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Link(TSharedPtr<State<void, tStateConstructorFn>> in_targetState, tPredicateFn in_predicate)
|
||||||
|
: m_targetState(MoveTemp(in_targetState))
|
||||||
|
, m_predicate(in_predicate)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual TOptional<TransitionEvent> EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const final
|
||||||
|
{
|
||||||
|
TOptional<TransitionEvent> result;
|
||||||
|
if(m_predicate())
|
||||||
|
{
|
||||||
|
if(in_onTransitionFn)
|
||||||
|
{
|
||||||
|
in_onTransitionFn();
|
||||||
|
}
|
||||||
|
result = TransitionEvent{ m_targetState->stateCtorFn(), m_targetState->stateId };
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedPtr<State<void, tStateConstructorFn>> m_targetState;
|
||||||
|
tPredicateFn m_predicate;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal link definition object (exit-state specialization)
|
||||||
|
template<class tPredicateFn>
|
||||||
|
class Link<void, void, tPredicateFn> : public LinkBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Link(TSharedPtr<State<void, void>> in_targetState, tPredicateFn in_predicate)
|
||||||
|
: m_targetState(MoveTemp(in_targetState))
|
||||||
|
, m_predicate(in_predicate)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual TOptional<TransitionEvent> EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const final
|
||||||
|
{
|
||||||
|
TOptional<TransitionEvent> result;
|
||||||
|
if(m_predicate())
|
||||||
|
{
|
||||||
|
if(in_onTransitionFn)
|
||||||
|
{
|
||||||
|
in_onTransitionFn();
|
||||||
|
}
|
||||||
|
result = TransitionEvent{ Task<>(), m_targetState->stateId };
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedPtr<State<void, void>> m_targetState;
|
||||||
|
tPredicateFn m_predicate;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialized type traits that deduce the first argument type of an arbitrary callable type
|
||||||
|
template <typename tRet, typename tArg>
|
||||||
|
static tArg get_first_arg_type(TFunction<tRet(tArg)> f); // Return type is first argument type
|
||||||
|
|
||||||
|
template <typename tRet>
|
||||||
|
static void get_first_arg_type(TFunction<tRet()> f); // Return type is void (function has no arguments)
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct function_traits : public function_traits<decltype(&T::operator())> // Generic callable objects (use operator())
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tRet, typename... tArgs> // Function
|
||||||
|
struct function_traits<tRet(tArgs...)>
|
||||||
|
{
|
||||||
|
using tFunction = TFunction<tRet(tArgs...)>;
|
||||||
|
using tArg = decltype(get_first_arg_type(tFunction()));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tRet, typename... tArgs> // Function ptr
|
||||||
|
struct function_traits<tRet(*)(tArgs...)>
|
||||||
|
{
|
||||||
|
using tFunction = TFunction<tRet(tArgs...)>;
|
||||||
|
using tArg = decltype(get_first_arg_type(tFunction()));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tClass, typename tRet, typename... tArgs> // Member function ptr (const)
|
||||||
|
struct function_traits<tRet(tClass::*)(tArgs...) const>
|
||||||
|
{
|
||||||
|
using tFunction = TFunction<tRet(tArgs...)>;
|
||||||
|
using tArg = decltype(get_first_arg_type(tFunction()));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tClass, typename tRet, typename... tArgs> // Member function ptr
|
||||||
|
struct function_traits<tRet(tClass::*)(tArgs...)>
|
||||||
|
{
|
||||||
|
using tFunction = TFunction<tRet(tArgs...)>;
|
||||||
|
using tArg = decltype(get_first_arg_type(tFunction()));
|
||||||
|
};
|
896
include/Private/TaskPrivate.h
Normal file
896
include/Private/TaskPrivate.h
Normal file
@ -0,0 +1,896 @@
|
|||||||
|
// WARNING: This is an internal implementation header, which must be included from a specific location/namespace
|
||||||
|
// That is the reason that this header does not contain a #pragma once, nor namespace guards
|
||||||
|
|
||||||
|
enum class eTaskRef;
|
||||||
|
template <typename tRet> class TaskPromise;
|
||||||
|
class TaskInternalBase;
|
||||||
|
template <typename tRet> class TaskInternal;
|
||||||
|
|
||||||
|
//--- tTaskReadyFn ---//
|
||||||
|
using tTaskReadyFn = TFunction<bool()>;
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto CancelTaskIf(Task<tRet, RefType, Resumable>&& in_task, tTaskCancelFn in_cancelFn);
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto StopTaskIf(Task<tRet, RefType, Resumable>&& in_task, tTaskCancelFn in_cancelFn);
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable, typename tTimeFn>
|
||||||
|
auto StopTaskIf(Task<tRet, RefType, Resumable>&& in_task, tTaskCancelFn in_cancelFn, tTaskTime in_timeout, tTimeFn in_timeFn);
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable, typename T>
|
||||||
|
auto StopTaskIf(Task<tRet, RefType, Resumable>&& in_task, tTaskCancelFn in_cancelFn, tTaskTime in_timeout);
|
||||||
|
|
||||||
|
//--- Suspend-If Awaiter ---//
|
||||||
|
struct SuspendIf
|
||||||
|
{
|
||||||
|
SuspendIf(bool in_suspend)
|
||||||
|
: m_suspend(in_suspend)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
bool await_ready() noexcept { return !m_suspend; }
|
||||||
|
void await_suspend(std::coroutine_handle<>) noexcept {}
|
||||||
|
void await_resume() noexcept {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_suspend;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- Task Debug Stack Formatter ---//
|
||||||
|
struct TaskDebugStackFormatter
|
||||||
|
{
|
||||||
|
// Format function (formats a debug output string) [virtual]
|
||||||
|
virtual FString Format(const FString& in_str) const
|
||||||
|
{
|
||||||
|
FString result = Indent(0);
|
||||||
|
int32_t indent = 0;
|
||||||
|
int32_t start = 0;
|
||||||
|
int32_t found = 0;
|
||||||
|
while((found = in_str.FindChar('\n', start)) != INDEX_NONE)
|
||||||
|
{
|
||||||
|
int32_t end = found + 1;
|
||||||
|
if((found < in_str.Len() - 1) && (in_str[found + 1] == '`')) // indent
|
||||||
|
{
|
||||||
|
++indent;
|
||||||
|
++end;
|
||||||
|
}
|
||||||
|
else if((found >= 1) && (in_str[found - 1] == '`')) // dedent
|
||||||
|
{
|
||||||
|
--indent;
|
||||||
|
--found;
|
||||||
|
}
|
||||||
|
result += in_str.Mid(start, found - start) + '\n' + Indent(indent);
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
result += in_str.Mid(start);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
virtual FString Indent(int32_t in_indent) const
|
||||||
|
{
|
||||||
|
return FString::ChrN(in_indent * 2, ' ');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static FString FormatDebugString(FString in_str)
|
||||||
|
{
|
||||||
|
in_str.ReplaceCharInline('\n', ' ');
|
||||||
|
in_str.LeftChopInline(32, false);
|
||||||
|
return in_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- SetDebugName Awaiter ---//
|
||||||
|
#if SQUID_ENABLE_TASK_DEBUG
|
||||||
|
struct SetDebugName
|
||||||
|
{
|
||||||
|
// Sets a Task's debug name field
|
||||||
|
SetDebugName(const char* in_name)
|
||||||
|
: m_name(in_name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
SetDebugName(const char* in_name, TFunction<FString()> in_dataFn)
|
||||||
|
: m_name(in_name)
|
||||||
|
, m_dataFn(in_dataFn)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename tRet> friend class TaskPromiseBase;
|
||||||
|
const char* m_name = nullptr;
|
||||||
|
TFunction<FString()> m_dataFn;
|
||||||
|
};
|
||||||
|
#endif //SQUID_ENABLE_TASK_DEBUG
|
||||||
|
|
||||||
|
//--- AddStopTask Awaiter ---//
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
struct AddStopTaskAwaiter
|
||||||
|
{
|
||||||
|
AddStopTaskAwaiter(Task<tRet, RefType, Resumable>& in_taskToStop)
|
||||||
|
: m_taskToStop(&in_taskToStop)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename tRet> friend class TaskPromiseBase;
|
||||||
|
Task<tRet, RefType, Resumable>* m_taskToStop = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto AddStopTask(Task<tRet, RefType, Resumable>& in_taskToStop)
|
||||||
|
{
|
||||||
|
return AddStopTaskAwaiter<tRet, RefType, Resumable>(in_taskToStop);
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- RemoveStopTask Awaiter ---//
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
struct RemoveStopTaskAwaiter
|
||||||
|
{
|
||||||
|
RemoveStopTaskAwaiter(Task<tRet, RefType, Resumable>& in_taskToStop)
|
||||||
|
: m_taskToStop(&in_taskToStop)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename tRet> friend class TaskPromiseBase;
|
||||||
|
Task<tRet, RefType, Resumable>* m_taskToStop = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto RemoveStopTask(Task<tRet, RefType, Resumable>& in_taskToStop)
|
||||||
|
{
|
||||||
|
return RemoveStopTaskAwaiter<tRet, RefType, Resumable>(in_taskToStop);
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- Task Awaiter ---//
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable, typename promise_type>
|
||||||
|
struct TaskAwaiterBase
|
||||||
|
{
|
||||||
|
TaskAwaiterBase(const Task<tRet, RefType, Resumable>& in_task)
|
||||||
|
{
|
||||||
|
// This constructor exists to minimize downstream compile-error spam when co_awaiting a non-copyable Task by copy
|
||||||
|
}
|
||||||
|
TaskAwaiterBase(Task<tRet, RefType, Resumable>&& in_task)
|
||||||
|
: m_task(MoveTemp(in_task))
|
||||||
|
{
|
||||||
|
SQUID_RUNTIME_CHECK(m_task.IsValid(), "Tried to await an invalid task");
|
||||||
|
}
|
||||||
|
TaskAwaiterBase(TaskAwaiterBase&& in_taskAwaiter) noexcept
|
||||||
|
{
|
||||||
|
m_task = MoveTemp(in_taskAwaiter.m_task);
|
||||||
|
}
|
||||||
|
bool await_ready() noexcept
|
||||||
|
{
|
||||||
|
if(m_task.IsDone())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
template <eTaskResumable UResumable = Resumable, typename std::enable_if_t<UResumable == eTaskResumable::Yes>* = nullptr>
|
||||||
|
bool await_suspend(std::coroutine_handle<promise_type> in_coroHandle) noexcept
|
||||||
|
{
|
||||||
|
// Set the sub-task on the suspending task
|
||||||
|
auto& promise = in_coroHandle.promise();
|
||||||
|
auto taskInternal = promise.GetInternalTask();
|
||||||
|
auto subTaskInternal = m_task.GetInternalTask();
|
||||||
|
if(taskInternal->IsStopRequested())
|
||||||
|
{
|
||||||
|
subTaskInternal->RequestStop(); // Propagate any stop request to new sub-tasks
|
||||||
|
}
|
||||||
|
taskInternal->SetSubTask(StaticCastSharedPtr<TaskInternalBase>(subTaskInternal));
|
||||||
|
|
||||||
|
// Resume the task
|
||||||
|
if(m_task.Resume() == eTaskStatus::Done)
|
||||||
|
{
|
||||||
|
taskInternal->SetSubTask(nullptr);
|
||||||
|
return false; // Do not suspend, because the task is done
|
||||||
|
}
|
||||||
|
return true; // Suspend, because the task is not done
|
||||||
|
}
|
||||||
|
template <eTaskResumable UResumable = Resumable, typename std::enable_if_t<UResumable == eTaskResumable::No>* = nullptr>
|
||||||
|
bool await_suspend(std::coroutine_handle<promise_type> in_coroHandle) noexcept
|
||||||
|
{
|
||||||
|
auto& promise = in_coroHandle.promise();
|
||||||
|
if(!m_task.IsDone())
|
||||||
|
{
|
||||||
|
promise.SetReadyFunction([this] { return m_task.IsDone(); });
|
||||||
|
return true; // Suspend, because the task is not done
|
||||||
|
}
|
||||||
|
return false; // Do not suspend, because the task is done
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
auto GetInternalTask() const
|
||||||
|
{
|
||||||
|
return m_task.GetInternalTask();
|
||||||
|
}
|
||||||
|
Task<tRet, RefType, Resumable> m_task;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable, typename promise_type>
|
||||||
|
struct TaskAwaiter : public TaskAwaiterBase<tRet, RefType, Resumable, promise_type>
|
||||||
|
{
|
||||||
|
using TaskAwaiterBase<tRet, RefType, Resumable, promise_type>::TaskAwaiterBase;
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
auto await_resume()
|
||||||
|
{
|
||||||
|
this->m_task.RethrowUnhandledException(); // Re-throw any exceptions
|
||||||
|
auto retVal = this->m_task.TakeReturnValue();
|
||||||
|
SQUID_RUNTIME_CHECK(retVal, "Awaited task return value is unset");
|
||||||
|
return MoveTemp(retVal.GetValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
|
||||||
|
void await_resume()
|
||||||
|
{
|
||||||
|
this->m_task.RethrowUnhandledException(); // Re-throw any exceptions
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- Future Awaiter ---//
|
||||||
|
template <typename tRet, typename promise_type>
|
||||||
|
struct FutureAwaiter
|
||||||
|
{
|
||||||
|
FutureAwaiter(TFuture<tRet>&& in_future)
|
||||||
|
: m_future(MoveTemp(in_future))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~FutureAwaiter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FutureAwaiter(FutureAwaiter&& in_futureAwaiter) noexcept
|
||||||
|
{
|
||||||
|
m_future = MoveTemp(in_futureAwaiter.m_future);
|
||||||
|
}
|
||||||
|
bool await_ready() noexcept
|
||||||
|
{
|
||||||
|
bool isReady = m_future.IsReady();
|
||||||
|
return isReady;
|
||||||
|
}
|
||||||
|
bool await_suspend(std::coroutine_handle<promise_type> in_coroHandle) noexcept
|
||||||
|
{
|
||||||
|
// Set the ready function
|
||||||
|
auto& promise = in_coroHandle.promise();
|
||||||
|
|
||||||
|
// Suspend if future is not ready
|
||||||
|
bool shouldSuspend = !m_future.IsReady();
|
||||||
|
if(shouldSuspend)
|
||||||
|
{
|
||||||
|
promise.SetReadyFunction([this] { return m_future.IsReady(); });
|
||||||
|
}
|
||||||
|
return shouldSuspend;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
auto await_resume()
|
||||||
|
{
|
||||||
|
return m_future.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
|
||||||
|
void await_resume()
|
||||||
|
{
|
||||||
|
m_future.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TFuture<tRet> m_future;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- Shared Future Awaiter ---//
|
||||||
|
template <typename tRet, typename promise_type>
|
||||||
|
struct SharedFutureAwaiter
|
||||||
|
{
|
||||||
|
SharedFutureAwaiter(const TSharedFuture<tRet>& in_sharedFuture)
|
||||||
|
: m_sharedFuture(in_sharedFuture)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
bool await_ready() noexcept
|
||||||
|
{
|
||||||
|
bool isReady = m_sharedFuture.IsReady();
|
||||||
|
return isReady;
|
||||||
|
}
|
||||||
|
bool await_suspend(std::coroutine_handle<promise_type> in_coroHandle) noexcept
|
||||||
|
{
|
||||||
|
// Set the ready function
|
||||||
|
auto& promise = in_coroHandle.promise();
|
||||||
|
|
||||||
|
// Suspend if future is not ready
|
||||||
|
bool shouldSuspend = !m_sharedFuture.IsReady();
|
||||||
|
if(shouldSuspend)
|
||||||
|
{
|
||||||
|
promise.SetReadyFunction([this] { return m_sharedFuture.IsReady(); });
|
||||||
|
}
|
||||||
|
return shouldSuspend;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
auto await_resume()
|
||||||
|
{
|
||||||
|
return m_sharedFuture.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
|
||||||
|
void await_resume()
|
||||||
|
{
|
||||||
|
m_sharedFuture.Get(); // Trigger any pending errors
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TSharedFuture<tRet> m_sharedFuture;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- TaskPromiseBase ---//
|
||||||
|
template <typename tRet>
|
||||||
|
class alignas(16) TaskPromiseBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Type aliases
|
||||||
|
using promise_type = TaskPromise<tRet>;
|
||||||
|
using tTaskInternal = TaskInternal<tRet>;
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~TaskPromiseBase()
|
||||||
|
{
|
||||||
|
// NOTE: Destructor is non-virtual, because it is always handled + destroyed as its concrete type
|
||||||
|
m_taskInternal->OnTaskPromiseDestroyed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coroutine interface functions
|
||||||
|
auto initial_suspend() noexcept
|
||||||
|
{
|
||||||
|
return std::suspend_always();
|
||||||
|
}
|
||||||
|
auto final_suspend() noexcept
|
||||||
|
{
|
||||||
|
return std::suspend_always();
|
||||||
|
}
|
||||||
|
auto get_return_object()
|
||||||
|
{
|
||||||
|
return std::coroutine_handle<promise_type>::from_promise(*static_cast<promise_type*>(this));
|
||||||
|
}
|
||||||
|
static TSharedPtr<tTaskInternal> get_return_object_on_allocation_failure()
|
||||||
|
{
|
||||||
|
SQUID_THROW(std::bad_alloc(), "Failed to allocate memory for Task");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// HACK: Coroutines in UE5 under MSVC is currently causing a memory underrun
|
||||||
|
// These allocators are a workaround for the issue (as is alignas(16))
|
||||||
|
void* operator new(size_t Size) noexcept
|
||||||
|
{
|
||||||
|
const size_t WorkaroundAlign = std::alignment_of<TaskPromiseBase>();
|
||||||
|
Size += WorkaroundAlign;
|
||||||
|
return (void*)((uint8_t*)FMemory::Malloc(Size, WorkaroundAlign) + WorkaroundAlign);
|
||||||
|
}
|
||||||
|
void operator delete(void* Ptr) noexcept
|
||||||
|
{
|
||||||
|
const size_t WorkaroundAlign = std::alignment_of<TaskPromiseBase>();
|
||||||
|
auto OffsetPtr = (uint8_t*)Ptr - WorkaroundAlign;
|
||||||
|
FMemory::Free(OffsetPtr);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if SQUID_NEEDS_UNHANDLED_EXCEPTION
|
||||||
|
void unhandled_exception() noexcept
|
||||||
|
{
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
// Propagate exceptions for handling
|
||||||
|
m_taskInternal->SetUnhandledException(std::current_exception());
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
}
|
||||||
|
#endif // SQUID_NEEDS_UNHANDLED_EXCEPTION
|
||||||
|
|
||||||
|
// Internal Task
|
||||||
|
void SetInternalTask(tTaskInternal* in_taskInternal)
|
||||||
|
{
|
||||||
|
m_taskInternal = in_taskInternal;
|
||||||
|
}
|
||||||
|
tTaskInternal* GetInternalTask()
|
||||||
|
{
|
||||||
|
return m_taskInternal;
|
||||||
|
}
|
||||||
|
const tTaskInternal* GetInternalTask() const
|
||||||
|
{
|
||||||
|
return m_taskInternal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ready Function
|
||||||
|
void SetReadyFunction(const tTaskReadyFn& in_taskReadyFn)
|
||||||
|
{
|
||||||
|
m_taskInternal->SetReadyFunction(in_taskReadyFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Await-Transforms
|
||||||
|
auto await_transform(Suspend in_awaiter)
|
||||||
|
{
|
||||||
|
return in_awaiter;
|
||||||
|
}
|
||||||
|
auto await_transform(std::suspend_never in_awaiter)
|
||||||
|
{
|
||||||
|
return in_awaiter;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SQUID_ENABLE_TASK_DEBUG
|
||||||
|
auto await_transform(SetDebugName in_awaiter)
|
||||||
|
{
|
||||||
|
m_taskInternal->SetDebugName(in_awaiter.m_name);
|
||||||
|
m_taskInternal->SetDebugDataFn(in_awaiter.m_dataFn);
|
||||||
|
return std::suspend_never();
|
||||||
|
}
|
||||||
|
#endif //SQUID_ENABLE_TASK_DEBUG
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto await_transform(AddStopTaskAwaiter<tRet, RefType, Resumable> in_awaiter)
|
||||||
|
{
|
||||||
|
m_taskInternal->AddStopTask(*in_awaiter.m_taskToStop);
|
||||||
|
return std::suspend_never();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto await_transform(RemoveStopTaskAwaiter<tRet, RefType, Resumable> in_awaiter)
|
||||||
|
{
|
||||||
|
m_taskInternal->RemoveStopTask(*in_awaiter.m_taskToStop);
|
||||||
|
return std::suspend_never();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto await_transform(GetStopContext in_awaiter)
|
||||||
|
{
|
||||||
|
struct GetStopContextAwaiter : public std::suspend_never
|
||||||
|
{
|
||||||
|
GetStopContextAwaiter(StopContext in_stopCtx)
|
||||||
|
: stopCtx(in_stopCtx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
auto await_resume() noexcept
|
||||||
|
{
|
||||||
|
return stopCtx;
|
||||||
|
}
|
||||||
|
StopContext stopCtx;
|
||||||
|
};
|
||||||
|
GetStopContextAwaiter stopCtxAwaiter{ m_taskInternal->GetStopContext() };
|
||||||
|
return stopCtxAwaiter;
|
||||||
|
}
|
||||||
|
auto await_transform(const tTaskReadyFn& in_taskReadyFn)
|
||||||
|
{
|
||||||
|
// Check if we are already ready, and suspend if we are not
|
||||||
|
bool isReady = in_taskReadyFn();
|
||||||
|
if(!isReady)
|
||||||
|
{
|
||||||
|
m_taskInternal->SetReadyFunction(in_taskReadyFn);
|
||||||
|
}
|
||||||
|
return SuspendIf(!isReady); // Suspend if the function isn't already ready
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename tFutureRet>
|
||||||
|
auto await_transform(TFuture<tFutureRet>&& in_future)
|
||||||
|
{
|
||||||
|
return FutureAwaiter<tFutureRet, promise_type>(MoveTemp(in_future));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename tFutureRet>
|
||||||
|
auto await_transform(const TSharedFuture<tFutureRet>& in_sharedFuture)
|
||||||
|
{
|
||||||
|
return SharedFutureAwaiter<tFutureRet, promise_type>(in_sharedFuture);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task Await-Transforms
|
||||||
|
template <typename tTaskRet, eTaskRef RefType, eTaskResumable Resumable,
|
||||||
|
typename std::enable_if_t<Resumable == eTaskResumable::Yes>* = nullptr>
|
||||||
|
auto await_transform(Task<tTaskRet, RefType, Resumable>&& in_task) // Move version
|
||||||
|
{
|
||||||
|
return TaskAwaiter<tTaskRet, RefType, Resumable, promise_type>(MoveTemp(in_task));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename tTaskRet, eTaskRef RefType, eTaskResumable Resumable,
|
||||||
|
typename std::enable_if_t<Resumable == eTaskResumable::No>* = nullptr>
|
||||||
|
auto await_transform(Task<tTaskRet, RefType, Resumable> in_task) // Copy version (Non-Resumable)
|
||||||
|
{
|
||||||
|
return TaskAwaiter<tTaskRet, RefType, Resumable, promise_type>(MoveTemp(in_task));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename tTaskRet, eTaskRef RefType, eTaskResumable Resumable,
|
||||||
|
typename std::enable_if_t<Resumable == eTaskResumable::Yes>* = nullptr>
|
||||||
|
auto await_transform(const Task<tTaskRet, RefType, Resumable>& in_task) // Invalid copy version (Resumable)
|
||||||
|
{
|
||||||
|
static_assert(static_false<tTaskRet>::value, "Cannot await a non-copyable (resumable) Task by copy (try co_await MoveTemp(task), co_await WeakTaskHandle(task), or co_await task.WaitUntilDone()");
|
||||||
|
return TaskAwaiter<tTaskRet, RefType, Resumable, promise_type>(MoveTemp(in_task));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
tTaskInternal* m_taskInternal = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- TaskPromise ---//
|
||||||
|
template <typename tRet>
|
||||||
|
class TaskPromise : public TaskPromiseBase<tRet>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Return value access
|
||||||
|
void return_value(const tRet& in_retVal) // Copy return value
|
||||||
|
{
|
||||||
|
this->m_taskInternal->SetReturnValue(in_retVal);
|
||||||
|
}
|
||||||
|
void return_value(tRet&& in_retVal) // Move return value
|
||||||
|
{
|
||||||
|
this->m_taskInternal->SetReturnValue(MoveTemp(in_retVal));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class TaskPromise<void> : public TaskPromiseBase<void>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void return_void()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- TaskInternalBase ---//
|
||||||
|
class TaskInternalBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TaskInternalBase(std::coroutine_handle<> in_coroHandle)
|
||||||
|
: m_coroHandle(in_coroHandle)
|
||||||
|
{
|
||||||
|
SQUID_RUNTIME_CHECK(m_coroHandle, "Invalid coroutine handle passed into Task");
|
||||||
|
}
|
||||||
|
~TaskInternalBase() // NOTE: Destructor is intentionally non-virtual (shared_ptr preserves concrete type via deleter)
|
||||||
|
{
|
||||||
|
Kill(); // Used for killing subtasks
|
||||||
|
}
|
||||||
|
StopContext GetStopContext() const
|
||||||
|
{
|
||||||
|
return { &m_isStopRequested };
|
||||||
|
}
|
||||||
|
bool IsStopRequested() const
|
||||||
|
{
|
||||||
|
return m_isStopRequested;
|
||||||
|
}
|
||||||
|
void RequestStop() // Propagates a request for the task to come to a 'graceful' stop
|
||||||
|
{
|
||||||
|
m_isStopRequested = true;
|
||||||
|
for(auto& stopTask : m_stopTasks)
|
||||||
|
{
|
||||||
|
if(auto locked = stopTask.Pin())
|
||||||
|
{
|
||||||
|
locked->RequestStop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_stopTasks.SetNum(0);
|
||||||
|
}
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
void AddStopTask(Task<tRet, RefType, Resumable>& in_taskToStop) // Adds a task to the list of tasks to which we propagate stop requests
|
||||||
|
{
|
||||||
|
if(m_isStopRequested)
|
||||||
|
{
|
||||||
|
in_taskToStop.RequestStop();
|
||||||
|
}
|
||||||
|
else if(in_taskToStop.IsValid())
|
||||||
|
{
|
||||||
|
m_stopTasks.Add(in_taskToStop.GetInternalTask());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
void RemoveStopTask(Task<tRet, RefType, Resumable>& in_taskToStop) // Removes a task to the list of tasks to which we propagate stop requests
|
||||||
|
{
|
||||||
|
if(in_taskToStop.IsValid())
|
||||||
|
{
|
||||||
|
for(int32_t i = 0; i < m_stopTasks.Num(); ++i)
|
||||||
|
{
|
||||||
|
if(m_stopTasks[i].Pin() == in_taskToStop.GetInternalTask())
|
||||||
|
{
|
||||||
|
m_stopTasks[i] = m_stopTasks.Last();
|
||||||
|
m_stopTasks.Pop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eTaskStatus Resume() // Returns whether the task is still running
|
||||||
|
{
|
||||||
|
// Make sure this task is not already mid-resume
|
||||||
|
SQUID_RUNTIME_CHECK(m_internalState != eInternalState::Resuming, "Attempted to resume Task while already resumed");
|
||||||
|
|
||||||
|
// Task is destroyed, therefore task is done
|
||||||
|
if(m_internalState == eInternalState::Destroyed)
|
||||||
|
{
|
||||||
|
return eTaskStatus::Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark task as resuming
|
||||||
|
m_internalState = eInternalState::Resuming;
|
||||||
|
|
||||||
|
// Resume any active sub-task
|
||||||
|
if(m_subTaskInternal)
|
||||||
|
{
|
||||||
|
// Propagate any stop requests to sub-task prior to resuming
|
||||||
|
if(m_isStopRequested)
|
||||||
|
{
|
||||||
|
m_subTaskInternal->m_isStopRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resume the sub-task
|
||||||
|
if(m_subTaskInternal->Resume() != eTaskStatus::Done)
|
||||||
|
{
|
||||||
|
m_internalState = eInternalState::Idle;
|
||||||
|
return eTaskStatus::Suspended; // Sub-task not done, therefore task is not done
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the sub-task
|
||||||
|
m_subTaskInternal = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resume task, if necessary
|
||||||
|
if(CanResume())
|
||||||
|
{
|
||||||
|
m_taskReadyFn = nullptr; // Clear any ready function we were waiting on
|
||||||
|
m_coroHandle.resume(); // Resume the underlying std::coroutine_handle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return to idle state and return current task status
|
||||||
|
auto taskStatus = m_coroHandle.done() ? eTaskStatus::Done : eTaskStatus::Suspended;
|
||||||
|
if(taskStatus == eTaskStatus::Done)
|
||||||
|
{
|
||||||
|
m_isDone = true; // Mark task done
|
||||||
|
}
|
||||||
|
m_internalState = eInternalState::Idle;
|
||||||
|
return taskStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub-task
|
||||||
|
void SetSubTask(TSharedPtr<TaskInternalBase> in_subTaskInternal)
|
||||||
|
{
|
||||||
|
m_subTaskInternal = in_subTaskInternal;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SQUID_ENABLE_TASK_DEBUG
|
||||||
|
// Debug task name + stack
|
||||||
|
FString GetDebugName() const
|
||||||
|
{
|
||||||
|
return (!IsDone() && m_debugDataFn) ? (FString(m_debugName) + " [" + m_debugDataFn() + "]") : m_debugName;
|
||||||
|
}
|
||||||
|
FString GetDebugStack() const
|
||||||
|
{
|
||||||
|
FString result = m_subTaskInternal ? (GetDebugName() + " -> " + m_subTaskInternal->GetDebugStack()) : GetDebugName();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
void SetDebugName(const char* in_debugName)
|
||||||
|
{
|
||||||
|
if(in_debugName)
|
||||||
|
{
|
||||||
|
m_debugName = in_debugName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SetDebugDataFn(TFunction<FString()> in_debugDataFn)
|
||||||
|
{
|
||||||
|
m_debugDataFn = in_debugDataFn;
|
||||||
|
}
|
||||||
|
#endif //SQUID_ENABLE_TASK_DEBUG
|
||||||
|
|
||||||
|
// Exceptions
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
std::exception_ptr GetUnhandledException() const
|
||||||
|
{
|
||||||
|
if(m_isExceptionSet)
|
||||||
|
{
|
||||||
|
return m_exception;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
|
||||||
|
protected:
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
// Internal implementation of exception-setting (called by TaskInternal<> child classes)
|
||||||
|
void InternalSetUnhandledException(std::exception_ptr in_exception)
|
||||||
|
{
|
||||||
|
// NOTE: This must never be called more than once in the lifetime of an internal task
|
||||||
|
SQUID_RUNTIME_CHECK(!m_isExceptionSet, "Exception was set for a task after it had already been set");
|
||||||
|
if(!m_isExceptionSet)
|
||||||
|
{
|
||||||
|
m_exception = in_exception;
|
||||||
|
m_isExceptionSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename tRet> friend class TaskPromiseBase;
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable, typename promise_type> friend struct TaskAwaiterBase;
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable> friend class Task;
|
||||||
|
|
||||||
|
// Kill this task
|
||||||
|
void Kill() // Kill() can safely be called multiple times
|
||||||
|
{
|
||||||
|
SQUID_RUNTIME_CHECK(m_internalState != eInternalState::Resuming, "Attempted to kill Task while resumed");
|
||||||
|
if(m_internalState == eInternalState::Idle)
|
||||||
|
{
|
||||||
|
// Mark task done
|
||||||
|
m_isDone = true;
|
||||||
|
|
||||||
|
// First destroy any sub-tasks
|
||||||
|
if(m_subTaskInternal)
|
||||||
|
{
|
||||||
|
m_subTaskInternal->Kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the underlying std::coroutine_handle
|
||||||
|
m_coroHandle.destroy(); // This should only ever be called directly from this one place
|
||||||
|
m_coroHandle = nullptr;
|
||||||
|
m_taskReadyFn = nullptr; // Clear out the ready function
|
||||||
|
m_internalState = eInternalState::Destroyed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done + can-resume status
|
||||||
|
void SetReadyFunction(const tTaskReadyFn& in_taskReadyFn)
|
||||||
|
{
|
||||||
|
m_taskReadyFn = in_taskReadyFn;
|
||||||
|
}
|
||||||
|
bool CanResume() const
|
||||||
|
{
|
||||||
|
if(IsDone())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(m_subTaskInternal)
|
||||||
|
{
|
||||||
|
bool canResume = m_subTaskInternal->CanResume();
|
||||||
|
return canResume;
|
||||||
|
}
|
||||||
|
bool isReady = !m_taskReadyFn || m_taskReadyFn();
|
||||||
|
return isReady;
|
||||||
|
}
|
||||||
|
bool IsDone() const
|
||||||
|
{
|
||||||
|
return m_isDone;
|
||||||
|
}
|
||||||
|
bool m_isDone = false;
|
||||||
|
|
||||||
|
// Internal state
|
||||||
|
enum class eInternalState
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
Resuming,
|
||||||
|
Destroyed,
|
||||||
|
};
|
||||||
|
eInternalState m_internalState = eInternalState::Idle;
|
||||||
|
|
||||||
|
// Task ready condition (when awaiting a TFunction<bool>)
|
||||||
|
tTaskReadyFn m_taskReadyFn;
|
||||||
|
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
// Exceptions
|
||||||
|
std::exception_ptr m_exception = nullptr;
|
||||||
|
bool m_isExceptionSet = false;
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
|
||||||
|
// Sub-task
|
||||||
|
TSharedPtr<TaskInternalBase> m_subTaskInternal;
|
||||||
|
|
||||||
|
// Reference-counting (determines underlying std::coroutine_handle lifetime, not lifetime of this internal task)
|
||||||
|
void AddLogicalRef()
|
||||||
|
{
|
||||||
|
++m_refCount;
|
||||||
|
}
|
||||||
|
void RemoveLogicalRef()
|
||||||
|
{
|
||||||
|
--m_refCount;
|
||||||
|
if(m_refCount == 0)
|
||||||
|
{
|
||||||
|
Kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int32_t m_refCount = 0; // Number of (strong) non-weak tasks referencing the internal task
|
||||||
|
|
||||||
|
// C++ std::coroutine_handle
|
||||||
|
std::coroutine_handle<> m_coroHandle;
|
||||||
|
|
||||||
|
// Stop request
|
||||||
|
bool m_isStopRequested = false;
|
||||||
|
TArray<TWeakPtr<TaskInternalBase>> m_stopTasks;
|
||||||
|
|
||||||
|
#if SQUID_ENABLE_TASK_DEBUG
|
||||||
|
// Debug Data
|
||||||
|
const char* m_debugName = "[unnamed task]";
|
||||||
|
TFunction<FString()> m_debugDataFn;
|
||||||
|
#endif //SQUID_ENABLE_TASK_DEBUG
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- TaskInternal ---//
|
||||||
|
template <typename tRet>
|
||||||
|
class TaskInternal : public TaskInternalBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using promise_type = TaskPromise<tRet>;
|
||||||
|
|
||||||
|
TaskInternal(std::coroutine_handle<promise_type> in_handle)
|
||||||
|
: TaskInternalBase(in_handle)
|
||||||
|
{
|
||||||
|
auto& promisePtr = in_handle.promise();
|
||||||
|
promisePtr.SetInternalTask(this);
|
||||||
|
}
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
void SetUnhandledException(std::exception_ptr in_exception)
|
||||||
|
{
|
||||||
|
m_retValState = eTaskRetValState::Orphaned; // Return value can never be set if there was an unhandled exception
|
||||||
|
InternalSetUnhandledException(in_exception);
|
||||||
|
}
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
void SetReturnValue(const tRet& in_retVal)
|
||||||
|
{
|
||||||
|
tRet retVal = in_retVal;
|
||||||
|
SetReturnValue(MoveTemp(retVal));
|
||||||
|
}
|
||||||
|
void SetReturnValue(tRet&& in_retVal)
|
||||||
|
{
|
||||||
|
if(m_retValState == eTaskRetValState::Unset)
|
||||||
|
{
|
||||||
|
m_retVal = MoveTemp(in_retVal);
|
||||||
|
m_retValState = eTaskRetValState::Set;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These conditions should (logically) never be met, but they are included in case future changes violate that constraint
|
||||||
|
SQUID_RUNTIME_CHECK(m_retValState != eTaskRetValState::Set, "Attempted to set a task's return value when it was already set");
|
||||||
|
SQUID_RUNTIME_CHECK(m_retValState != eTaskRetValState::Taken, "Attempted to set a task's return value after it was already taken");
|
||||||
|
SQUID_RUNTIME_CHECK(m_retValState != eTaskRetValState::Orphaned, "Attempted to set a task's return value after it was orphaned");
|
||||||
|
}
|
||||||
|
TOptional<tRet> TakeReturnValue()
|
||||||
|
{
|
||||||
|
// If the value has been set, mark it as taken and move-return the value
|
||||||
|
if(m_retValState == eTaskRetValState::Set)
|
||||||
|
{
|
||||||
|
m_retValState = eTaskRetValState::Taken;
|
||||||
|
return MoveTemp(m_retVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the value was not set, return an unset optional (checking that it was neither taken nor orphaned)
|
||||||
|
SQUID_RUNTIME_CHECK(m_retValState != eTaskRetValState::Taken, "Attempted to take a task's return value after it was already successfully taken");
|
||||||
|
SQUID_RUNTIME_CHECK(m_retValState != eTaskRetValState::Orphaned, "Attempted to take a task's return value that will never be set (task ended prematurely)");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
void OnTaskPromiseDestroyed()
|
||||||
|
{
|
||||||
|
// Mark the return value as orphaned if it was never set
|
||||||
|
m_retValState = eTaskRetValState::Orphaned;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Internal state
|
||||||
|
enum class eTaskRetValState
|
||||||
|
{
|
||||||
|
Unset, // Has not yet been set
|
||||||
|
Set, // Has been set and can be taken
|
||||||
|
Taken, // Has been taken and can no longer be taken
|
||||||
|
Orphaned, // Will never be set because the TaskPromise has been destroyed
|
||||||
|
};
|
||||||
|
|
||||||
|
eTaskRetValState m_retValState = eTaskRetValState::Unset; // Initially unset
|
||||||
|
TOptional<tRet> m_retVal;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class TaskInternal<void> : public TaskInternalBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using promise_type = TaskPromise<void>;
|
||||||
|
|
||||||
|
TaskInternal(std::coroutine_handle<promise_type> in_handle)
|
||||||
|
: TaskInternalBase(in_handle)
|
||||||
|
{
|
||||||
|
auto& promisePtr = in_handle.promise();
|
||||||
|
promisePtr.SetInternalTask(this);
|
||||||
|
}
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
void SetUnhandledException(std::exception_ptr in_exception)
|
||||||
|
{
|
||||||
|
InternalSetUnhandledException(in_exception);
|
||||||
|
}
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
void TakeReturnValue() // This function is an intentional no-op, to simplify certain templated function implementations
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void OnTaskPromiseDestroyed()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
236
include/Private/TasksCommonPrivate.h
Normal file
236
include/Private/TasksCommonPrivate.h
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
//--- User configuration header ---//
|
||||||
|
#include "../TasksConfig.h"
|
||||||
|
|
||||||
|
// Namespace macros (enabled/disabled via SQUID_ENABLE_NAMESPACE)
|
||||||
|
#if SQUID_ENABLE_NAMESPACE
|
||||||
|
#define NAMESPACE_SQUID_BEGIN namespace Squid {
|
||||||
|
#define NAMESPACE_SQUID_END }
|
||||||
|
#define NAMESPACE_SQUID Squid
|
||||||
|
#else
|
||||||
|
#define NAMESPACE_SQUID_BEGIN
|
||||||
|
#define NAMESPACE_SQUID_END
|
||||||
|
#define NAMESPACE_SQUID
|
||||||
|
namespace Squid {} // Convenience to allow 'using namespace Squid' even when namespace is disabled
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Exception macros (to support environments with exceptions disabled)
|
||||||
|
#if SQUID_USE_EXCEPTIONS && (defined(__cpp_exceptions) || defined(__EXCEPTIONS))
|
||||||
|
#include <stdexcept>
|
||||||
|
#define SQUID_THROW(exception, errStr) throw exception;
|
||||||
|
#define SQUID_RUNTIME_ERROR(errStr) throw std::runtime_error(errStr);
|
||||||
|
#define SQUID_RUNTIME_CHECK(condition, errStr) if(!(condition)) throw std::runtime_error(errStr);
|
||||||
|
#else
|
||||||
|
#include <cassert>
|
||||||
|
#define SQUID_THROW(exception, errStr) assert(false && errStr);
|
||||||
|
#define SQUID_RUNTIME_ERROR(errStr) assert(false && errStr);
|
||||||
|
#define SQUID_RUNTIME_CHECK(condition, errStr) assert((condition) && errStr);
|
||||||
|
#endif //__cpp_exceptions
|
||||||
|
|
||||||
|
// Time Interface
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
#if SQUID_ENABLE_DOUBLE_PRECISION_TIME
|
||||||
|
using tTaskTime = double;
|
||||||
|
#else
|
||||||
|
using tTaskTime = float; // Defines time units for use with the Task system
|
||||||
|
#endif //SQUID_ENABLE_DOUBLE_PRECISION_TIME
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
|
||||||
|
// Coroutine de-optimization macros [DEPRECATED]
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if _MSC_VER >= 1920
|
||||||
|
// Newer versions of Visual Studio (>= VS2019) compile coroutines correctly
|
||||||
|
#define COROUTINE_OPTIMIZE_OFF
|
||||||
|
#define COROUTINE_OPTIMIZE_ON
|
||||||
|
#else
|
||||||
|
// Older versions of Visual Studio had code generation bugs when optimizing coroutines (they would compile, but have incorrect runtime results)
|
||||||
|
#define COROUTINE_OPTIMIZE_OFF __pragma(optimize("", off))
|
||||||
|
#define COROUTINE_OPTIMIZE_ON __pragma(optimize("", on))
|
||||||
|
#endif // _MSC_VER >= 1920
|
||||||
|
#else
|
||||||
|
// The Clang compiler has sometimes crashed when optimizing/inlining certain coroutines, so this macro can be used to disable inlining
|
||||||
|
#define COROUTINE_OPTIMIZE_OFF _Pragma("clang optimize off")
|
||||||
|
#define COROUTINE_OPTIMIZE_ON _Pragma("clang optimize on")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// False type for use in static_assert() [static_assert(false, ...) -> static_assert(static_false<T>, ...)]
|
||||||
|
template<typename T>
|
||||||
|
struct static_false : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine C++ Language Version
|
||||||
|
#if defined(_MSVC_LANG)
|
||||||
|
#define CPP_LANGUAGE_VERSION _MSVC_LANG
|
||||||
|
#elif defined(__cplusplus)
|
||||||
|
#define CPP_LANGUAGE_VERSION __cplusplus
|
||||||
|
#else
|
||||||
|
#define CPP_LANGUAGE_VERSION 0L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CPP_LANGUAGE_VERSION > 201703L // C++20 or higher
|
||||||
|
#define HAS_CXX17 1
|
||||||
|
#define HAS_CXX20 1
|
||||||
|
#elif CPP_LANGUAGE_VERSION > 201402L // C++17 or higher
|
||||||
|
#define HAS_CXX17 1
|
||||||
|
#define HAS_CXX20 0
|
||||||
|
#elif CPP_LANGUAGE_VERSION > 201103L // C++14 or higher
|
||||||
|
#define HAS_CXX17 0
|
||||||
|
#define HAS_CXX20 0
|
||||||
|
#else // C++11 or lower
|
||||||
|
#error Squid::Tasks requires C++14 or higher
|
||||||
|
#define HAS_CXX17 0
|
||||||
|
#define HAS_CXX20 0
|
||||||
|
#endif
|
||||||
|
#undef CPP_LANGUAGE_VERSION
|
||||||
|
|
||||||
|
// C++20 Compatibility (std::coroutine)
|
||||||
|
#if HAS_CXX20 || (defined(_MSVC_LANG) && defined(__cpp_lib_coroutine)) // Standard coroutines
|
||||||
|
#include <coroutine>
|
||||||
|
#define SQUID_EXPERIMENTAL_COROUTINES 0
|
||||||
|
#else // Experimental coroutines
|
||||||
|
#if defined(__clang__) && defined(_STL_COMPILER_PREPROCESSOR)
|
||||||
|
// HACK: Some distributions of clang don't have a <experimental/coroutine> header. We only need a few symbols, so just define them ourselves
|
||||||
|
namespace std {
|
||||||
|
namespace experimental {
|
||||||
|
inline namespace coroutines_v1 {
|
||||||
|
|
||||||
|
template <typename R, typename...> struct coroutine_traits {
|
||||||
|
using promise_type = typename R::promise_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Promise = void> struct coroutine_handle;
|
||||||
|
|
||||||
|
template <> struct coroutine_handle<void> {
|
||||||
|
static coroutine_handle from_address(void* addr) noexcept {
|
||||||
|
coroutine_handle me;
|
||||||
|
me.ptr = addr;
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
void operator()() { resume(); }
|
||||||
|
void* address() const { return ptr; }
|
||||||
|
void resume() const { __builtin_coro_resume(ptr); }
|
||||||
|
void destroy() const { __builtin_coro_destroy(ptr); }
|
||||||
|
bool done() const { return __builtin_coro_done(ptr); }
|
||||||
|
coroutine_handle& operator=(decltype(nullptr)) {
|
||||||
|
ptr = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
coroutine_handle(decltype(nullptr)) : ptr(nullptr) {}
|
||||||
|
coroutine_handle() : ptr(nullptr) {}
|
||||||
|
// void reset() { ptr = nullptr; } // add to P0057?
|
||||||
|
explicit operator bool() const { return ptr; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void* ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Promise> struct coroutine_handle : coroutine_handle<> {
|
||||||
|
using coroutine_handle<>::operator=;
|
||||||
|
|
||||||
|
static coroutine_handle from_address(void* addr) noexcept {
|
||||||
|
coroutine_handle me;
|
||||||
|
me.ptr = addr;
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise& promise() const {
|
||||||
|
return *reinterpret_cast<Promise*>(
|
||||||
|
__builtin_coro_promise(ptr, alignof(Promise), false));
|
||||||
|
}
|
||||||
|
static coroutine_handle from_promise(Promise& promise) {
|
||||||
|
coroutine_handle p;
|
||||||
|
p.ptr = __builtin_coro_promise(&promise, alignof(Promise), true);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _PromiseT>
|
||||||
|
bool operator==(coroutine_handle<_PromiseT> const& _Left,
|
||||||
|
coroutine_handle<_PromiseT> const& _Right) noexcept
|
||||||
|
{
|
||||||
|
return _Left.address() == _Right.address();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename _PromiseT>
|
||||||
|
bool operator!=(coroutine_handle<_PromiseT> const& _Left,
|
||||||
|
coroutine_handle<_PromiseT> const& _Right) noexcept
|
||||||
|
{
|
||||||
|
return !(_Left == _Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct suspend_always {
|
||||||
|
bool await_ready() noexcept { return false; }
|
||||||
|
void await_suspend(coroutine_handle<>) noexcept {}
|
||||||
|
void await_resume() noexcept {}
|
||||||
|
};
|
||||||
|
struct suspend_never {
|
||||||
|
bool await_ready() noexcept { return true; }
|
||||||
|
void await_suspend(coroutine_handle<>) noexcept {}
|
||||||
|
void await_resume() noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <experimental/coroutine>
|
||||||
|
#endif
|
||||||
|
namespace std // Alias experimental coroutine symbols into std namespace
|
||||||
|
{
|
||||||
|
template <class _Promise = void>
|
||||||
|
using coroutine_handle = experimental::coroutine_handle<_Promise>;
|
||||||
|
using suspend_never = experimental::suspend_never;
|
||||||
|
using suspend_always = experimental::suspend_always;
|
||||||
|
};
|
||||||
|
#define SQUID_EXPERIMENTAL_COROUTINES 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Determine whether our tasks need the member function "unhandled_exception()" defined or not
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
// MSVC's rules for exceptions differ between standard + experimental coroutines
|
||||||
|
#if SQUID_EXPERIMENTAL_COROUTINES
|
||||||
|
// If exceptions are enabled, we must define unhandled_exception()
|
||||||
|
#if defined(__cpp_exceptions) && __cpp_exceptions == 199711
|
||||||
|
#define SQUID_NEEDS_UNHANDLED_EXCEPTION 1
|
||||||
|
#else
|
||||||
|
#define SQUID_NEEDS_UNHANDLED_EXCEPTION 0
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// If we're using VS16.11 or newer -- or older than 16.10, we have one set of rules for standard coroutines
|
||||||
|
#if _MSC_FULL_VER >= 192930133L || _MSC_VER < 1429L
|
||||||
|
#define SQUID_NEEDS_UNHANDLED_EXCEPTION 1
|
||||||
|
#else
|
||||||
|
#if defined(__cpp_exceptions) && __cpp_exceptions == 199711
|
||||||
|
#define SQUID_NEEDS_UNHANDLED_EXCEPTION 1
|
||||||
|
#else
|
||||||
|
// 16.10 has a bug with their standard coroutine implementation that creates a set of contradicting requirements
|
||||||
|
// https://developercommunity.visualstudio.com/t/coroutine-uses-promise_type::unhandled_e/1374530
|
||||||
|
#error Visual Studio 16.10 has a compiler bug that prevents all coroutines from compiling when exceptions are disabled and using standard C++20 coroutines or /await:strict. Please either upgrade your version of Visual Studio, or use the experimental /await flag, or enable exceptions.
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Clang always requires unhandled_exception() to be defined
|
||||||
|
#define SQUID_NEEDS_UNHANDLED_EXCEPTION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// C++17 Compatibility ([[nodiscard]])
|
||||||
|
#if !defined(SQUID_NODISCARD) && defined(__has_cpp_attribute)
|
||||||
|
#if __has_cpp_attribute(nodiscard)
|
||||||
|
#define SQUID_NODISCARD [[nodiscard]]
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifndef SQUID_NODISCARD
|
||||||
|
#define SQUID_NODISCARD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef HAS_CXX17
|
||||||
|
#undef HAS_CXX20
|
||||||
|
|
||||||
|
// Include UE core headers
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Engine/World.h"
|
||||||
|
#include "Engine/Engine.h"
|
||||||
|
#include "Async/Future.h"
|
1153
include/Task.h
Normal file
1153
include/Task.h
Normal file
File diff suppressed because it is too large
Load Diff
331
include/TaskFSM.h
Normal file
331
include/TaskFSM.h
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @defgroup TaskFSM Task FSM
|
||||||
|
/// @brief Finite state machine that implements states using task factories
|
||||||
|
/// @{
|
||||||
|
///
|
||||||
|
/// Full documentation of the TaskFSM system coming soon!
|
||||||
|
|
||||||
|
#include "Task.h"
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
|
||||||
|
class TaskFSM;
|
||||||
|
|
||||||
|
namespace FSM
|
||||||
|
{
|
||||||
|
// State ID wrapper
|
||||||
|
struct StateId
|
||||||
|
{
|
||||||
|
StateId() = default;
|
||||||
|
StateId(int32_t in_idx) : idx(in_idx) {}
|
||||||
|
StateId(size_t in_idx) : idx((int32_t)in_idx) {}
|
||||||
|
bool operator==(const StateId& other) const { return (other.idx == idx); }
|
||||||
|
bool operator!=(const StateId& other) const { return (other.idx != idx); }
|
||||||
|
bool IsValid() const { return idx != INT32_MAX; }
|
||||||
|
|
||||||
|
int32_t idx = INT32_MAX; // Default to invalid idx
|
||||||
|
};
|
||||||
|
|
||||||
|
// State transition debug data
|
||||||
|
struct TransitionDebugData
|
||||||
|
{
|
||||||
|
FSM::StateId oldStateId;
|
||||||
|
FString oldStateName;
|
||||||
|
FSM::StateId newStateId;
|
||||||
|
FString newStateName;
|
||||||
|
};
|
||||||
|
|
||||||
|
// State transition callback function
|
||||||
|
using tOnStateTransitionFn = TFunction<void()>;
|
||||||
|
|
||||||
|
#include "Private/TaskFSMPrivate.h" // Internal use only! Do not include elsewhere!
|
||||||
|
|
||||||
|
//--- State Handle ---//
|
||||||
|
template<class tStateInput, class tStateConstructorFn>
|
||||||
|
class StateHandle
|
||||||
|
{
|
||||||
|
using tPredicateRet = typename std::conditional<!std::is_void<tStateInput>::value, TOptional<tStateInput>, bool>::type;
|
||||||
|
using tPredicateFn = TFunction<tPredicateRet()>;
|
||||||
|
public:
|
||||||
|
StateHandle(StateHandle&& in_other) = default;
|
||||||
|
StateHandle& operator=(StateHandle&& in_other) = default;
|
||||||
|
|
||||||
|
StateId GetId() const //< Get the ID of this state
|
||||||
|
{
|
||||||
|
return m_state ? m_state->idx : StateId{};
|
||||||
|
}
|
||||||
|
|
||||||
|
// SFINAE Template Declaration Macros (#defines)
|
||||||
|
/// @cond
|
||||||
|
#define NONVOID_ONLY_WITH_PREDICATE template <class tPredicateFn, typename tPayload = tStateInput, typename std::enable_if_t<!std::is_void<tPayload>::value>* = nullptr>
|
||||||
|
#define VOID_ONLY_WITH_PREDICATE template <class tPredicateFn, typename tPayload = tStateInput, typename std::enable_if_t<std::is_void<tPayload>::value>* = nullptr>
|
||||||
|
#define NONVOID_ONLY template <typename tPayload = tStateInput, typename std::enable_if_t<!std::is_void<tPayload>::value && !std::is_convertible<tPayload, tPredicateFn>::value>* = nullptr>
|
||||||
|
#define VOID_ONLY template <typename tPayload = tStateInput, typename std::enable_if_t<std::is_void<tPayload>::value>* = nullptr>
|
||||||
|
#define PREDICATE_ONLY template <typename tPredicateFn, typename std::enable_if_t<!std::is_convertible<tStateInput, tPredicateFn>::value>* = nullptr>
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
// Link methods
|
||||||
|
VOID_ONLY LinkHandle Link() //< Empty predicate link (always follow link)
|
||||||
|
{
|
||||||
|
return _InternalLink([] { return true; }, LinkHandle::eType::Normal);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY LinkHandle Link(tPayload in_payload) //< Empty predicate link w/ payload (always follow link, using provided payload)
|
||||||
|
{
|
||||||
|
return _InternalLink([payload = MoveTemp(in_payload)]() -> tPredicateRet { return payload; }, LinkHandle::eType::Normal);
|
||||||
|
}
|
||||||
|
PREDICATE_ONLY LinkHandle Link(tPredicateFn in_predicate) //< Predicate link w/ implicit payload (follow link when predicate returns a value; use return value as payload)
|
||||||
|
{
|
||||||
|
return _InternalLink(in_predicate, LinkHandle::eType::Normal);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY_WITH_PREDICATE LinkHandle Link(tPredicateFn in_predicate, tPayload in_payload) //< Predicate link w/ explicit payload (follow link when predicate returns true; use provided payload)
|
||||||
|
{
|
||||||
|
return _InternalLink(in_predicate, MoveTemp(in_payload), LinkHandle::eType::Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnCompleteLink methods
|
||||||
|
VOID_ONLY LinkHandle OnCompleteLink() //< Empty predicate link (always follow link)
|
||||||
|
{
|
||||||
|
return _InternalLink([] { return true; }, LinkHandle::eType::OnComplete);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY LinkHandle OnCompleteLink(tPayload in_payload) //< Empty predicate link w/ payload (always follow link, using provided payload)
|
||||||
|
{
|
||||||
|
return _InternalLink([payload = MoveTemp(in_payload)]() -> tPredicateRet { return payload; }, LinkHandle::eType::OnComplete);
|
||||||
|
}
|
||||||
|
PREDICATE_ONLY LinkHandle OnCompleteLink(tPredicateFn in_predicate) //< Predicate link w/ implicit payload (follow link when predicate returns a value; use return value as payload)
|
||||||
|
{
|
||||||
|
return _InternalLink(in_predicate, LinkHandle::eType::OnComplete, true);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY_WITH_PREDICATE LinkHandle OnCompleteLink(tPredicateFn in_predicate, tPayload in_payload) //< Predicate link w/ explicit payload (follow link when predicate returns true; use provided payload)
|
||||||
|
{
|
||||||
|
return _InternalLink(in_predicate, MoveTemp(in_payload), LinkHandle::eType::OnComplete, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ::TaskFSM;
|
||||||
|
|
||||||
|
StateHandle() = delete;
|
||||||
|
StateHandle(TSharedPtr<State<tStateInput, tStateConstructorFn>> InStatePtr)
|
||||||
|
: m_state(InStatePtr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
StateHandle(const StateHandle& Other) = delete;
|
||||||
|
StateHandle& operator=(const StateHandle& Other) = delete;
|
||||||
|
|
||||||
|
// Internal link function implementations
|
||||||
|
VOID_ONLY_WITH_PREDICATE LinkHandle _InternalLink(tPredicateFn in_predicate, LinkHandle::eType in_linkType, bool in_isConditional = false) // bool-returning predicate
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<bool, decltype(in_predicate())>::value, "This link requires a predicate function returning bool");
|
||||||
|
TSharedPtr<LinkBase> link = MakeShared<FSM::Link<tStateInput, tStateConstructorFn, tPredicateFn>>(m_state, in_predicate);
|
||||||
|
return LinkHandle(link, in_linkType, in_isConditional);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY_WITH_PREDICATE LinkHandle _InternalLink(tPredicateFn in_predicate, LinkHandle::eType in_linkType, bool in_isConditional = false) // optional-returning predicate
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<TOptional<tStateInput>, decltype(in_predicate())>::value, "This link requires a predicate function returning TOptional<tStateInput>");
|
||||||
|
TSharedPtr<LinkBase> link = MakeShared<FSM::Link<tStateInput, tStateConstructorFn, tPredicateFn>>(m_state, in_predicate);
|
||||||
|
return LinkHandle(link, in_linkType, in_isConditional);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY_WITH_PREDICATE LinkHandle _InternalLink(tPredicateFn in_predicate, tPayload in_payload, LinkHandle::eType in_linkType, bool in_isConditional = false) // bool-returning predicate w/ fixed payload
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<bool, decltype(in_predicate())>::value, "This link requires a predicate function returning bool");
|
||||||
|
auto predicate = [in_predicate, in_payload]() -> TOptional<tStateInput>
|
||||||
|
{
|
||||||
|
return in_predicate() ? TOptional<tStateInput>(in_payload) : TOptional<tStateInput>{};
|
||||||
|
};
|
||||||
|
return _InternalLink(predicate, in_linkType, in_isConditional);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SFINAE Template Declaration Macros (#undefs)
|
||||||
|
#undef NONVOID_ONLY_WITH_PREDICATE
|
||||||
|
#undef VOID_ONLY_WITH_PREDICATE
|
||||||
|
#undef NONVOID_ONLY
|
||||||
|
#undef VOID_ONLY
|
||||||
|
#undef PREDICATE_ONLY
|
||||||
|
|
||||||
|
TSharedPtr<State<tStateInput, tStateConstructorFn>> m_state; // Internal state object
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace FSM
|
||||||
|
|
||||||
|
using StateId = FSM::StateId;
|
||||||
|
template<class tStateInput, class tStateConstructorFn>
|
||||||
|
using StateHandle = FSM::StateHandle<tStateInput, tStateConstructorFn>;
|
||||||
|
using TransitionDebugData = FSM::TransitionDebugData;
|
||||||
|
using tOnStateTransitionFn = FSM::tOnStateTransitionFn;
|
||||||
|
|
||||||
|
//--- TaskFSM ---//
|
||||||
|
class TaskFSM
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using tOnStateTransitionFn = TFunction<void()>;
|
||||||
|
using tDebugStateTransitionFn = TFunction<void(TransitionDebugData)>;
|
||||||
|
|
||||||
|
// Create a new FSM state [fancy param-deducing version (hopefully) coming soon!]
|
||||||
|
template<typename tStateConstructorFn>
|
||||||
|
auto State(FString in_name, tStateConstructorFn in_stateCtorFn)
|
||||||
|
{
|
||||||
|
typedef FSM::function_traits<tStateConstructorFn> tFnTraits;
|
||||||
|
using tStateInput = typename tFnTraits::tArg;
|
||||||
|
const FSM::StateId newStateId = m_states.Num();
|
||||||
|
m_states.Add(InternalStateData(in_name));
|
||||||
|
auto state = MakeShared<FSM::State<tStateInput, tStateConstructorFn>>(MoveTemp(in_stateCtorFn), newStateId, in_name);
|
||||||
|
return FSM::StateHandle<tStateInput, tStateConstructorFn>{ state };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new FSM exit state (immediately terminates the FSM when executed)
|
||||||
|
FSM::StateHandle<void, void> State(FString in_name)
|
||||||
|
{
|
||||||
|
const FSM::StateId newStateId = m_states.Num();
|
||||||
|
m_states.Add(InternalStateData(in_name));
|
||||||
|
m_exitStates.Add(newStateId);
|
||||||
|
auto state = MakeShared<FSM::State<void, void>>(newStateId, in_name);
|
||||||
|
return FSM::StateHandle<void, void>{ state };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the initial entry links into the state machine
|
||||||
|
void EntryLinks(TArray<FSM::LinkHandle> in_entryLinks);
|
||||||
|
|
||||||
|
// Define all outgoing links from a given state (may only be called once per state)
|
||||||
|
template<class tStateInput, class tStateConstructorFn>
|
||||||
|
void StateLinks(const FSM::StateHandle<tStateInput, tStateConstructorFn>& in_originState, TArray<FSM::LinkHandle> in_outgoingLinks);
|
||||||
|
|
||||||
|
// Begins execution of the state machine (returns id of final exit state)
|
||||||
|
Task<FSM::StateId> Run(tOnStateTransitionFn in_onTransitionFn = {}, tDebugStateTransitionFn in_debugStateTransitionFn = {}) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Evaluates all possible outgoing links from the current state, returning the first valid transition (if any transitions are valid)
|
||||||
|
TOptional<FSM::TransitionEvent> EvaluateLinks(FSM::StateId in_curStateId, bool in_isCurrentStateComplete, const tOnStateTransitionFn& in_onTransitionFn) const;
|
||||||
|
|
||||||
|
// Internal state
|
||||||
|
struct InternalStateData
|
||||||
|
{
|
||||||
|
InternalStateData(FString in_debugName)
|
||||||
|
: debugName(in_debugName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
TArray<FSM::LinkHandle> outgoingLinks;
|
||||||
|
FString debugName;
|
||||||
|
};
|
||||||
|
TArray<InternalStateData> m_states;
|
||||||
|
TArray<FSM::LinkHandle> m_entryLinks;
|
||||||
|
TArray<FSM::StateId> m_exitStates;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @} end of group TaskFSM
|
||||||
|
|
||||||
|
//--- TaskFSM Methods ---//
|
||||||
|
template<class tStateInput, class tStateConstructorFn>
|
||||||
|
void TaskFSM::StateLinks(const FSM::StateHandle<tStateInput, tStateConstructorFn>& in_originState, TArray<FSM::LinkHandle> in_outgoingLinks)
|
||||||
|
{
|
||||||
|
const int32_t stateIdx = in_originState.m_state->stateId.idx;
|
||||||
|
SQUID_RUNTIME_CHECK(m_states[stateIdx].outgoingLinks.Num() == 0, "Cannot set outgoing links more than once for each state");
|
||||||
|
|
||||||
|
// Validate that there are exactly 0 or 1 unconditional OnComplete links (there may be any number of other OnComplete links, but only one with no condition)
|
||||||
|
int32_t numOnCompleteLinks = 0;
|
||||||
|
int32_t numOnCompleteLinks_Unconditional = 0;
|
||||||
|
for(const FSM::LinkHandle& link : in_outgoingLinks)
|
||||||
|
{
|
||||||
|
if(link.IsOnCompleteLink())
|
||||||
|
{
|
||||||
|
SQUID_RUNTIME_CHECK(numOnCompleteLinks_Unconditional == 0, "Cannot call OnCompleteLink() after calling OnCompleteLink() with no conditions (unreachable link)");
|
||||||
|
++numOnCompleteLinks;
|
||||||
|
if(!link.HasCondition())
|
||||||
|
{
|
||||||
|
numOnCompleteLinks_Unconditional++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SQUID_RUNTIME_CHECK(numOnCompleteLinks == 0 || numOnCompleteLinks_Unconditional > 0, "More than one unconditional OnCompleteLink() was set");
|
||||||
|
|
||||||
|
// Set the outgoing links for the origin state
|
||||||
|
m_states[stateIdx].outgoingLinks = MoveTemp(in_outgoingLinks);
|
||||||
|
}
|
||||||
|
inline void TaskFSM::EntryLinks(TArray<FSM::LinkHandle> in_entryLinks)
|
||||||
|
{
|
||||||
|
// Validate to ensure there are no OnComplete links set as entry links
|
||||||
|
int32_t numOnCompleteLinks = 0;
|
||||||
|
for(const FSM::LinkHandle& link : in_entryLinks)
|
||||||
|
{
|
||||||
|
if(link.IsOnCompleteLink())
|
||||||
|
{
|
||||||
|
++numOnCompleteLinks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SQUID_RUNTIME_CHECK(numOnCompleteLinks == 0, "EntryLinks() list may not contain any OnCompleteLink() links");
|
||||||
|
|
||||||
|
// Set the entry links list for this FSM
|
||||||
|
m_entryLinks = MoveTemp(in_entryLinks);
|
||||||
|
}
|
||||||
|
inline TOptional<FSM::TransitionEvent> TaskFSM::EvaluateLinks(FSM::StateId in_curStateId, bool in_isCurrentStateComplete, const tOnStateTransitionFn& in_onTransitionFn) const
|
||||||
|
{
|
||||||
|
// Determine whether to use entry links or state-specific outgoing links
|
||||||
|
const TArray<FSM::LinkHandle>& links = (in_curStateId.idx < m_states.Num()) ? m_states[in_curStateId.idx].outgoingLinks : m_entryLinks;
|
||||||
|
|
||||||
|
// Find the first valid transition from the current state
|
||||||
|
for(const FSM::LinkHandle& link : links)
|
||||||
|
{
|
||||||
|
if(!link.IsOnCompleteLink() || in_isCurrentStateComplete) // Skip link evaluation check for OnComplete links unless current state is complete
|
||||||
|
{
|
||||||
|
if(auto result = link.EvaluateLink(in_onTransitionFn)) // Check if the transition to this state is valid
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}; // No valid transition was found
|
||||||
|
}
|
||||||
|
inline Task<FSM::StateId> TaskFSM::Run(tOnStateTransitionFn in_onTransitionFn, tDebugStateTransitionFn in_debugStateTransitionFn) const
|
||||||
|
{
|
||||||
|
// Task-local variables
|
||||||
|
FSM::StateId curStateId; // The current state's ID
|
||||||
|
Task<> task; // The current state's task
|
||||||
|
|
||||||
|
// Custom debug task name logic
|
||||||
|
TASK_NAME(__FUNCTION__, [this, &curStateId, &task]
|
||||||
|
{
|
||||||
|
const auto stateName = m_states.IsValidIndex(curStateId.idx) ? m_states[curStateId.idx].debugName : "";
|
||||||
|
return FString::Printf(TEXT("%s -- %s"), *stateName, *task.GetDebugStack());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Debug state transition lambda
|
||||||
|
auto DebugStateTransition = [this, in_debugStateTransitionFn](FSM::StateId in_oldStateId, FSM::StateId in_newStateId) {
|
||||||
|
if(in_debugStateTransitionFn)
|
||||||
|
{
|
||||||
|
FString oldStateName = in_oldStateId.IsValid() ? m_states[in_oldStateId.idx].debugName : FString("<ENTRY>");
|
||||||
|
FString newStateName = m_states[in_newStateId.idx].debugName;
|
||||||
|
in_debugStateTransitionFn({ in_oldStateId, MoveTemp(oldStateName), in_newStateId, MoveTemp(newStateName) });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Main FSM loop
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// Evaluate links, checking for a valid transition
|
||||||
|
if(TOptional<FSM::TransitionEvent> transition = EvaluateLinks(curStateId, task.IsDone(), in_onTransitionFn))
|
||||||
|
{
|
||||||
|
auto newStateId = transition->newStateId;
|
||||||
|
DebugStateTransition(curStateId, newStateId); // Call state-transition debug function
|
||||||
|
|
||||||
|
// If the transition is to an exit state, return that state ID (terminating the FSM)
|
||||||
|
if(m_exitStates.Contains(newStateId.idx))
|
||||||
|
{
|
||||||
|
co_return newStateId;
|
||||||
|
}
|
||||||
|
SQUID_RUNTIME_CHECK(newStateId.idx < m_states.Num(), "It should be logically impossible to get an invalid state to this point");
|
||||||
|
|
||||||
|
// Begin running new state (implicitly killing old state)
|
||||||
|
curStateId = newStateId;
|
||||||
|
co_await RemoveStopTask(task);
|
||||||
|
task = MoveTemp(transition->newTask); // NOTE: Initial call to Resume() happens below
|
||||||
|
co_await AddStopTask(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resume current state
|
||||||
|
task.Resume();
|
||||||
|
|
||||||
|
// Suspend until next frame
|
||||||
|
co_await Suspend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_END
|
215
include/TaskManager.h
Normal file
215
include/TaskManager.h
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @defgroup TaskManager Task Manager
|
||||||
|
/// @brief Manager that runs and resumes a collection of tasks.
|
||||||
|
/// @{
|
||||||
|
///
|
||||||
|
/// A TaskManager is a simple manager class that holds an ordered list of tasks and resumes them whenever it is updated.
|
||||||
|
///
|
||||||
|
/// Running Tasks
|
||||||
|
/// -------------
|
||||||
|
/// There are two primary ways to run tasks on a task manager.
|
||||||
|
///
|
||||||
|
/// The first method (running an "unmanaged task") is to pass a task into @ref TaskManager::Run(). This will move the task
|
||||||
|
/// into the task manager and return a @ref TaskHandle that can be used to observe and manage the lifetime of the task (as well
|
||||||
|
/// as potentially take a return value after the task finishes). With unmanaged tasks, the task manager only holds a weak
|
||||||
|
/// reference to the task, meaning that the @ref TaskHandle returned by @ref TaskManager::Run() is the only remaining strong
|
||||||
|
/// reference to the task. Because of this, the caller is entirely responsible for managing the lifetime of the task.
|
||||||
|
///
|
||||||
|
/// The second method (running a "managed task") is to pass a task into @ref TaskManager::RunManaged(). Like
|
||||||
|
/// @ref TaskManager::Run(), this will move the task into the task manager and return a @ref WeakTaskHandle that can be used to
|
||||||
|
/// observe the lifetime of the task (as well as manually kill it, if desired). Unlike unmanaged tasks, the task manager
|
||||||
|
/// stores a strong reference to the task. Because of this, that caller is not responsible for managing the lifetime of
|
||||||
|
/// the task. This difference in task ownership means that (unlike an unmanaged task) a managed task can be thought of as
|
||||||
|
/// a "fire-and-forget" task that will run until either it finishes or until something else explicitly kills it.
|
||||||
|
///
|
||||||
|
/// Order of Execution
|
||||||
|
/// ------------------
|
||||||
|
/// The ordering of task updates within a call to @ref TaskManager::Update() is stable, meaning that the first task that
|
||||||
|
/// is run on a task manager will remain the first to resume, no matter how many other tasks are run on the task manager
|
||||||
|
/// (or terminate) in the meantime.
|
||||||
|
///
|
||||||
|
/// Integration into Actor Classes
|
||||||
|
/// ------------------------------
|
||||||
|
/// Consider the following example of a TaskManager that has been integrated into a TaskActor base class:
|
||||||
|
///
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||||
|
///
|
||||||
|
/// class TaskActor : public Actor
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
/// virtual void OnInitialize() override // Automatically called when this enemy enters the scene
|
||||||
|
/// {
|
||||||
|
/// Actor::OnInitialize(); // Call the base Actor function
|
||||||
|
/// m_taskMgr.RunManaged(ManageActor()); // Run main actor task as a fire-and-forget "managed task"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// virtual void Tick(float in_dt) override // Automatically called every frame
|
||||||
|
/// {
|
||||||
|
/// Actor::Tick(in_dt); // Call the base Actor function
|
||||||
|
/// m_taskMgr.Update(); // Resume all active tasks once per tick
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// virtual void OnDestroy() override // Automatically called when this enemy leaves the scene
|
||||||
|
/// {
|
||||||
|
/// m_taskMgr.KillAllTasks(); // Kill all active tasks when we leave the scene
|
||||||
|
/// Actor::OnDestroy(); // Call the base Actor function
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// protected:
|
||||||
|
/// virtual Task<> ManageActor() // Overridden (in its entirety) by child classes
|
||||||
|
/// {
|
||||||
|
/// co_await WaitForever(); // Waits forever (doing nothing)
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// TaskManager m_taskMgr;
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
///
|
||||||
|
/// In the above example, TaskManager is instantiated once per high-level actor. It is updated once per frame within
|
||||||
|
/// the Tick() method, and all its tasks are killed when it leaves the scene in OnDestroy(). Lastly, a single entry-point
|
||||||
|
/// coroutine is run as a managed task when the actor enters the scene. (The above is the conventional method of integration
|
||||||
|
/// into this style of game engine.)
|
||||||
|
///
|
||||||
|
/// Note that it is sometimes necessary to have multiple TaskManagers within a single actor. For example, if there are
|
||||||
|
/// multiple tick functions (such as one for pre-physics updates and one for post-physics updates), then instantiating
|
||||||
|
/// a second "post-physics" task manager may be desirable.
|
||||||
|
|
||||||
|
#include "Task.h"
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
|
||||||
|
//--- TaskManager ---//
|
||||||
|
/// Manager that runs and resumes a collection of tasks.
|
||||||
|
class TaskManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~TaskManager() {} /// Destructor (disables copy/move construction + assignment)
|
||||||
|
|
||||||
|
/// @brief Run an unmanaged task
|
||||||
|
/// @details Run() return a @ref TaskHandle<> that holds a strong reference to the task. If there are ever no
|
||||||
|
/// strong references remaining to an unmanaged task, it will immediately be killed and removed from the manager.
|
||||||
|
template <typename tRet>
|
||||||
|
SQUID_NODISCARD TaskHandle<tRet> Run(Task<tRet>&& in_task)
|
||||||
|
{
|
||||||
|
// Run unmanaged task
|
||||||
|
TaskHandle<tRet> taskHandle = in_task;
|
||||||
|
WeakTask weakTask = MoveTemp(in_task);
|
||||||
|
RunWeakTask(MoveTemp(weakTask));
|
||||||
|
return taskHandle;
|
||||||
|
}
|
||||||
|
template <typename tRet>
|
||||||
|
SQUID_NODISCARD TaskHandle<tRet> Run(const Task<tRet>& in_task) /// @private Illegal copy implementation
|
||||||
|
{
|
||||||
|
static_assert(static_false<tRet>::value, "Cannot run an unmanaged task by copy (try Run(MoveTemp(task)))");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Run a managed task
|
||||||
|
/// @details RunManaged() return a @ref WeakTaskHandle, meaning it can be used to run a "fire-and-forget" background
|
||||||
|
/// task in situations where it is not necessary to observe or control task lifetime.
|
||||||
|
template <typename tRet>
|
||||||
|
WeakTaskHandle RunManaged(Task<tRet>&& in_task)
|
||||||
|
{
|
||||||
|
// Run managed task
|
||||||
|
WeakTaskHandle weakTaskHandle = in_task;
|
||||||
|
m_strongRefs.Add(Run(MoveTemp(in_task)));
|
||||||
|
return weakTaskHandle;
|
||||||
|
}
|
||||||
|
template <typename tRet>
|
||||||
|
WeakTaskHandle RunManaged(const Task<tRet>& in_task) /// @private Illegal copy implementation
|
||||||
|
{
|
||||||
|
static_assert(static_false<tRet>::value, "Cannot run a managed task by copy (try RunManaged(MoveTemp(task)))");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Run a weak task
|
||||||
|
/// @details RunWeakTask() runs a WeakTask. The caller is assumed to have already created a strong TaskHandle<> that
|
||||||
|
/// references the WeakTask, thus keeping it from being killed. When the last strong reference to the WeakTask is
|
||||||
|
/// destroyed, the task will immediately be killed and removed from the manager.
|
||||||
|
void RunWeakTask(WeakTask&& in_task)
|
||||||
|
{
|
||||||
|
// Run unmanaged task
|
||||||
|
m_tasks.Add(MoveTemp(in_task));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call Task::Kill() on all tasks (managed + unmanaged)
|
||||||
|
void KillAllTasks()
|
||||||
|
{
|
||||||
|
m_tasks.Reset(); // Destroying all the weak tasks implicitly destroys all internal tasks
|
||||||
|
|
||||||
|
// No need to call Kill() on each TaskHandle in m_strongRefs
|
||||||
|
m_strongRefs.Reset(); // Handles in the strong refs array only ever point to tasks in the now-cleared m_tasks array
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Issue a stop request using @ref Task::RequestStop() on all active tasks (managed and unmanaged)
|
||||||
|
/// @details Returns a new awaiter task that will wait until all those tasks have all terminated.
|
||||||
|
Task<> StopAllTasks()
|
||||||
|
{
|
||||||
|
// Request stop on all tasks
|
||||||
|
TArray<WeakTaskHandle> weakHandles;
|
||||||
|
for(auto& task : m_tasks)
|
||||||
|
{
|
||||||
|
task.RequestStop();
|
||||||
|
weakHandles.Add(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a fence task that waits until all stopped tasks are complete
|
||||||
|
return [](TArray<WeakTaskHandle> in_weakHandles) -> Task<> {
|
||||||
|
TASK_NAME("StopAllTasks() Fence Task");
|
||||||
|
for(const auto& weakHandle : in_weakHandles)
|
||||||
|
{
|
||||||
|
co_await weakHandle; // Wait until task is complete
|
||||||
|
}
|
||||||
|
}(MoveTemp(weakHandles));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call @ref Task::Resume() on all active tasks exactly once (managed + unmanaged)
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
// Resume all tasks
|
||||||
|
int32 writeIdx = 0;
|
||||||
|
for(int32 readIdx = 0; readIdx < m_tasks.Num(); ++readIdx)
|
||||||
|
{
|
||||||
|
if(m_tasks[readIdx].Resume() != eTaskStatus::Done)
|
||||||
|
{
|
||||||
|
if(writeIdx != readIdx)
|
||||||
|
{
|
||||||
|
m_tasks[writeIdx] = MoveTemp(m_tasks[readIdx]);
|
||||||
|
}
|
||||||
|
++writeIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_tasks.SetNum(writeIdx);
|
||||||
|
|
||||||
|
// Prune strong tasks that are done
|
||||||
|
m_strongRefs.RemoveAllSwap([](const auto& in_taskHandle) { return in_taskHandle.IsDone(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a debug string containing a list of all active tasks
|
||||||
|
FString GetDebugString(TOptional<TaskDebugStackFormatter> in_formatter = {}) const
|
||||||
|
{
|
||||||
|
FString debugStr;
|
||||||
|
for(const auto& task : m_tasks)
|
||||||
|
{
|
||||||
|
if(!task.IsDone())
|
||||||
|
{
|
||||||
|
if(debugStr.Len())
|
||||||
|
{
|
||||||
|
debugStr += '\n';
|
||||||
|
}
|
||||||
|
debugStr += task.GetDebugStack(in_formatter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return debugStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TArray<WeakTask> m_tasks;
|
||||||
|
TArray<TaskHandle<>> m_strongRefs;
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
|
||||||
|
///@} end of TaskManager group
|
48
include/TasksConfig.h
Normal file
48
include/TasksConfig.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Squid::Tasks version (major.minor.patch)
|
||||||
|
#define SQUID_TASKS_VERSION_MAJOR 0
|
||||||
|
#define SQUID_TASKS_VERSION_MINOR 2
|
||||||
|
#define SQUID_TASKS_VERSION_PATCH 0
|
||||||
|
|
||||||
|
/// @defgroup Config Configuration
|
||||||
|
/// @brief Configuration settings for the Squid::Tasks library
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Enables Task debug names and callstack tracking via Task::GetDebugStack() and Task::GetDebugName()
|
||||||
|
#ifndef SQUID_ENABLE_TASK_DEBUG
|
||||||
|
#define SQUID_ENABLE_TASK_DEBUG 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Switches time type (tTaskTime) from 32-bit single-precision floats to 64-bit double-precision floats
|
||||||
|
#ifndef SQUID_ENABLE_DOUBLE_PRECISION_TIME
|
||||||
|
#define SQUID_ENABLE_DOUBLE_PRECISION_TIME 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Wraps a Squid:: namespace around all classes in the Squid::Tasks library
|
||||||
|
#ifndef SQUID_ENABLE_NAMESPACE
|
||||||
|
#define SQUID_ENABLE_NAMESPACE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Enables experimental (largely-untested) exception handling, and replaces all asserts with runtime_error exceptions
|
||||||
|
#ifndef SQUID_USE_EXCEPTIONS
|
||||||
|
#define SQUID_USE_EXCEPTIONS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Enables global time support(alleviating the need to specify a time stream for time - sensitive awaiters) [see @ref GetGlobalTime()]
|
||||||
|
#ifndef SQUID_ENABLE_GLOBAL_TIME
|
||||||
|
// ***************
|
||||||
|
// *** WARNING ***
|
||||||
|
// ***************
|
||||||
|
// It is generally inadvisable for game projects to define a global task time, as it assumes there is only a single time-stream.
|
||||||
|
// Within game projects, there is usually a "game time" and "real time", as well as others (such as "audio time", "unpaused time").
|
||||||
|
// Furthermore, in engines such as Unreal, a non-static world context object must be provided.
|
||||||
|
|
||||||
|
// To enable global task time, user must *also* define a GetGlobalTime() implementation (otherwise there will be a linker error)
|
||||||
|
#define SQUID_ENABLE_GLOBAL_TIME 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @} end of addtogroup Config
|
||||||
|
|
||||||
|
//--- C++17/C++20 Compatibility ---//
|
||||||
|
#include "Private/TasksCommonPrivate.h"
|
320
include/TokenList.h
Normal file
320
include/TokenList.h
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @defgroup Tokens Token List
|
||||||
|
/// @brief Data structure for tracking decentralized state across multiple tasks.
|
||||||
|
/// @{
|
||||||
|
///
|
||||||
|
/// Token objects can be created using @ref TokenList::MakeToken(), returning a shared pointer to a new Token. This
|
||||||
|
/// new Token can then be added to the TokenList using @ref TokenList::AddToken(). @ref TokenList::TakeToken()
|
||||||
|
/// can be used to make + add a new token with a single function call.
|
||||||
|
///
|
||||||
|
/// Because TokenList uses weak pointers to track its elements, Token objects are logically removed from the list once
|
||||||
|
/// they are destroyed. As such, it is usually unnecessary to explicitly call @ref TokenList::RemoveToken() to remove a
|
||||||
|
/// Token from the list. Instead, it is idiomatic to consider the Token to be a sort of "scope guard" that will remove
|
||||||
|
/// itself from all TokenList objects when it leaves scope.
|
||||||
|
///
|
||||||
|
/// The TokenList class is included as part of Squid::Tasks to provide a simple mechanism for robustly sharing aribtrary
|
||||||
|
/// state between multiple tasks. Consider this example of a poison damage-over-time system:
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||||
|
///
|
||||||
|
/// class Character : public Actor
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
/// bool IsPoisoned() const
|
||||||
|
/// {
|
||||||
|
/// return m_poisonTokens; // Whether there are any live poison tokens
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// void OnPoisoned(float in_dps, float in_duration)
|
||||||
|
/// {
|
||||||
|
/// m_taskMgr.RunManaged(ManagePoisonInstance(in_dps, in_duration));
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// private:
|
||||||
|
/// TokenList<float> m_poisonTokens; // Token list indicating live poison damage
|
||||||
|
///
|
||||||
|
/// Task<> ManagePoisonInstance(float in_dps, float in_duration)
|
||||||
|
/// {
|
||||||
|
/// // Take a poison token and hold it for N seconds
|
||||||
|
/// auto poisonToken = m_poisonTokens.TakeToken(__FUNCTION__, in_dps);
|
||||||
|
/// co_await WaitSeconds(in_duration);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Task<> ManageCharacter() // Called once per frame
|
||||||
|
/// {
|
||||||
|
/// while(true)
|
||||||
|
/// {
|
||||||
|
/// float poisonDps = m_poisonTokens.GetMax(); // Get highest DPS poison instance
|
||||||
|
/// DealDamage(poisonDps * GetDT()); // Deal the actual poison damage
|
||||||
|
/// co_await Suspend();
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
///
|
||||||
|
/// As the above example shows, this mechanism is well-suited for coroutines, as they can hold a Token across
|
||||||
|
/// multiple frames. Also note that Token objects can optionally hold data. The TokenList class has query functions
|
||||||
|
/// (e.g. GetMin()/GetMax()) that can be used to aggregate the data from the set of live tokens. This is used above
|
||||||
|
/// to quickly find the highest DPS poison instance.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
//--- User configuration header ---//
|
||||||
|
#include "TasksConfig.h"
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
|
||||||
|
template <typename T = void>
|
||||||
|
class TokenList;
|
||||||
|
|
||||||
|
/// @brief Handle to a TokenList element that stores a debug name
|
||||||
|
/// @details In most circumstances, name should be set to \ref __FUNCTION__ at the point of creation.
|
||||||
|
struct Token
|
||||||
|
{
|
||||||
|
Token(FString in_name)
|
||||||
|
: name(MoveTemp(in_name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FString name; // Used for debug only
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Handle to a TokenList element that stores both a debug name and associated data
|
||||||
|
/// @details In most circumstances, name should be set to \c __FUNCTION__ at the point of creation.
|
||||||
|
template <typename tData>
|
||||||
|
struct DataToken
|
||||||
|
{
|
||||||
|
DataToken(FString in_name, tData in_data)
|
||||||
|
: name(MoveTemp(in_name))
|
||||||
|
, data(MoveTemp(in_data))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FString name; // Used for debug only
|
||||||
|
tData data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create a token with the specified debug name
|
||||||
|
inline TSharedPtr<Token> MakeToken(FString in_name)
|
||||||
|
{
|
||||||
|
return MakeShared<Token>(MoveTemp(in_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a token with the specified debug name and associated data
|
||||||
|
template <typename tData>
|
||||||
|
TSharedPtr<DataToken<tData>> MakeToken(FString in_name, tData in_data)
|
||||||
|
{
|
||||||
|
return MakeShared<DataToken<tData>>(MoveTemp(in_name), MoveTemp(in_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Container for tracking decentralized state across multiple tasks. (See \ref Tokens for more info...)
|
||||||
|
/// @tparam T Type of data to associate with each Token in this container
|
||||||
|
template <typename T>
|
||||||
|
class TokenList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Type of Token tracked by this container
|
||||||
|
using Token = typename std::conditional_t<std::is_void<T>::value, Token, DataToken<T>>;
|
||||||
|
|
||||||
|
/// Create a token with the specified debug name
|
||||||
|
template <typename U = T, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
|
||||||
|
static TSharedPtr<Token> MakeToken(FString in_name)
|
||||||
|
{
|
||||||
|
return MakeShared<Token>(MoveTemp(in_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a token with the specified debug name and associated data
|
||||||
|
template <typename U = T, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
static TSharedPtr<Token> MakeToken(FString in_name, U in_data)
|
||||||
|
{
|
||||||
|
return MakeShared<Token>(MoveTemp(in_name), MoveTemp(in_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create and add a token with the specified debug name
|
||||||
|
template <typename U = T, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
|
||||||
|
SQUID_NODISCARD TSharedPtr<Token> TakeToken(FString in_name)
|
||||||
|
{
|
||||||
|
return AddToken(MakeToken(MoveTemp(in_name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create and add a token with the specified debug name and associated data
|
||||||
|
template <typename U = T, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
SQUID_NODISCARD TSharedPtr<Token> TakeToken(FString in_name, U in_data)
|
||||||
|
{
|
||||||
|
return AddToken(MakeToken(MoveTemp(in_name), MoveTemp(in_data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an existing token to this container
|
||||||
|
TSharedPtr<Token> AddToken(TSharedPtr<Token> in_token)
|
||||||
|
{
|
||||||
|
SQUID_RUNTIME_CHECK(in_token, "Cannot add null token");
|
||||||
|
Sanitize();
|
||||||
|
m_tokens.AddUnique(in_token);
|
||||||
|
return in_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Explicitly remove a token from this container
|
||||||
|
void RemoveToken(TSharedPtr<Token> in_token)
|
||||||
|
{
|
||||||
|
// Find and remove the token
|
||||||
|
m_tokens.Remove(in_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience conversion operator that calls HasTokens()
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return HasTokens();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this container holds any live tokens
|
||||||
|
bool HasTokens() const
|
||||||
|
{
|
||||||
|
// Return true when holding any unexpired tokens
|
||||||
|
for(auto i = (int32_t)(m_tokens.Num() - 1); i >= 0; --i)
|
||||||
|
{
|
||||||
|
const auto& token = m_tokens[i];
|
||||||
|
if(token.IsValid())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
m_tokens.Pop(); // Because the token is expired, we can safely remove it from the back
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an array of all live token data
|
||||||
|
TArray<T> GetTokenData() const
|
||||||
|
{
|
||||||
|
TArray<T> tokenData;
|
||||||
|
for(const auto& tokenWeak : m_tokens)
|
||||||
|
{
|
||||||
|
if(auto token = tokenWeak.Pin())
|
||||||
|
{
|
||||||
|
tokenData.Add(token->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tokenData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @name Data Queries
|
||||||
|
/// Methods for querying and aggregating the data from the set of live tokens.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Returns associated data from the least-recently-added live token
|
||||||
|
TOptional<T> GetLeastRecent() const
|
||||||
|
{
|
||||||
|
Sanitize();
|
||||||
|
return m_tokens.Num() ? m_tokens[0].Pin()->data : TOptional<T>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns associated data from the most-recently-added live token
|
||||||
|
TOptional<T> GetMostRecent() const
|
||||||
|
{
|
||||||
|
Sanitize();
|
||||||
|
return m_tokens.Num() ? m_tokens.Last().Pin()->data : TOptional<T>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns smallest associated data from the set of live tokens
|
||||||
|
TOptional<T> GetMin() const
|
||||||
|
{
|
||||||
|
TOptional<T> ret;
|
||||||
|
SanitizeAndProcessData([&ret](const T& in_data) {
|
||||||
|
if(!ret || in_data < ret.GetValue())
|
||||||
|
{
|
||||||
|
ret = in_data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns largest associated data from the set of live tokens
|
||||||
|
TOptional<T> GetMax() const
|
||||||
|
{
|
||||||
|
TOptional<T> ret;
|
||||||
|
SanitizeAndProcessData([&ret](const T& in_data) {
|
||||||
|
if(!ret || in_data > ret.GetValue())
|
||||||
|
{
|
||||||
|
ret = in_data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns arithmetic mean of all associated data from the set of live tokens
|
||||||
|
TOptional<double> GetMean() const
|
||||||
|
{
|
||||||
|
TOptional<double> ret;
|
||||||
|
TOptional<double> total;
|
||||||
|
SanitizeAndProcessData([&total](const T& in_data) {
|
||||||
|
total = total.Get(0.0) + (double)in_data;
|
||||||
|
});
|
||||||
|
if(total)
|
||||||
|
{
|
||||||
|
ret = total.GetValue() / m_tokens.Num();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the set of live tokens contains at least one token associated with the specified data
|
||||||
|
template <typename U = T, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
bool Contains(const U& in_searchData) const
|
||||||
|
{
|
||||||
|
bool containsData = false;
|
||||||
|
SanitizeAndProcessData([&in_searchData, &containsData](const T& in_data) {
|
||||||
|
if(in_searchData == in_data)
|
||||||
|
{
|
||||||
|
containsData = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return containsData;
|
||||||
|
}
|
||||||
|
///@} end of Data Queries
|
||||||
|
|
||||||
|
/// Returns a debug string containing a list of the debug names of all live tokens
|
||||||
|
FString GetDebugString() const
|
||||||
|
{
|
||||||
|
TArray<FString> tokenStrings;
|
||||||
|
for(auto token : m_tokens)
|
||||||
|
{
|
||||||
|
if(token.IsValid())
|
||||||
|
{
|
||||||
|
tokenStrings.Add(token.Pin()->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(tokenStrings.Num())
|
||||||
|
{
|
||||||
|
return FString::Join(tokenStrings, TEXT("\n"));
|
||||||
|
}
|
||||||
|
return TEXT("[no tokens]");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Sanitation
|
||||||
|
void Sanitize() const
|
||||||
|
{
|
||||||
|
// Remove all invalid tokens
|
||||||
|
m_tokens.RemoveAll([](const Wp<Token>& in_token) { return !in_token.IsValid(); });
|
||||||
|
}
|
||||||
|
template <typename tFn>
|
||||||
|
void SanitizeAndProcessData(tFn in_dataFn) const
|
||||||
|
{
|
||||||
|
// Remove all invalid tokens while applying a processing function on each valid token
|
||||||
|
m_tokens.RemoveAll([&in_dataFn](const TWeakPtr<Token>& in_token) {
|
||||||
|
if(auto pinnedToken = in_token.Pin())
|
||||||
|
{
|
||||||
|
in_dataFn(pinnedToken->data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token data
|
||||||
|
mutable TArray<TWeakPtr<Token>> m_tokens; // Mutable so we can remove expired tokens while converting bool
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
|
||||||
|
///@} end of Tokens group
|
52
samples/Common/TimeSystem.h
Normal file
52
samples/Common/TimeSystem.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
//--- Time System ---//
|
||||||
|
class TimeSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename... Args>
|
||||||
|
static void Create(Args&&... args)
|
||||||
|
{
|
||||||
|
s_timeSys = new TimeSystem(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
static void UpdateTime()
|
||||||
|
{
|
||||||
|
s_timeSys->_UpdateTime();
|
||||||
|
}
|
||||||
|
static auto GetTimeSince(double in_time)
|
||||||
|
{
|
||||||
|
return s_timeSys->_GetTimeSince(in_time);
|
||||||
|
}
|
||||||
|
static auto GetTime()
|
||||||
|
{
|
||||||
|
return s_timeSys->_GetTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimeSystem()
|
||||||
|
{
|
||||||
|
m_startTimePoint = std::chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
void _UpdateTime()
|
||||||
|
{
|
||||||
|
std::chrono::steady_clock::time_point curTimePoint = std::chrono::steady_clock::now();
|
||||||
|
std::chrono::duration<double> span = std::chrono::duration_cast<std::chrono::duration<double>>(curTimePoint - m_startTimePoint);
|
||||||
|
m_time = span.count();
|
||||||
|
}
|
||||||
|
double _GetTimeSince(double in_time) const
|
||||||
|
{
|
||||||
|
return m_time - in_time;
|
||||||
|
}
|
||||||
|
double _GetTime() const
|
||||||
|
{
|
||||||
|
return m_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::steady_clock::time_point m_startTimePoint;
|
||||||
|
std::atomic<double> m_time;
|
||||||
|
static TimeSystem* s_timeSys;
|
||||||
|
};
|
||||||
|
TimeSystem* TimeSystem::s_timeSys;
|
32
samples/Sample_Template/Main.cpp
Normal file
32
samples/Sample_Template/Main.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "Task.h"
|
||||||
|
#include "TaskManager.h"
|
||||||
|
#include "TimeSystem.h"
|
||||||
|
|
||||||
|
// User-defined GetGlobalTime() is required to link Task.h
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
tTaskTime GetGlobalTime()
|
||||||
|
{
|
||||||
|
return (tTaskTime)TimeSystem::GetTime();
|
||||||
|
}
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
|
||||||
|
// Simple main function
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
TimeSystem::Create();
|
||||||
|
|
||||||
|
// Initialize the game
|
||||||
|
// ... <your code here> ...
|
||||||
|
|
||||||
|
// Run the game until it's ready to quit
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// Update time before each frame (logically, all tasks should resume "at the same time")
|
||||||
|
TimeSystem::UpdateTime();
|
||||||
|
|
||||||
|
// Update the game
|
||||||
|
// ... <your code here> ...
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
172
samples/Sample_Template/Sample_Template.vcxproj
Normal file
172
samples/Sample_Template/Sample_Template.vcxproj
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Main.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\include\FunctionGuard.h" />
|
||||||
|
<ClInclude Include="..\..\include\Private\TasksCommonPrivate.h" />
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskFSMPrivate.h" />
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskPrivate.h" />
|
||||||
|
<ClInclude Include="..\..\include\Task.h" />
|
||||||
|
<ClInclude Include="..\..\include\TaskFSM.h" />
|
||||||
|
<ClInclude Include="..\..\include\TaskManager.h" />
|
||||||
|
<ClInclude Include="..\..\include\TasksConfig.h" />
|
||||||
|
<ClInclude Include="..\..\include\TokenList.h" />
|
||||||
|
<ClInclude Include="..\Common\TimeSystem.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{E48F8265-C836-4564-9525-AFB12295CF64}</ProjectGuid>
|
||||||
|
<RootNamespace>Sample_Template</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
<ProjectName>Sample_Template</ProjectName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await -Xclang -fcoroutines-ts %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await -Xclang -fcoroutines-ts %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await -Xclang -fcoroutines-ts %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await -Xclang -fcoroutines-ts %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
63
samples/Sample_Template/Sample_Template.vcxproj.filters
Normal file
63
samples/Sample_Template/Sample_Template.vcxproj.filters
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\SquidTasks">
|
||||||
|
<UniqueIdentifier>{63b632a7-ce3c-4dd9-a970-5e661d591932}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\SquidTasks\Private">
|
||||||
|
<UniqueIdentifier>{89a92d2a-3fa9-4c0d-8dbf-466c03830dc3}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\Common">
|
||||||
|
<UniqueIdentifier>{cf5b02a9-ec31-44ea-9840-80634ce22458}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Main.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\include\FunctionGuard.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Task.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TaskManager.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TasksConfig.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TokenList.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TaskFSM.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskFSMPrivate.h">
|
||||||
|
<Filter>Source Files\SquidTasks\Private</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskPrivate.h">
|
||||||
|
<Filter>Source Files\SquidTasks\Private</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Private\TasksCommonPrivate.h">
|
||||||
|
<Filter>Source Files\SquidTasks\Private</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\Common\TimeSystem.h">
|
||||||
|
<Filter>Source Files\Common</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
83
samples/Sample_Tests/Main.cpp
Normal file
83
samples/Sample_Tests/Main.cpp
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include "Task.h"
|
||||||
|
#include "TimeSystem.h"
|
||||||
|
#include "TaskFSM.h"
|
||||||
|
|
||||||
|
// User-defined GetGlobalTime() is required to link Task.h
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
tTaskTime GetGlobalTime()
|
||||||
|
{
|
||||||
|
return (tTaskTime)TimeSystem::GetTime();
|
||||||
|
}
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
|
||||||
|
Task<> IdleTask()
|
||||||
|
{
|
||||||
|
TASK_NAME(__FUNCTION__);
|
||||||
|
|
||||||
|
printf("Idle task\n");
|
||||||
|
co_await WaitForever();
|
||||||
|
}
|
||||||
|
|
||||||
|
Task<> PeriodicTask(float in_duration)
|
||||||
|
{
|
||||||
|
TASK_NAME(__FUNCTION__);
|
||||||
|
printf("Periodic task\n");
|
||||||
|
co_await WaitSeconds(in_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task<> TestFsmTask()
|
||||||
|
{
|
||||||
|
TASK_NAME(__FUNCTION__);
|
||||||
|
TaskFSM fsm;
|
||||||
|
|
||||||
|
auto LambdaStateTask = [](float in_duration) -> Task<>
|
||||||
|
{
|
||||||
|
TASK_NAME(__FUNCTION__);
|
||||||
|
printf("Lambda state!\n");
|
||||||
|
|
||||||
|
auto stopCtx = co_await GetStopContext();
|
||||||
|
co_await WaitSeconds(in_duration).CancelIf([&] { return stopCtx.IsStopRequested(); });
|
||||||
|
};
|
||||||
|
|
||||||
|
auto idleState = fsm.State("Idle", IdleTask);
|
||||||
|
auto periodicState = fsm.State("Periodic", &PeriodicTask);
|
||||||
|
auto lambdaState = fsm.State("Lambda", LambdaStateTask);
|
||||||
|
auto endState = fsm.State("End");
|
||||||
|
|
||||||
|
fsm.EntryLinks({
|
||||||
|
idleState.Link(),
|
||||||
|
});
|
||||||
|
fsm.StateLinks(idleState, {
|
||||||
|
periodicState.Link([]() -> std::optional<float> { return 1.0f; }),
|
||||||
|
endState.OnCompleteLink(),
|
||||||
|
});
|
||||||
|
fsm.StateLinks(periodicState, {
|
||||||
|
lambdaState.Link([]() -> std::optional<float> { return 2.0f; }),
|
||||||
|
});
|
||||||
|
fsm.StateLinks(lambdaState, {
|
||||||
|
idleState.OnCompleteLink(),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto fsmTask = fsm.Run();
|
||||||
|
fsmTask.RequestStop();
|
||||||
|
co_await std::move(fsmTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTaskFSM()
|
||||||
|
{
|
||||||
|
auto task = TestFsmTask();
|
||||||
|
while(task.Resume() != eTaskStatus::Done)
|
||||||
|
{
|
||||||
|
TimeSystem::UpdateTime(); // Update time before each frame (logically, all tasks should resume "at the same time")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple main function
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
TimeSystem::Create();
|
||||||
|
|
||||||
|
TestTaskFSM();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
172
samples/Sample_Tests/Sample_Tests.vcxproj
Normal file
172
samples/Sample_Tests/Sample_Tests.vcxproj
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Main.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\include\FunctionGuard.h" />
|
||||||
|
<ClInclude Include="..\..\include\Private\TasksCommonPrivate.h" />
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskFSMPrivate.h" />
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskPrivate.h" />
|
||||||
|
<ClInclude Include="..\..\include\Task.h" />
|
||||||
|
<ClInclude Include="..\..\include\TaskFSM.h" />
|
||||||
|
<ClInclude Include="..\..\include\TaskManager.h" />
|
||||||
|
<ClInclude Include="..\..\include\TasksConfig.h" />
|
||||||
|
<ClInclude Include="..\..\include\TokenList.h" />
|
||||||
|
<ClInclude Include="..\Common\TimeSystem.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{ABA88D0D-D79F-4371-BA63-D441662242B4}</ProjectGuid>
|
||||||
|
<RootNamespace>Sample_Tests</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
<ProjectName>Sample_Tests</ProjectName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await -Xclang -fcoroutines-ts %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await -Xclang -fcoroutines-ts %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await -Xclang -fcoroutines-ts %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await -Xclang -fcoroutines-ts %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
63
samples/Sample_Tests/Sample_Tests.vcxproj.filters
Normal file
63
samples/Sample_Tests/Sample_Tests.vcxproj.filters
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\SquidTasks">
|
||||||
|
<UniqueIdentifier>{63b632a7-ce3c-4dd9-a970-5e661d591932}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\SquidTasks\Private">
|
||||||
|
<UniqueIdentifier>{89a92d2a-3fa9-4c0d-8dbf-466c03830dc3}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\Common">
|
||||||
|
<UniqueIdentifier>{cf5b02a9-ec31-44ea-9840-80634ce22458}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Main.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\include\FunctionGuard.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Task.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TaskManager.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TasksConfig.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TokenList.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TaskFSM.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskFSMPrivate.h">
|
||||||
|
<Filter>Source Files\SquidTasks\Private</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskPrivate.h">
|
||||||
|
<Filter>Source Files\SquidTasks\Private</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Private\TasksCommonPrivate.h">
|
||||||
|
<Filter>Source Files\SquidTasks\Private</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\Common\TimeSystem.h">
|
||||||
|
<Filter>Source Files\Common</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
27
samples/Sample_TextGame/Main.cpp
Normal file
27
samples/Sample_TextGame/Main.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "Task.h"
|
||||||
|
#include "TimeSystem.h"
|
||||||
|
#include "TextGame.h"
|
||||||
|
#include "TaskFSM.h"
|
||||||
|
|
||||||
|
// User-defined GetGlobalTime() is required to link Task.h
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
tTaskTime GetGlobalTime()
|
||||||
|
{
|
||||||
|
return (tTaskTime)TimeSystem::GetTime();
|
||||||
|
}
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
|
||||||
|
// Simple main function
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
TimeSystem::Create();
|
||||||
|
|
||||||
|
auto game = std::make_shared<TextGame>();
|
||||||
|
while(!game->IsGameOver())
|
||||||
|
{
|
||||||
|
TimeSystem::UpdateTime(); // Update time before each frame (logically, all tasks should resume "at the same time")
|
||||||
|
game->Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
174
samples/Sample_TextGame/Sample_TextGame.vcxproj
Normal file
174
samples/Sample_TextGame/Sample_TextGame.vcxproj
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Main.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\include\FunctionGuard.h" />
|
||||||
|
<ClInclude Include="..\..\include\Private\TasksCommonPrivate.h" />
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskFSMPrivate.h" />
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskPrivate.h" />
|
||||||
|
<ClInclude Include="..\..\include\Task.h" />
|
||||||
|
<ClInclude Include="..\..\include\TaskFSM.h" />
|
||||||
|
<ClInclude Include="..\..\include\TaskManager.h" />
|
||||||
|
<ClInclude Include="..\..\include\TasksConfig.h" />
|
||||||
|
<ClInclude Include="..\..\include\TokenList.h" />
|
||||||
|
<ClInclude Include="..\Common\TimeSystem.h" />
|
||||||
|
<ClInclude Include="TextGame.h" />
|
||||||
|
<ClInclude Include="TextInput.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{9095cb85-e1b0-4d03-9a3c-b3d277a1e300}</ProjectGuid>
|
||||||
|
<RootNamespace>Sample_TextGame</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
<ProjectName>Sample_TextGame</ProjectName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await:strict -Xclang -fcoroutines-ts </AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await:strict -Xclang -fcoroutines-ts </AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>stdcpp14</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await -Xclang -fcoroutines-ts </AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);SQUIDTASK_TIME_PRECISION_DOUBLE</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<AdditionalOptions>/await:strict -Xclang -fcoroutines-ts </AdditionalOptions>
|
||||||
|
<AdditionalIncludeDirectories>../../include;../Common</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
69
samples/Sample_TextGame/Sample_TextGame.vcxproj.filters
Normal file
69
samples/Sample_TextGame/Sample_TextGame.vcxproj.filters
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\SquidTasks">
|
||||||
|
<UniqueIdentifier>{63b632a7-ce3c-4dd9-a970-5e661d591932}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\SquidTasks\Private">
|
||||||
|
<UniqueIdentifier>{0b6b681b-d03c-436c-9a7b-f544d0845b52}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\Common">
|
||||||
|
<UniqueIdentifier>{a0b32634-d0f3-491e-a37a-66c739f881e5}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="TextInput.h">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="TextGame.h">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\FunctionGuard.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Task.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TaskManager.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TasksConfig.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TokenList.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\TaskFSM.h">
|
||||||
|
<Filter>Source Files\SquidTasks</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskFSMPrivate.h">
|
||||||
|
<Filter>Source Files\SquidTasks\Private</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Private\TaskPrivate.h">
|
||||||
|
<Filter>Source Files\SquidTasks\Private</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\include\Private\TasksCommonPrivate.h">
|
||||||
|
<Filter>Source Files\SquidTasks\Private</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\Common\TimeSystem.h">
|
||||||
|
<Filter>Source Files\Common</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Main.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
1376
samples/Sample_TextGame/TextGame.h
Normal file
1376
samples/Sample_TextGame/TextGame.h
Normal file
File diff suppressed because it is too large
Load Diff
124
samples/Sample_TextGame/TextInput.h
Normal file
124
samples/Sample_TextGame/TextInput.h
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Task.h"
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include <conio.h>
|
||||||
|
|
||||||
|
using namespace Squid;
|
||||||
|
|
||||||
|
class TextInput
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TextInput()
|
||||||
|
{
|
||||||
|
m_inputThread = std::thread([this] {
|
||||||
|
InputThread();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
~TextInput()
|
||||||
|
{
|
||||||
|
m_terminate = true;
|
||||||
|
m_inputThread.join();
|
||||||
|
}
|
||||||
|
void ClearInput()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> inputLock(m_inputMutex);
|
||||||
|
m_inputStr.Reset();
|
||||||
|
}
|
||||||
|
Task<FString> WaitForInput(bool in_echoText = true)
|
||||||
|
{
|
||||||
|
TASK_NAME(__FUNCTION__);
|
||||||
|
|
||||||
|
ClearInput();
|
||||||
|
FString input;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
auto inputMaybe = GetNextInputChar();
|
||||||
|
if(inputMaybe)
|
||||||
|
{
|
||||||
|
auto c = inputMaybe.GetValue();
|
||||||
|
if(isalnum(c) || c == 32)
|
||||||
|
{
|
||||||
|
if(in_echoText)
|
||||||
|
{
|
||||||
|
std::cout << c;
|
||||||
|
}
|
||||||
|
input += c;
|
||||||
|
}
|
||||||
|
else if(c == 8) // Backspace
|
||||||
|
{
|
||||||
|
std::cout << c << ' ' << c;
|
||||||
|
input = input.substr(0, input.Num() - 1);
|
||||||
|
}
|
||||||
|
else if(c == '\r')
|
||||||
|
{
|
||||||
|
if(in_echoText)
|
||||||
|
{
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
co_await Suspend();
|
||||||
|
}
|
||||||
|
co_return input;
|
||||||
|
}
|
||||||
|
Task<char> WaitForInputChar()
|
||||||
|
{
|
||||||
|
TASK_NAME(__FUNCTION__);
|
||||||
|
|
||||||
|
ClearInput();
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
auto inputMaybe = GetNextInputChar();
|
||||||
|
if(inputMaybe)
|
||||||
|
{
|
||||||
|
auto c = inputMaybe.GetValue();
|
||||||
|
if(isalnum(c) || c == 32 || c == 8 || c == '\r')
|
||||||
|
{
|
||||||
|
co_return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
co_await Suspend();
|
||||||
|
}
|
||||||
|
co_return '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::thread m_inputThread;
|
||||||
|
bool m_terminate = false;
|
||||||
|
std::mutex m_inputMutex;
|
||||||
|
std::list<char> m_inputStr;
|
||||||
|
|
||||||
|
TOptional<char> GetNextInputChar()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> inputLock(m_inputMutex);
|
||||||
|
if(m_inputStr.Num())
|
||||||
|
{
|
||||||
|
char c = m_inputStr.front();
|
||||||
|
m_inputStr.pop_front();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
void InputThread()
|
||||||
|
{
|
||||||
|
while(!m_terminate)
|
||||||
|
{
|
||||||
|
if(_kbhit())
|
||||||
|
{
|
||||||
|
char c = _getch();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> inputLock(m_inputMutex);
|
||||||
|
m_inputStr.Add(c);
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
623
samples/Sample_TextGame/gamedata/nyms.csv
Normal file
623
samples/Sample_TextGame/gamedata/nyms.csv
Normal file
@ -0,0 +1,623 @@
|
|||||||
|
abandon abdicate, desert, leave, resign, abjure, discontinue, quit, retire from, cast off, forego, recant, retract, cease, forsake, relinquish, surrender, cede, forswear, renounce, vacate, depart from, give up, repudiate, withdraw from adopt, defend, occupy, seek, advocate, favor, prosecute, support, assert, haunt, protect, undertake, cherish, hold, pursue, uphold, claim, keep, retain, vindicate, court, maintain
|
||||||
|
abase bring low, depress, dishonor, lower, cast down, discredit, humble, reduce, debase, disgrace, humiliate, sink, degrade advance, elevate, honor, raise, aggrandize, exalt, promote, uplift, dignify
|
||||||
|
abash bewilder, daunt, embarrass, mortify, chagrin, discompose, humble, overawe, confound, disconcert, humiliate, shame, confuse, dishearten animate, cheer, encourage, rally, buoy, embolden, inspirit, uphold
|
||||||
|
abate decline, ebb, mitigate, reduce, decrease, lessen, moderate, subside, diminish, lower aggravate, enhance, foment, rage, amplify, enlarge, increase, raise, continue, extend, magnify, revive, develop
|
||||||
|
abbreviation abridgment, contraction
|
||||||
|
abet advocate, countenance, incite, sanction, aid, embolden, instigate, support, assist, encourage, promote, uphold baffle, deter, dissuade, hinder, confound, disapprove, expose, impede, counteract, disconcert, frustrate, obstruct, denounce, discourage
|
||||||
|
abhor abominate, dislike, loathe, scorn, despise, hate, nauseate, shun, detest admire, crave, esteem, love, approve, desire, like, relish, covet, enjoy
|
||||||
|
abide anticipate, dwell, remain, stop, await, endure, reside, tarry, bear, expect, rest, tolerate, bide, inhabit, sojourn, wait, confront, live, stay, watch, continue, lodge abandon, forfeit, migrate, reject, avoid, forfend, move, resist, depart, journey, proceed, shun
|
||||||
|
abolish abate, eradicate, prohibit, stamp out, abrogate, exterminate, remove, subvert, annihilate, extirpate, repeal, supplant, annul, nullify, reverse, suppress, destroy, obliterate, revoke, terminate, end, overthrow, set aside authorize, establish, reinstate, revive, cherish, institute, renew, set up, confirm, introduce, repair, support, continue, legalize, restore, sustain, enact, promote
|
||||||
|
abomination abhorrence, curse, hatred, plague, abuse, detestation, horror, shame, annoyance, disgust, iniquity, villainy, aversion, evil, nuisance, wickedness, crime, execration, offense affection, blessing, enjoyment, joy, appreciation, delight, esteem, satisfaction, approval, desire, gratification, treat, benefit
|
||||||
|
abridgment abbreviation, compend, epitome, summary, abstract, compendium, outline, synopsis, analysis, digest
|
||||||
|
absolute arbitrary, compulsory, haughty, peremptory, arrogant, controlling, imperative, positive, authoritative, despotic, imperious, supreme, autocratic, dictatorial, irresponsible, tyrannical, coercive, dogmatic, lordly, unconditional, commanding, domineering, overbearing, unequivocal, compulsive, exacting accountable, constitutional, gentle, lowly, responsible, complaisant, contingent, humble, meek, submissive, compliant, docile, lenient, mild, yielding, conditional, ductile, limited
|
||||||
|
absolve acquit, exculpate, forgive, pardon, clear, exempt, free, release, discharge, exonerate, liberate, set free accuse, charge, condemn, impeach, obligate, bind, compel, convict, inculpate, oblige
|
||||||
|
absorb consume, engross, suck up, take in, drink in, exhaust, swallow, take up, drink up, imbibe, swallow up cast out, dissipate, emit, put forth, shoot forth, disgorge, distract, exude, radiate, throw off, disperse, eject, give up, send out, vomit
|
||||||
|
abstinence abstemiousness, frugality, self-denial, sobriety, continence, moderation, self-restraint, temperance, fasting, self-control drunkenness, greed, reveling, sensuality, excess, intemperance, revelry, wantonness, gluttony, intoxication, self-indulgence
|
||||||
|
abstract appropriate, distract, purloin, steal, detach, divert, remove, take away, discriminate, eliminate, separate, withdraw, distinguish add, complete, fill up, restore, unite, combine, conjoin, increase, strengthen
|
||||||
|
abstracted absent, heedless, listless, preoccupied, absent-minded, inattentive, negligent, thoughtless, absorbed, indifferent, oblivious alert, on hand, ready, wide-awake, attentive, prompt, thoughtful
|
||||||
|
absurd anomalous, ill-considered, ludicrous, ridiculous, chimerical, ill-judged, mistaken, senseless, erroneous, inconclusive, monstrous, stupid, false, incorrect, nonsensical, unreasonable, foolish, infatuated, paradoxical, wild, ill-advised, irrational, preposterous certain, incontrovertible, rational, substantial, consistent, indisputable, reasonable, true, demonstrable, indubitable, sagacious, undeniable, demonstrated, infallible, sensible, unquestionable, established, logical, sound, wise, incontestable
|
||||||
|
abuse aggrieve, impose on or, oppress, ruin, damage, upon, persecute, slander, defame, injure, pervert, victimize, defile, malign, prostitute, vilify, disparage, maltreat, rail at, violate, harm, misemploy, ravish, vituperate, ill-treat, misuse, reproach, wrong, ill-use, molest, revile applaud, conserve, favor, protect, sustain, benefit, consider, laud, regard, tend, care for, eulogize, panegyrize, respect, uphold, cherish, extol, praise, shield, vindicate
|
||||||
|
accessory abetter or abettor, associate, companion, henchman, accomplice, attendant, confederate, participator, ally, coadjutor, follower, partner, assistant, colleague, helper, retainer adversary, chief, foe, leader, principal, antagonist, commander, hinderer, opponent, rival, betrayer, enemy, instigator, opposer
|
||||||
|
accident adventure, contingency, happening, misfortune, calamity, disaster, hazard, mishap, casualty, fortuity, incident, possibility, chance, hap, misadventure appointment, decree, intention, ordainment, preparation, calculation, fate, law, ordinance, provision, certainty, foreordination, necessity, plan, purpose
|
||||||
|
acquaintance association, experience, fellowship, intimacy, companionship, familiarity, friendship, knowledge ignorance, ignoring, inexperience, unfamiliarity
|
||||||
|
acrimony acerbity, harshness, severity, tartness, asperity, malignity, sharpness, unkindness, bitterness, moroseness, sourness, virulence, causticity amiability, gentleness, kindness, smoothness, courtesy, good nature, mildness, sweetness
|
||||||
|
act accomplishment, execution, movement, achievement, exercise, operation, action, exertion, performance, consummation, exploit, proceeding, deed, feat, transaction, doing, motion, work, effect cessation, immobility, inertia, quiet, suffering, deliberation, inaction, passion[A], repose, suspension, endurance, inactivity, quiescence, rest
|
||||||
|
active agile, energetic, officious, sprightly, alert, expeditious, prompt, spry, brisk, industrious, quick, supple, bustling, lively, ready, vigorous, busy, mobile, restless, wide awake, diligent, nimble dull, inactive, lazy, slow, heavy, indolent, quiescent, sluggish, idle, inert, quiet, stupid
|
||||||
|
acumen acuteness, insight, perspicacity, sharpness, cleverness, keenness, sagacity, shrewdness, discernment, penetration bluntness, dulness, obtuseness, stupidity
|
||||||
|
add adjoin, annex, augment, extend, make up, affix, append, cast up, increase, subjoin, amplify, attach, enlarge, join on, sum up abstract, diminish, lessen, remove, withdraw, deduct, dissever, reduce, subtract
|
||||||
|
addicted abandoned, devoted, given over, inclined, accustomed, disposed, given up, prone, attached, given, habituated, wedded averse, disinclined, indisposed, unaccustomed
|
||||||
|
address cost, approach, hail, speak to, apostrophize, court, salute, woo, appeal, greet avoid, elude, overlook, pass by, cut, ignore, pass, shun
|
||||||
|
address adroitness, discretion, manners, readiness, courtesy, ingenuity, politeness, tact, dexterity awkwardness, clumsiness, ill-breeding, stupidity, boorishness, fatuity, ill manners, unmannerliness, clownishness, folly, rudeness, unwisdom
|
||||||
|
adequate able, competent, fitted, satisfactory, adapted, equal, fitting, sufficient, capable, fit, qualified, suitable, commensurate disqualified, inferior, unequal, unsatisfactory, useless, inadequate, insufficient, unfit, unsuitable, worthless, incompetent, poor, unqualified
|
||||||
|
adherent aid, ally, disciple, partisan, supporter, aider, backer, follower adversary, betrayer, enemy, opponent, traitor, antagonist, deserter, hater, renegade
|
||||||
|
adhesive cohesive, gummy, sticky, viscous, glutinous, sticking, viscid free, inadhesive, loose, separable
|
||||||
|
adjacent abutting, bordering, contiguous, neighboring, adjoining, close, coterminous, next, attached, conterminous, near, nigh, beside detached, disconnected, disjoined, distant, remote, separate
|
||||||
|
admire adore, delight in, extol, respect, venerate, applaud, enjoy, honor, revere, wonder, approve, esteem, love abhor, contemn, detest, execrate, ridicule, abominate, despise, dislike, hate, scorn
|
||||||
|
adorn beautify, decorate, garnish, illustrate, bedeck, embellish, gild, ornament, deck deface, deform, disfigure, mar, spoil
|
||||||
|
affront aggravate, exasperate, offend, vex, annoy, insult, provoke, wound, displease, irritate, tease conciliate, content, gratify, honor, please
|
||||||
|
agent actor, factor, means, operator, promoter, doer, instrument, mover, performer chief, inventor, originator, principal
|
||||||
|
agree accede, admit, coincide, concur, accept, approve, combine, consent, accord, assent, comply, harmonize, acquiesce contend, demur, disagree, oppose, contradict, deny, dispute, protest, decline, differ, dissent, refuse
|
||||||
|
agriculture cultivation, gardening, kitchen-gardening, culture, horticulture, market-gardening, farming, husbandry, tillage, floriculture
|
||||||
|
aim aspiration, endeavor, intention, tendency, design, goal, mark, determination, inclination, object, end, intent, purpose aimlessness, heedlessness, negligence, purposelessness, avoidance, neglect, oversight, thoughtlessness, carelessness
|
||||||
|
air appearance, demeanor, manner, sort, bearing, expression, mien, style, behavior, fashion, port, way, carriage, look
|
||||||
|
airy aerial, ethereal, frolicsome, joyous, lively, animated, fairylike, gay, light, sprightly clumsy, heavy, ponderous, sluggish, wooden, dull, inert, slow, stony
|
||||||
|
alarm affright, disquietude, fright, solicitude, apprehension, dread, misgiving, terror, consternation, fear, panic, timidity, dismay assurance, calmness, confidence, repose, security
|
||||||
|
alert active, lively, prepared, vigilant, brisk, nimble, prompt, watchful, hustling, on the watch, ready, wide-awake drowsy, dull, heavy, inactive, slow, sluggish, stupid
|
||||||
|
alien conflicting, distant, inappropriate, strange, contradictory, foreign, irrelevant, unconnected, contrary, hostile, opposed, unlike, contrasted, impertinent, remote akin, apropos, germane, proper, appropriate, essential, pertinent, relevant
|
||||||
|
alien foreigner, stranger citizen, fellow-countryman, native-born inhabitant, countryman, native, naturalized person
|
||||||
|
alike akin, equivalent, kindred, same, analogous, homogeneous, like, similar, equal, identical, resembling, uniform different, dissimilar, distinct, heterogeneous, unlike
|
||||||
|
alive active, breathing, live, quick, alert, brisk, lively, subsisting, animate, existent, living, vivacious, animated, existing dead, defunct, dull, lifeless, deceased, dispirited, inanimate, spiritless
|
||||||
|
allay alleviate, compose, quiet, still, appease, mollify, soothe, tranquilize, calm, pacify agitate, excite, kindle, rouse, stir up, arouse, fan, provoke, stir
|
||||||
|
allege adduce, asseverate, claim, maintain, produce, advance, assign, declare, offer, say, affirm, aver, introduce, plead, state, assert, cite
|
||||||
|
allegiance devotion, fealty, loyalty, obedience, subjection, faithfulness, homage disaffection, disloyalty, rebellion, sedition, treason
|
||||||
|
allegory fable, fiction, illustration, metaphor, parable, simile chronicle, fact, history, narrative, record
|
||||||
|
alleviate abate, lighten, reduce, remove, assuage, mitigate, relieve, soften, lessen, moderate aggravate, embitter, heighten, intensify, make worse, augment, enhance, increase, magnify
|
||||||
|
alliance coalition, confederation, fusion, partnership, compact, federation, league, union, confederacy antagonism, disunion, enmity, schism, separation, discord, divorce, hostility, secession, war
|
||||||
|
allot appoint, destine, give, portion out, apportion, distribute, grant, select, assign, divide, mete out, set apart, award appropriate, deny, resume, seize, confiscate, refuse, retain, withhold
|
||||||
|
allow admit, consent to, let, sanction, tolerate, concede, grant, permit, suffer, yield deny, disapprove, protest, reject, withstand, disallow, forbid, refuse, resist
|
||||||
|
alloy admixture, adulteration, debasement, deterioration
|
||||||
|
allude advert, indicate, intimate, point, signify, hint, insinuate, mention, refer, suggest, imply
|
||||||
|
allure attract, captivate, decoy, entice, lure, tempt, cajole, coax, draw, inveigle, seduce, win chill, damp, deter, dissuade, drive away, repel, warn
|
||||||
|
also as well, in addition, likewise, too, as well as, in like manner, similarly, withal, besides but, nevertheless, on the contrary, yet, in spite of, notwithstanding, on the other hand
|
||||||
|
alternative choice, election, option, pick, preference, resource compulsion, necessity
|
||||||
|
amass accumulate, collect, heap up, hoard up, store up, aggregate, gather, hoard, pile up disperse, divide, portion, spend, waste, dissipate, parcel, scatter, squander
|
||||||
|
amateur connoisseur, critic, dilettante, novice, tyro
|
||||||
|
amazement admiration, awe, confusion, surprise, astonishment, bewilderment, perplexity, wonder anticipation, composure, expectation, preparation, steadiness, calmness, coolness, indifference, self-possession, stoicism
|
||||||
|
ambition aspiration, competition, emulation, opposition, rivalry carelessness, contentment, humility, indifference, satisfaction
|
||||||
|
amend advance, correct, meliorate, rectify, ameliorate, emend, mend, reform, better, improve, mitigate, repair, cleanse, make better, purify aggravate, debase, harm, mar, tarnish, blemish, depress, impair, spoil, vitiate, corrupt, deteriorate, injure
|
||||||
|
amiable agreeable, engaging, lovable, pleasing, attractive, gentle, lovely, sweet, benignant, good-natured, loving, winning, harming, kind, pleasant, winsome acrimonious, crusty, hateful, ill-tempered, surly, churlish, disagreeable, ill-conditioned, morose, unamiable, crabbed, dogged, ill-humored, sour, unlovely, cruel, gruff, ill-natured, sullen
|
||||||
|
amid amidst, amongst, betwixt, mingled with, among, between, in the midst of, surrounded by afar from, away from, beyond, far from, outside, without
|
||||||
|
amplify augment, dilate, expand, extend, unfold, develop, enlarge, expatiate, increase, widen abbreviate, amputate, condense, cut down, reduce, summarize, abridge, "boil down", curtail, epitomize, retrench, sum up
|
||||||
|
analogy affinity, likeness, relation, similarity, coincidence, parity, resemblance, simile, comparison, proportion, semblance, similitude disagreement, disproportion, dissimilarity, incongruity, unlikeness
|
||||||
|
anger animosity, fury, offense, rage, choler, impatience, passion, resentment, displeasure, indignation, peevishness, temper, exasperation, ire, pettishness, vexation, fretfulness, irritation, petulance, wrath amiability, gentleness, long-suffering, patience, peacefulness, charity, leniency, love, peace, self-control, forbearance, lenity, mildness, peaceableness, self-restraint
|
||||||
|
animal beast, fauna, living organism, sentient being, brute, living creature angel, man, mind, soul, substance (material), inanimate object, matter, mineral, spirit, vegetable
|
||||||
|
announce advertise, give notice (of), proclaim, reveal, circulate, give out, promulgate, say, communicate, herald, propound, spread abroad, declare, make known, publish, state, enunciate, notify, report, tell bury, cover (up), hush, keep secret, suppress, conceal, hide, keep back, secrete, withhold
|
||||||
|
answer rejoinder, repartee, reply, response, retort
|
||||||
|
anticipate apprehend, forecast, hope, expect, foretaste, look forward to despair of, distrust, doubt, dread, fear, recall, recollect, remember
|
||||||
|
anticipation antepast, expectation, foresight, hope, apprehension, foreboding, foretaste, presentiment, expectancy, forecast, forethought, prevision astonishment, despair, dread, fear, surprise, consummation, doubt, enjoyment, realization, wonder
|
||||||
|
antipathy abhorrence, disgust, hatred, repugnance, antagonism, dislike, hostility, repulsion, aversion, distaste, opposition, uncongeniality, detestation affinity, attraction, fellow-feeling, kindliness, sympathy, agreement, congeniality, harmony, regard
|
||||||
|
antique ancient, old-fashioned, quaint, superannuated, antiquated fashionable, fresh, modern, modish, new, recent, stylish
|
||||||
|
anxiety anguish, disquiet, foreboding, perplexity, apprehension, disturbance, fretfulness, solicitude, care, dread, fretting, trouble, concern, fear, misgiving, worry apathy, calmness, confidence, light-heartedness, satisfaction, assurance, carelessness, ease, nonchalance, tranquillity
|
||||||
|
apathy calmness, indifference, quietness, stoicism, composure, insensibility, quietude, tranquillity, immobility, lethargy, sluggishness, unconcern, impassibility, phlegm, stillness, unfeelingness agitation, disturbance, feeling, sensibility, sympathy, alarm, eagerness, frenzy, sensitiveness, turbulence, anxiety, emotion, fury, storm, vehemence, care, excitement, passion, susceptibility, violence, distress
|
||||||
|
apiece distributively, each, individually, separately, severally accumulatively, confusedly, indiscriminately, together, unitedly, collectively, en masse, synthetically
|
||||||
|
apology acknowledgment, defense, excuse, plea, confession, exculpation, justification, vindication accusation, charge, condemnation, injury, offense, censure, complaint, imputation, insult, wrong
|
||||||
|
apparent likely, presumable, probable, seeming doubtful, dubious, improbable, unimaginable, unlikely
|
||||||
|
appear have the appearance or semblance, look, seem be, be certain real or true, be the fact, exist
|
||||||
|
appendage accessory, addition, appurtenance, concomitant, accompaniment, adjunct, attachment, extension, addendum, appendix, auxiliary, supplement main body, original, total, whole
|
||||||
|
appetite appetency, impulse, lust, propensity, craving, inclination, passion, relish, desire, liking, proclivity, thirst, disposition, longing, proneness, zest antipathy, detestation, dislike, distaste, indifference, repugnance, aversion, disgust, disrelish, hatred, loathing, repulsion
|
||||||
|
apportion allot, appropriate, deal, distribute, grant, appoint, assign, dispense, divide, share cling to, consolidate, gather together, receive, collect, divide arbitrarily, keep together, retain
|
||||||
|
approximation approach, likeness, neighborhood, resemblance, contiguity, nearness, propinquity, similarity difference, distance, error, remoteness, unlikeness, variation
|
||||||
|
arms accouterments, armor, harness, mail, weapons
|
||||||
|
army armament, forces, military, soldiers, array, host, multitude, soldiery, force, legions, phalanx, troops
|
||||||
|
arraign accuse, charge, impeach, prosecute, censure, cite, indict, summon acquit, discharge, exonerate, overlook, release, condone, excuse, forgive, pardon, set free
|
||||||
|
array army, collection, line of battle, parade, arrangement, disposition, order, show, battle array, exhibition, order of battle, sight
|
||||||
|
arrest apprehend, detain, restrain, stop, capture, hold, secure, take into custody, catch, make prisoner, seize, take prisoner discharge, dismiss, free, liberate, release, set free
|
||||||
|
artifice art, craft, finesse, invention, stratagem, blind, cunning, fraud, machination, subterfuge, cheat, device, guile, maneuver, trick, contrivance, dodge, imposture, ruse, wile artlessness, fairness, guilelessness, ingenuousness, openness, sincerity, candor, frankness, honesty, innocence, simplicity, truth
|
||||||
|
artist artificer, artisan, mechanic, operative, workman
|
||||||
|
ask beg, crave, entreat, petition, request, solicit, beseech, demand, implore, pray, require, supplicate claim, command, deny, enforce, exact, extort, insist, refuse, reject
|
||||||
|
associate accomplice, coadjutor, comrade, fellow, mate, ally, colleague, confederate, friend, partner, chum, companion, consort, helpmate, peer antagonist, enemy, foe, hinderer, opponent, opposer, rival, stranger
|
||||||
|
association alliance, confederacy, familiarity, lodge, club, confederation, federation, participation, community, conjunction, fellowship, partnership, companionship, connection, fraternity, society, company, corporation, friendship, union disintegration, independence, isolation, separation, solitude
|
||||||
|
assume accept, arrogate, postulate, put on, affect, claim, presume, take, appropriate, feign, pretend, usurp
|
||||||
|
assurance arrogance, boldness, impudence, self-confidence, assertion, confidence, presumption, self-reliance, assumption, effrontery, self-assertion, trust bashfulness, consternation, distrust, hesitancy, shyness, confusion, dismay, doubt, misgiving, timidity
|
||||||
|
astute acute, discerning, penetrating, sharp, clear-sighted, discriminating, penetrative, shrewd, crafty, keen, perspicacious, subtile, cunning, knowing, sagacious, subtle blind, idiotic, shallow, stolid, undiscerning, dull, imbecile, short-sighted, stupid, unintelligent
|
||||||
|
attachment adherence, devotion, friendship, regard, adhesion, esteem, inclination, tenderness, affection, estimation, love, union alienation, aversion, distance, estrangement, repugnance, animosity, coolness, divorce, indifference, separation, antipathy, dislike, enmity, opposition, severance
|
||||||
|
attack assail, beset, combat, invade, assault, besiege, encounter, set upon, beleaguer, charge, fall upon, storm aid, cover, protect, shelter, support, uphold, befriend, defend, resist, shield, sustain, withstand
|
||||||
|
attack aggression, incursion, invasion, onslaught, assault, infringement, onset, trespass, encroachment, intrusion defense, repulsion, resistance, retreat, submission, surrender
|
||||||
|
attain accomplish, arrive at, gain, master, reach, achieve, compass, get, obtain, secure, acquire, earn, grasp, procure, win abandon, fail, forfeit, give up, let go, lose, miss
|
||||||
|
attitude pose, position, posture
|
||||||
|
attribute ascribe, associate, connect, impute, refer, assign, charge deny, disconnect, dissociate, separate, sever, sunder
|
||||||
|
attribute property, quality being, essence, nature, substance
|
||||||
|
augur betoken, divine, foretell, predict, prognosticate, bode, forebode, portend, presage, prophesy assure, demonstrate, establish, make sure, settle, calculate, determine, insure, prove, warrant
|
||||||
|
authentic accepted, certain, original, sure, accredited, current, real, true, authoritative, genuine, received, trustworthy, authorized, legitimate, reliable, veritable apocryphal, counterfeit, exploded, false, spurious, baseless, disputed, fabulous, fictitious, unauthorized
|
||||||
|
auxiliary accessory, ally, coadjutor, helper, promoter, aid, assistant, confederate, mercenary, subordinate antagonist, hinderer, opponent, opposer
|
||||||
|
avaricious close, greedy, niggardly, penurious, sordid, covetous, miserly, parsimonious, rapacious, stingy bountiful, free, generous, liberal, munificent, prodigal, wasteful
|
||||||
|
avenge punish, retaliate, revenge, vindicate, visit
|
||||||
|
avow knowledge, aver, confess, own, profess, testify, admit, avouch, declare, proclaim, protest, witness contradict, deny, disavow, disclaim, disown, ignore, repudiate
|
||||||
|
awful alarming, direful, frightful, majestic, solemn, appalling, dread, grand, noble, stately, august, dreadful, horrible, portentous, terrible, dire, fearful, imposing, shocking, terrific base, contemptible, inferior, paltry, beggarly, despicable, lowly, undignified, commonplace, humble, mean, vulgar
|
||||||
|
awkward boorish, clumsy, rough, unhandy, bungling, gawky, uncouth, unskilful, clownish, maladroit, ungainly adroit, clever, dexterous, handy, skilful
|
||||||
|
axiom absurdity, contradiction, demonstration, nonsense, paradox, sophism
|
||||||
|
babble blab, cackle, gabble, murmur, prattle, blurt, chat, gossip, palaver, tattle, blurt out, chatter, jabber, prate, twaddle
|
||||||
|
banish ban, dismiss, evict, expatriate, ostracize, discharge, drive out, exile, expel, oust, dislodge, eject
|
||||||
|
bank beach, bound, brink, edge, margin, shore, border, brim, coast, marge, rim, strand
|
||||||
|
banter badinage, derision, jeering, raillery, sarcasm, chaff, irony, mockery, ridicule, satire
|
||||||
|
barbarous atrocious, brutal, merciless, uncivilized, barbarian, cruel, rude, uncouth, barbaric, inhuman, savage, untamed civilized, cultured, elegant, humane, polite, tender, courtly, delicate, graceful, nice, refined, urbane
|
||||||
|
barrier bar, bulwark, obstruction, rampart, barricade, hindrance, parapet, restraint, breastwork, obstacle, prohibition, restriction admittance, opening, road, transit, entrance, passage, thoroughfare, way
|
||||||
|
battle action, combat, encounter, passage of arms, affair, conflict, engagement, skirmish, bout, contest, fight, strife armistice, concord, peace, suspension of hostilities, truce
|
||||||
|
beat bastinado, chastise, overcome, spank, thrash, batter, conquer, pommel, strike, vanquish, belabor, cudgel, pound, surpass, whip, bruise, defeat, scourge, switch, worst, castigate, flog, smite fail, fall, get the worst of, go down, go under, surrender
|
||||||
|
beautiful attractive, charming, exquisite, handsome, beauteous, comely, fair, lovely, bewitching, delightful, fine, picturesque, bonny, elegant, graceful, pretty awkward, frightful, grotesque, repulsive, uncouth, clumsy, ghastly, hideous, shocking, ungainly, deformed, grim, horrid, ugly, unlovely, disgusting, grisly, odious, unattractive, unpleasant
|
||||||
|
because as, for, inasmuch as, since altho, however, nevertheless, notwithstanding, yet
|
||||||
|
becoming befitting, congruous, fit, meet, seemly, beseeming, decent, fitting, neat, suitable, comely, decorous, graceful, proper, worthy awkward, ill-fitting, indecent, unbecoming, unseemly, ill-becoming, improper, indecorous, unfit, unsuitable
|
||||||
|
beginning arising, inauguration, origin, source, commencement, inception, outset, spring, fount, initiation, rise, start, fountain, opening
|
||||||
|
behavior action, breeding, conduct, deportment, manner, bearing, carriage, demeanor, life, manners
|
||||||
|
bend bias, curve, diverge, mold, submit, twist, bow, deflect, incline, persuade, turn, warp, crook, deviate, influence, stoop, twine, yield
|
||||||
|
benevolence almsgiving, charity, kind-heartedness, munificence, beneficence, generosity, kindliness, philanthropy, benignity, good-will, kindness, sympathy, bounty, humanity, liberality, unselfishness barbarity, greediness, ill-will, malignity, self-seeking, brutality, harshness, inhumanity, niggardliness, stinginess, churlishness, illiberality, malevolence, selfishness, unkindness
|
||||||
|
bind compel, fetter, oblige, restrict, shackle, engage, fix, restrain, secure, tie, fasten free, loose, set free, unbind, unfasten, unloose, untie
|
||||||
|
bitter acerb, acidulous, caustic, pungent, stinging, acetous, acrid, cutting, savage, tart, acid, acrimonious, harsh, sharp, vinegarish, acidulated, biting, irate, sour, virulent dulcet, honeyed, luscious, nectared, saccharine, sweet
|
||||||
|
bleach blanch, make white, whiten, whitewash blacken, color, darken, dye, soil, stain
|
||||||
|
blemish blot, defacement, disgrace, injury, spot, blur, defect, dishonor, reproach, stain, brand, deformity, fault, smirch, stigma, crack, dent, flaw, soil, taint, daub, disfigurement, imperfection, speck, tarnish
|
||||||
|
blow box, concussion, disaster, misfortune, stripe, buffet, cuff, knock, rap, stroke, calamity, cut, lash, shock, thump
|
||||||
|
bluff abrupt, brusk, impolite, rough, blunt, coarse, inconsiderate, rude, blustering, discourteous, open, uncivil, bold, frank, plain-spoken, unmannerly bland, courteous, genial, polished, polite, refined, reserved, urbane
|
||||||
|
body ashes, clay, dust, frame, system, carcass, corpse, form, remains, trunk intellect, intelligence, mind, soul, spirit
|
||||||
|
both twain, two each, either, every, neither, none, no one, not any
|
||||||
|
boundary barrier, confines, limit, margin, border, edge, line, term, bound, enclosure, marches, termination, bourn, frontier, marge, verge, bourne, landmark center, citadel, estate, inside, interior, land, region, territory
|
||||||
|
brave adventurous, courageous, fearless, undaunted, bold, daring, gallant, undismayed, chivalric, dauntless, heroic, valiant, chivalrous, doughty, intrepid, venturesome afraid, cringing, fearful, pusillanimous, timid, cowardly, faint-hearted, frightened, shrinking, timorous
|
||||||
|
break bankrupt, crack, destroy, rive, shatter, split, burst, crush, fracture, rupture, shiver, sunder, cashier, demolish, rend, sever, smash, transgress attach, bind, fasten, join, mend, secure, solder, unite, weld
|
||||||
|
brutish animal, brutal, ignorant, sensual, swinish, base, brute, imbruted, sottish, unintellectual, beastly, carnal, insensible, stolid, unspiritual, bestial, coarse, lascivious, stupid, vile elevated, exalted, great, intellectual, noble, enlightened, grand, humane, intelligent, refined
|
||||||
|
burn blaze, char, flame, incinerate, set fire to, brand, consume, flash, kindle, set on fire, cauterize, cremate, ignite, scorch, singe cool, extinguish, put out, smother, stifle, subdue
|
||||||
|
business affair, commerce, handicraft, trading, art, concern, job, traffic, avocation, craft, occupation, transaction, barter, duty, profession, vocation, calling, employment, trade, work
|
||||||
|
but and, however, notwithstanding, that, barely, just, only, tho, besides, merely, provided, unless, except, moreover, save, yet, further, nevertheless, still
|
||||||
|
by by dint of, by means of, through, with
|
||||||
|
cabal combination, confederacy, crew, gang, conclave, conspiracy, faction, junto
|
||||||
|
calculate account, consider, enumerate, rate, cast, count, estimate, reckon, compute, deem, number, sum up
|
||||||
|
call bawl, cry (out), roar, shriek, bellow, ejaculate, scream, vociferate, clamor, exclaim, shout, yell be silent, be still, hark, hearken, hush, list, listen
|
||||||
|
calm collected, imperturbable, sedate, still, composed, peaceful, self-possessed, tranquil, cool, placid, serene, undisturbed, dispassionate, quiet, smooth, unruffled agitated, excited, frenzied, passionate, ruffled, violent, boisterous, fierce, furious, raging, stormy, wild, disturbed, frantic, heated, roused, turbulent, wrathful
|
||||||
|
cancel abolish, discharge, nullify, rescind, abrogate, efface, obliterate, revoke, annul, erase, quash, rub off or out, blot out, expunge, remove, scratch out, cross off or out, make void, repeal, vacate approve, enact, establish, perpetuate, reenact, uphold, confirm, enforce, maintain, record, sustain, write
|
||||||
|
candid aboveboard, honest, open, truthful, artless, impartial, simple, unbiased, fair, ingenuous, sincere, unprejudiced, frank, innocent, straightforward, unreserved, guileless, naive, transparent, unsophisticated adroit, cunning, diplomatic, intriguing, sharp, subtle, artful, deceitful, foxy, knowing, shrewd, tricky, crafty, designing, insincere, maneuvering, sly, wily
|
||||||
|
caparison accouterments, harness, housings, trappings
|
||||||
|
capital chief city, metropolis, seat of government
|
||||||
|
care anxiety, concern, oversight, trouble, attention, direction, perplexity, vigilance, caution, forethought, precaution, wariness, charge, heed, prudence, watchfulness, circumspection, management, solicitude, worry carelessness, heedlessness, indifference, negligence, oversight, remissness, disregard, inattention, neglect, omission, recklessness, slight
|
||||||
|
career charge, flight, passage, race, course, line of achievement, public life, rush
|
||||||
|
caress coddle, embrace, fondle, pamper, court, flatter, kiss, pet
|
||||||
|
caricature burlesque, extravaganza, mimicry, take-off, exaggeration, imitation, parody, travesty
|
||||||
|
carry bear, convey, move, sustain, transmit, bring, lift, remove, take, transport drop, fall under, give up, let go, shake off, throw down, throw off
|
||||||
|
catastrophe calamity, denouement, mischance, mishap, cataclysm, disaster, misfortune, sequel benefit, boon, favor, pleasure, prosperity, blessing, comfort, help, privilege, success
|
||||||
|
catch apprehend, comprehend, grasp, overtake, snatch, capture, discover, grip, secure, take, clasp, ensnare, gripe, seize, take hold of, clutch, entrap, lay hold of (on upon) fail of, give up, lose, release, throw aside, fall short of, let go, miss, restore, throw away
|
||||||
|
cause actor, causality, designer, occasion, precedent, agent, causation, former, origin, reason, antecedent, condition, fountain, originator, source, author, creator, motive, power, spring consequence, development, end, fruit, outcome, product, creation, effect, event, issue, outgrowth, result
|
||||||
|
cease abstain, desist, give over, quit, bring to an end, discontinue, intermit, refrain, come to an end, end, leave off, stop, conclude, finish, pause, terminate begin, enter upon, initiate, originate, set going, set on foot, commence, inaugurate, institute, set about, set in operation, start
|
||||||
|
celebrate commemorate, keep, observe, solemnize contemn, dishonor, forget, neglect, profane, despise, disregard, ignore, overlook, violate
|
||||||
|
center middle, midst bound, boundary, circumference, perimeter, rim
|
||||||
|
chagrin confusion, discomposure, humiliation, shame, disappointment, dismay, mortification, vexation delight, exultation, glory, rejoicing, triumph
|
||||||
|
change alter, exchange, shift, transmute, commute, metamorphose, substitute, turn, convert, modify, transfigure, vary, diversify, qualify, transform, veer abide, continue, hold, persist, retain, bide, endure, keep, remain, stay
|
||||||
|
change alteration, mutation, renewing, transmutation, conversion, novelty, revolution, variation, diversity, regeneration, transformation, variety, innovation, renewal, transition, vicissitude constancy, fixedness, invariability, steadiness, continuance, fixity, permanence, unchangeableness, firmness, identity, persistence, uniformity
|
||||||
|
character constitution, genius, personality, reputation, temper, disposition, nature, record, spirit, temperament
|
||||||
|
characteristic attribute, feature, peculiarity, sign, trace, character, indication, property, singularity, trait, distinction, mark, quality
|
||||||
|
charming bewitching, delightful, enrapturing, fascinating, captivating, enchanting, entrancing, winning
|
||||||
|
chasten afflict, chastise, discipline, punish, refine, subdue, castigate, correct, humble, purify, soften, try
|
||||||
|
cherish cheer, encourage, harbor, nurse, shelter, cling to, entertain, hold dear, nurture, treasure, comfort, foster, nourish, protect, value
|
||||||
|
choose cull, elect, pick, pick out, prefer, select cast away, decline, dismiss, refuse, repudiate, cast out, disclaim, leave, reject, throw aside
|
||||||
|
circumlocution diffuseness, prolixity, surplusage, verbiage, periphrasis, redundance, tautology, verbosity, pleonasm, redundancy, tediousness, wordiness brevity, compression, condensation, plainness, succinctness, compactness, conciseness, directness, shortness, terseness
|
||||||
|
circumstance accompaniment, fact, item, point, concomitant, feature, occurrence, position, detail, incident, particular, situation, event
|
||||||
|
class association, circle, clique, company, grade, rank, caste, clan, club, coterie, order, set
|
||||||
|
cleanse brush, dust, purify, scour, sponge, wash, clean, lave, rinse, scrub, sweep, wipe, disinfect, mop befoul, besmirch, contaminate, debase, deprave, soil, stain, taint, besmear, bespatter, corrupt, defile, pollute, spoil, sully, vitiate
|
||||||
|
clear apparent, intelligible, pellucid, transparent, diaphanous, limpid, perspicuous, unadorned, distinct, lucid, plain, unambiguous, evident, manifest, straightforward, unequivocal, explicit, obvious, translucent, unmistakable ambiguous, dim, foggy, mysterious, opaque, unintelligible, cloudy, dubious, indistinct, obscure, turbid, vague
|
||||||
|
clever able, capable, happy, keen, sharp, adroit, dexterous, ingenious, knowing, skilful, apt, expert, intellectual, quick, smart, bright, gifted, intelligent, quick-witted, talented awkward, clumsy, foolish, ignorant, slow, thick-headed, bungling, dull, idiotic, senseless, stupid, witless
|
||||||
|
collision clash, concussion, contact, impact, opposition, clashing, conflict, encounter, meeting, shock agreement, coincidence, concord, conformity, unison, amity, concert, concurrence, harmony, unity
|
||||||
|
comfortable agreeable, cheery, genial, snug, at ease, commodious, pleasant, well-off, at rest, contented, satisfactory, well-provided, cheerful, convenient, satisfied, well-to-do cheerless, discontented, distressed, forlorn, uncomfortable, disagreeable, dissatisfied, dreary, miserable, wretched
|
||||||
|
commit assign, confide, consign, entrust, relegate, trust
|
||||||
|
company assemblage, concourse, convocation, host, assembly, conference, crowd, meeting, collection, congregation, gathering, multitude, conclave, convention, group, throng dispersion, loneliness, privacy, retirement, seclusion, solitude
|
||||||
|
compel coerce, drive, make, oblige, constrain, force, necessitate
|
||||||
|
complain croak, growl, grunt, remonstrate, find fault, grumble, murmur, repine applaud, approve, commend, eulogize, laud, praise
|
||||||
|
complex abstruse, confused, intricate, mixed, complicated, conglomerate, involved, multiform, composite, entangled, manifold, obscure, compound, heterogeneous, mingled, tangled clear, homogeneous, plain, uncombined, uniform, direct, obvious, simple, uncompounded, unraveled
|
||||||
|
condemn blame, convict, doom, reprove, censure, denounce, reprobate, sentence absolve, applaud, exonerate, pardon, acquit, approve, justify, praise
|
||||||
|
confess accept, allow, concede, grant, acknowledge, avow, disclose, own, admit, certify, endorse, recognize cloak, deny, disown, hide, screen, conceal, disavow, dissemble, mask, secrete, cover, disguise, dissimulate, repudiate, veil
|
||||||
|
confirm assure, fix, sanction, substantiate, corroborate, prove, settle, sustain, establish, ratify, strengthen, uphold abrogate, cancel, overthrow, shatter, upset, annul, destroy, shake, unsettle, weaken
|
||||||
|
congratulate condole with, console
|
||||||
|
conquer beat, humble, overthrow, subject, checkmate, master, prevail over, subjugate, crush, overcome, put down, surmount, defeat, overmaster, reduce, vanquish, discomfit, overmatch, rout, win, down, overpower, subdue, worst capitulate, fail, fly, lose, retire, submit, surrender, cede, fall, forfeit, resign, retreat, succumb, yield
|
||||||
|
conscious advised, assured, certain, cognizant, sensible, apprised, aware, certified, informed, sure cold, dead, deaf, ignorant, insensible, unaware, unconscious
|
||||||
|
consequence consequent, end, issue, outgrowth, sequel, effect, event, outcome, result, upshot
|
||||||
|
console comfort, condole with, encourage, sympathize with annoy, distress, disturb, grieve, hurt, sadden, trouble, wound
|
||||||
|
continual ceaseless, incessant, regular, uninterrupted, constant, invariable, unbroken, unremitting, continuous, perpetual, unceasing, unvarying
|
||||||
|
contract agreement, cartel, engagement, pledge, arrangement, compact, obligation, promise, bargain, covenant, pact, stipulation
|
||||||
|
contrast compare, differentiate, discriminate, oppose
|
||||||
|
conversation chat, communion, converse, intercourse, colloquy, confabulation, dialogue, parley, communication, conference, discourse, talk
|
||||||
|
convert disciple, neophyte, proselyte
|
||||||
|
convey carry, give, remove, shift, transmit, change, move, sell, transfer, transport cling to, hold, keep, possess, preserve, retain
|
||||||
|
convoke assemble, call together, convene, muster, call, collect, gather, summon adjourn, disband, dismiss, dissolve, scatter, break up, discharge, disperse, prorogue, separate
|
||||||
|
criminal abominable, flagitious, immoral, sinful, vile, culpable, guilty, iniquitous, unlawful, wicked, felonious, illegal, nefarious, vicious, wrong innocent, lawful, meritorious, right, just, legal, moral, virtuous
|
||||||
|
daily nightly, nocturnal
|
||||||
|
danger hazard, insecurity, jeopardy, peril, risk defense, immunity, protection, safeguard, safety, security, shelter
|
||||||
|
dark black, dusky, mysterious, sable, somber, dim, gloomy, obscure, shadowy, swart, dismal, murky, opaque, shady, swarthy bright, crystalline, glowing, lucid, shining, brilliant, dazzling, illumined, luminous, transparent, clear, gleaming, light, radiant, white
|
||||||
|
decay corrupt, decompose, molder, putrefy, rot, spoil
|
||||||
|
deception craft, dissimulation, finesse, lie, cunning, double-dealing, fraud, lying, deceit, duplicity, guile, prevarication, deceitfulness, fabrication, hypocrisy, trickery, delusion, falsehood, imposition, untruth candor, frankness, honesty, simplicity, truth, fair dealing, guilelessness, openness, sincerity, veracity
|
||||||
|
defense apology, guard, rampart, shelter, bulwark, justification, resistance, shield, fortress, protection, safeguard, vindication abandonment, betrayal, capitulation, desertion, flight, surrender
|
||||||
|
defile befoul, corrupt, pollute, spoil, sully, tarnish, contaminate, infect, soil, stain, taint, vitiate clean, cleanse, disinfect, hallow, purify, sanctify, wash
|
||||||
|
definition comment, description, exposition, rendering, commentary, explanation, interpretation, translation
|
||||||
|
delegate deputy, legate, proxy, representative, substitute
|
||||||
|
deliberate confer, consult, meditate, reflect, consider, debate, ponder, weigh
|
||||||
|
delicious dainty, delightful, exquisite, luscious, savory acrid, bitter, loathsome, nauseous, repulsive, unpalatable, unsavory
|
||||||
|
delightful acceptable, delicious, pleasant, refreshing, agreeable, grateful, pleasing, satisfying, congenial, gratifying, pleasurable, welcome depressing, distressing, horrible, miserable, painful, woful, disappointing, hateful, melancholy, mournful, saddening, wretched
|
||||||
|
delusion error, fallacy, hallucination, illusion, phantasm actuality, certainty, fact, reality, truth, verity
|
||||||
|
demolish destroy, overthrow, overturn, raze, ruin build, construct, create, make, repair, restore
|
||||||
|
demonstration certainty, consequence, evidence, inference, conclusion, deduction, induction, proof
|
||||||
|
design aim, final cause, object, proposal, device, intent, plan, purpose, end, intention, project, scheme
|
||||||
|
desire appetency, concupiscence, hankering, proclivity, appetite, coveting, inclination, propensity, aspiration, craving, longing, wish
|
||||||
|
despair desperation, despondency, discouragement, hopelessness anticipation, cheer, courage, encouragement, expectation, hopefulness, assurance, confidence, elation, expectancy, hope, trust
|
||||||
|
dexterity adroitness, aptitude, cleverness, expertness, readiness, skill
|
||||||
|
diction expression, phrase, style, vocabulary, language, phraseology, verbiage, wording
|
||||||
|
die cease, decline, expire, perish, decease, depart, fade, wither be born, come into being, flourish, rise again, begin, come to life, grow, rise from the dead, be immortal, exist, live, survive
|
||||||
|
difference contrariety, discrimination, distinction, inequality, contrast, disparity, divergence, unlikeness, disagreement, dissimilarity, diversity, variation, discrepancy, dissimilitude, inconsistency, variety agreement, harmony, likeness, sameness, uniformity, consonance, identity, resemblance, similarity, unity
|
||||||
|
difficult arduous, hard, onerous, toilsome, exhausting, laborious, severe, trying easy, facile, light, pleasant, slight, trifling, trivial
|
||||||
|
direction aim, bearing, course, inclination, tendency, way
|
||||||
|
discern behold, discriminate, observe, recognize, descry, distinguish, perceive, see
|
||||||
|
discover ascertain, detect, disclose, ferret out, find out, descry, discern, expose, find, invent
|
||||||
|
disease affection, disorder, indisposition, sickness, ailment, distemper, infirmity, unhealthiness, complaint, illness, malady, unsoundness health, robustness, soundness, strength, sturdiness, vigor
|
||||||
|
disparage belittle, depreciate, discredit, underestimate, carp at, derogate from, dishonor, underrate, decry, detract from, lower, undervalue
|
||||||
|
displace confuse, derange, disturb, mislay, remove, crowd out, disarrange, jumble, misplace, unsettle adjust, assort, dispose, order, put in order, set in order, array, classify, group, place, put in place, sort
|
||||||
|
do accomplish, carry out, discharge, perform, achieve, carry through, effect, perpetrate, actualize, commit, execute, realize, bring about, complete, finish, transact, bring to pass, consummate, fulfil, work out baffle, defeat, fail, mar, miss, ruin, come short, destroy, frustrate, miscarry, neglect, spoil
|
||||||
|
docile amenable, manageable, pliant, teachable, compliant, obedient, submissive, tractable, gentle, pliable, tame, yielding determined, firm, intractable, opinionated, self-willed, wilful, dogged, inflexible, obstinate, resolute, stubborn, unyielding
|
||||||
|
doctrine article of belief, belief, precept, teaching, article of faith, dogma, principle, tenet
|
||||||
|
dogmatic arrogant, doctrinal, magisterial, positive, authoritative, domineering, opinionated, self-opinionated, dictatorial, imperious, overbearing, systematic
|
||||||
|
doubt distrust, mistrust, surmise, suspect believe, confide in, depend on, depend upon, rely on, rely upon, trust
|
||||||
|
doubt disbelief, incredulity, perplexity, suspense, distrust, indecision, question, suspicion, hesitancy, irresolution, scruple, unbelief, hesitation, misgiving, skepticism, uncertainty assurance, certainty, conviction, determination, resolution, belief, confidence, decision, persuasion, resolve
|
||||||
|
draw allure, drag, haul, induce, lure, tow, attract, entice, incline, lead, pull, tug alienate, estrange, rebuff, reject, repel, repulse
|
||||||
|
dream day-dream, fantasy, reverie, trance, fancy, hallucination, romance, vision certainty, fact, reality, realization, substance, verity
|
||||||
|
dress apparel, clothes, garb, habit, uniform, array, clothing, garments, raiment, vestments, attire, costume, habiliments, robes, vesture bareness, disarray, dishabille, exposure, nakedness, nudity, undress
|
||||||
|
drive compel, propel, repel, resist, thrust, impel, push, repulse, ride, urge on
|
||||||
|
duplicate copy, facsimile, likeness, reproduction, counterpart, imitation, replica, transcript archetype, model, original, pattern, prototype
|
||||||
|
duty accountability, function, office, right, business, obligation, responsibility, righteousness
|
||||||
|
eager animated, desirous, glowing, importunate, longing, anxious, earnest, hot, intense, vehement, ardent, enthusiastic, impatient, intent, yearning, burning, fervent, impetuous, keen, zealous apathetic, cool, indifferent, regardless, unconcerned, calm, dispassionate, negligent, stolid, uninterested, careless, frigid, phlegmatic, stony, unmindful, cold, heedless, purposeless, stupid, unmoved
|
||||||
|
ease easiness, expertness, facility, knack, readiness annoyance, constraint, discomfort, irritation, trouble, vexation, awkwardness, difficulty, disquiet, perplexity, uneasiness, worry
|
||||||
|
education breeding, discipline, learning, study, cultivation, information, nurture, teaching, culture, instruction, reading, training, development, knowledge, schooling, tuition ignorance, illiteracy
|
||||||
|
effrontery assurance, boldness, hardihood, insolence, audacity, brass, impudence, shamelessness bashfulness, diffidence, sensitiveness, shyness, coyness, modesty, shrinking, timidity
|
||||||
|
egotism conceit, self-assertion, self-confidence, self-esteem, egoism, self-conceit, self-consciousness, vanity bashfulness, diffidence, modesty, self-forgetfulness, unobtrusiveness, deference, humility, self-distrust, shyness, unostentatiousness
|
||||||
|
emblem attribute, figure, image, sign, symbol, token, type
|
||||||
|
emigrate immigrate, migrate
|
||||||
|
employ call, engage, engross, hire, make use of, use, use up
|
||||||
|
end break off, close, conclude, expire, quit, terminate, cease, complete, desist, finish, stop, wind up
|
||||||
|
end accomplishment, effect, limit, achievement, expiration, outcome, bound, extent, period, boundary, extremity, point, cessation, finale, purpose, close, finis, result, completion, finish, termination, conclusion, fulfilment, terminus, consequence, goal, tip, consummation, intent, utmost, design, issue, uttermost
|
||||||
|
endeavor attempt, essay, strive, try, undertake abandon, give up, omit, throw away, dismiss, let go, overlook, throw over, drop, neglect, pass by, throw up
|
||||||
|
endeavor attempt, effort, essay, exertion, struggle, trial
|
||||||
|
endure abide, bear, brook, submit to, sustain, afford, bear up under, permit, suffer, tolerate, allow, bear with, put up with, support, undergo break, despair, fail, fall, give out, sink, surrender, break down, droop, faint, falter, give up, succumb, yield
|
||||||
|
enemy adversary, antagonist, competitor, foe, opponent, rival abettor, accessory, accomplice, ally, friend, helper, supporter
|
||||||
|
enmity acrimony, bitterness, ill will, malignity, animosity, hatred, malevolence, rancor, antagonism, hostility, malice, spite agreement, amity, friendship, kindliness, regard, alliance, concord, harmony, kindness, sympathy
|
||||||
|
entertain amuse, cheer, disport, enliven, interest, please, beguile, delight, divert, gratify, occupy, recreate annoy, bore, busy, disquiet, distract, disturb, tire, weary
|
||||||
|
entertainment amusement, diversion, fun, pleasure, cheer, enjoyment, merriment, recreation, delight, frolic, pastime, sport ennui, fatigue, labor, lassitude, toil, weariness, work
|
||||||
|
enthusiasm ardor, excitement, frenzy, transport, devotion, extravagance, inspiration, vehemence, eagerness, fanaticism, intensity, warmth, earnestness, fervency, passion, zeal, ecstasy, fervor, rapture calculation, caution, deadness, indifference, policy, timidity, calmness, coldness, dulness, lukewarmness, prudence, wariness
|
||||||
|
entrance access, approach, gate, introduction, accession, door, gateway, opening, adit, doorway, ingress, penetration, admission, entrée, inlet, portal, admittance, entry departure, ejection, exit, refusal, withdrawal, egress, exclusion, expulsion, rejection
|
||||||
|
envious jealous, suspicious contented, friendly, kindly, satisfied, trustful, well-disposed
|
||||||
|
equivocal ambiguous, enigmatical, indistinct, questionable, doubtful, indefinite, obscure, suspicious, dubious, indeterminate, perplexing, uncertain, enigmatic certain, evident, lucid, perspicuous, unequivocal, clear, indisputable, manifest, plain, unquestionable, distinct, indubitable, obvious, unambiguous, unquestioned
|
||||||
|
esteem appreciate, consider, estimate, prize, think, calculate, deem, hold, regard, value
|
||||||
|
esteem estimate, estimation, favor, regard, respect abhorrence, aversion, dislike, loathing, antipathy, contempt, hatred, repugnance
|
||||||
|
eternal deathless, fadeless, never-failing, undying, endless, immortal, perennial, unending, eonian, imperishable, perpetual, unfading, everlasting, interminable, timeless, unfailing, ever-living, never-ending, unceasing, without end
|
||||||
|
event case, contingency, fortune, outcome, chance, end, incident, possibility, circumstance, episode, issue, result, consequence, fact, occurrence, sequel
|
||||||
|
every all, any, both, each, either
|
||||||
|
evident apparent, glaring, overt, tangible, clear, indubitable, palpable, transparent, conspicuous, manifest, patent, unmistakable, discernible, obvious, perceptible, visible, distinct, open, plain concealed, impalpable, latent, secret, unknown, covert, impenetrable, obscure, undiscovered, unseen, dark, imperceptible, occult, unimagined, unthought-of, hidden, invisible
|
||||||
|
example archetype, ideal, prototype, type, ensample, model, sample, warning, exemplar, pattern, specimen, exemplification, precedent, standard
|
||||||
|
excess dissipation, lavishness, redundance, surplus, exorbitance, overplus, redundancy, waste, extravagance, prodigality, superabundance, wastefulness, intemperance, profusion, superfluity dearth, destitution, frugality, lack, scantiness, defect, economy, inadequacy, need, shortcoming, deficiency, failure, insufficiency, poverty, want
|
||||||
|
execute administer, carry out, do, enforce, perform
|
||||||
|
exercise act, application, exertion, performance, action, drill, occupation, practise, activity, employment, operation, use idleness, inaction, inactivity, relaxation, rest
|
||||||
|
expense cost, expenditure, outgo, outlay gain, proceeds, profit, receipt, return, income, product, profits, receipts, returns
|
||||||
|
explicit ambiguous, implicit, indefinite, uncertain, doubtful, implied, indeterminate, vague
|
||||||
|
extemporaneous extemporary, impromptu, offhand, extempore, improvised, unpremeditated elaborated, premeditated, prepared, read, recited, studied, written
|
||||||
|
exterminate annihilate, eradicate, overthrow, uproot, banish, expel, remove, wipe out, destroy, extirpate, root out augment, breed, cherish, develop, increase, populate, replenish, beget, build up, colonize, foster, plant, propagate, settle
|
||||||
|
faint dim, fatigued, irresolute, weak, exhausted, feeble, languid, wearied, faded, half-hearted, listless, worn, faint-hearted, ill-defined, purposeless, worn down, faltering, indistinct, timid, worn out bright, clear, daring, fresh, resolute, sturdy, brilliant, conspicuous, energetic, hearty, strong, vigorous
|
||||||
|
faith assent, confidence, credit, opinion, assurance, conviction, creed, reliance, belief, credence, doctrine, trust denial, dissent, doubt, infidelity, rejection, suspicion, disbelief, distrust, incredulity, misgiving, skepticism, unbelief
|
||||||
|
faithful devoted, incorruptible, stanch, true, trusty, firm, loyal, sure, trustworthy, unwavering capricious, false, unfaithful, untrustworthy, faithless, fickle, untrue, wavering
|
||||||
|
fame celebrity, eminence, honor, notoriety, reputation, credit, glory, laurels, renown, repute, distinction contempt, discredit, dishonor, humiliation, infamy, obscurity, contumely, disgrace, disrepute, ignominy, oblivion, shame
|
||||||
|
fanaticism bigotry, credulity, intolerance, superstition cynicism, free-thinking, indifference, latitudinarianism
|
||||||
|
fanciful chimerical, fantastic, grotesque, imaginative, visionary accurate, commonplace, prosaic, regular, sound, calculable, literal, real, sensible, sure, calculated, ordinary, reasonable, solid, true
|
||||||
|
fancy belief, desire, imagination, predilection, caprice, humor, inclination, supposition, conceit, idea, liking, vagary, conception, image, mood, whim actuality, certainty, fact, reality, truth, verity
|
||||||
|
farewell adieu, good-by, parting salutation, valedictory, congé, leave-taking, valediction
|
||||||
|
fear affright, dismay, horror, timidity, apprehension, disquietude, misgiving, trembling, awe, dread, panic, tremor, consternation, fright, terror, trepidation
|
||||||
|
feminine effeminate, female, womanish, womanly
|
||||||
|
fetter bondage, custody, gyves, irons, bonds, durance, handcuffs, manacles, chains, duress, imprisonment, shackles
|
||||||
|
feud affray, brawl, contest, dissension, hostility, animosity, broil, controversy, enmity, quarrel, bitterness, contention, dispute, fray, strife
|
||||||
|
fiction allegory, fabrication, invention, myth, romance, apologue, falsehood, legend, novel, story, fable, figment certainty, fact, history, literalness, reality, truth, verity
|
||||||
|
fierce ferocious, furious, raging, uncultivated, violent, fiery, impetuous, savage, untrained, wild affectionate, gentle, kind, patient, submissive, tame, docile, harmless, mild, peaceful, sweet, tender
|
||||||
|
financial fiscal, monetary, pecuniary
|
||||||
|
fine beautiful, excellent, polished, small, clarified, exquisite, pure, smooth, clear, gauzy, refined, splendid, comminuted, handsome, sensitive, subtile, dainty, keen, sharp, subtle, delicate, minute, slender, tenuous, elegant, nice, slight, thin big, clumsy, great, huge, large, stout, blunt, coarse, heavy, immense, rude, thick
|
||||||
|
fire blaze, burning, combustion, conflagration, flame
|
||||||
|
flock bevy, covey, group, herd, lot, set, brood, drove, hatch, litter, pack, swarm
|
||||||
|
fluctuate hesitate, swerve, vacillate, veer, oscillate, undulate, vary, waver abide, adhere, hold fast, persist, stand fast, stay, stick
|
||||||
|
fluid gas, liquid
|
||||||
|
follow accompany, come after, go after, obey, pursue, attend, copy, heed, observe, result, chase, ensue, imitate, practise, succeed
|
||||||
|
food aliment, feed, nourishment, pabulum, sustenance, diet, fodder, nutriment, provender, viands, fare, forage, nutrition, regimen, victuals
|
||||||
|
formidable dangerous, redoubted, terrible, tremendous contemptible, despicable, feeble, harmless, helpless, powerless, weak
|
||||||
|
fortification castle, citadel, fastness, fort, fortress, stronghold
|
||||||
|
fortitude courage, endurance, heroism, resolution
|
||||||
|
fortunate favored, lucky, prospered, prosperous, successful, happy broken, fallen, miserable, unhappy, woful, crushed, ill-starred, unfortunate, unlucky, wretched
|
||||||
|
fraud artifice, deceit, duplicity, swindle, treason, cheat, deception, imposition, swindling, trick, cheating, dishonesty, imposture, treachery fairness, good faith, honesty, integrity, truth, uprightness
|
||||||
|
friendly accessible, companionable, genial, neighborly, affable, complaisant, hearty, sociable, affectionate, cordial, kind, social, amicable, favorable, kindly, tender, brotherly, fond, loving, well-disposed adverse, bellicose, contentious, estranged, ill-disposed, unfriendly, alienated, belligerent, disaffected, frigid, indifferent, unkind, antagonistic, cold, distant, hostile, inimical, warlike
|
||||||
|
friendship affection, comity, esteem, good will, amity, consideration, favor, love, attachment, devotion, friendliness, regard
|
||||||
|
frighten affright, appal, cow, dismay, scare, alarm, browbeat, daunt, intimidate, terrify
|
||||||
|
frugality economy, parsimony, saving, sparing, miserliness, providence, scrimping, thrift, parsimoniousness, prudence abundance, bounty, liberality, opulence, waste, affluence, extravagance, luxury, riches, wealth
|
||||||
|
garrulous chattering, loquacious, talkative, verbose laconic, reserved, reticent, silent, speechless, taciturn
|
||||||
|
general common, familiar, ordinary, universal, commonplace, frequent, popular, usual, customary, habitual, prevalent, everyday, normal, public exceptional, infrequent, rare, singular, uncommon, unknown, unusual
|
||||||
|
generous bountiful, free, liberal, noble, chivalrous, free-handed, magnanimous, open-handed, disinterested, free-hearted, munificent, open-hearted avaricious, covetous, ignoble, mean, niggardly, penurious, rapacious, close, greedy, illiberal, miserly, parsimonious, petty, stingy
|
||||||
|
genius talent, talents dulness, folly, imbecility, obtuseness, senselessness, stupidity
|
||||||
|
get achieve, attain, gain, procure, secure, acquire, earn, obtain, receive, win
|
||||||
|
gift benefaction, boon, bribe, grant, largess, bequest, bounty, donation, gratuity, present compensation, earnings, guerdon, penalty, remuneration wages
|
||||||
|
give bestow, communicate, deliver, grant, supply, cede, confer, furnish, impart
|
||||||
|
govern command, curb, influence, mold, reign over, rule, control, direct, manage, reign, restrain, sway be in subjection, be subject, comply, obey, submit, yield
|
||||||
|
grief affliction, melancholy, regret, sorrow, trouble, distress, mourning, sadness, tribulation, wo
|
||||||
|
habit custom, habitude, routine, system, use, fashion, practise, rule, usage, wont
|
||||||
|
happen bechance, chance, fall out, supervene, befall, come to pass, occur, take place, betide, fall
|
||||||
|
happiness blessedness, delight, gladness, pleasure, bliss, ecstasy, gratification, rapture, cheer, enjoyment, joy, rejoicing, comfort, felicity, merriment, satisfaction, contentment, gaiety, mirth, triumph
|
||||||
|
happy blessed, cheering, gay, lucky, rejoiced, blissful, cheery, glad, merry, rejoicing, blithe, delighted, jocund, mirthful, smiling, blithesome, delightful, jolly, pleased, sprightly, bright, dexterous, joyful, prosperous, successful, buoyant, felicitous, joyous, rapturous, sunny, cheerful, fortunate
|
||||||
|
harmony accord, concurrence, consistency, uniformity, accordance, conformity, consonance, union, agreement, congruity, symmetry, unison, amity, consent, unanimity, unity, concord antagonism, contest, discord, hostility, schism, battle, controversy, disproportion, incongruity, separation, conflict, difference, dissension, inconsistency, variance, contention, disagreement, disunion, opposition, warfare
|
||||||
|
harvest crop, harvest-home, ingathering, result, fruit, harvesting, proceeds, return, growth, harvest-tide, produce, yield, harvest-feast, harvest-time, product, harvest-festival, increase, reaping
|
||||||
|
hatred abhorrence, detestation, hostility, rancor, anger, dislike, ill will, repugnance, animosity, enmity, malevolence, resentment, antipathy, grudge, malice, revenge, aversion, hate, malignity, spite
|
||||||
|
have be in possession of, hold, occupy, own, possess, be possessed of
|
||||||
|
hazard accident, chance, danger, jeopardy, risk, casualty, contingency, fortuity, peril, venture assurance, necessity, protection, safety, surety, certainty, plan, safeguard, security
|
||||||
|
healthy hale, hygienic, sanitary, vigorous, healthful, salubrious, sound, well, hearty, salutary, strong, wholesome delicate, failing, ill, unsound, worn, diseased, fainting, sick, wasted, worn down, emaciated, fragile, unhealthy, weak, worn out, exhausted, frail
|
||||||
|
help abet, befriend, foster, succor, uphold, aid, cooperate, second, support, assist, encourage, stand by, sustain counteract, discourage, oppose, resist, thwart, withstand
|
||||||
|
heretic dissenter, heresiarch, non-conformist, schismatic
|
||||||
|
heterogeneous confused, mingled, unhomogeneous, conglomerate, miscellaneous, unlike, discordant, mixed, variant, dissimilar, non-homogeneous, various alike, homogeneous, identical, like, pure, same, similar, uniform
|
||||||
|
hide bury, cover, entomb, overwhelm, suppress, cloak, disguise, inter, screen, veil, conceal, dissemble, mask, secrete admit, disclose, exhume, manifest, show, advertise, discover, expose, promulgate, tell, avow, disinter, lay bare, publish, uncover, betray, divulge, lay open, raise, unmask, confess, exhibit, make known reveal, unveil
|
||||||
|
high elevated, exalted, noble, steep, towering, eminent, lofty, proud, tall, uplifted base, deep, degraded, depressed, dwarfed, inferior, low, mean, short, stunted
|
||||||
|
hinder baffle, clog, foil, obstruct, retard, balk, counteract, frustrate, oppose, stay, bar, delay, hamper, prevent, stop, block, embarrass, impede, resist, thwart, check, encumber, interrupt
|
||||||
|
history account, biography, muniment, record, annals, chronicle, narration, register, archives, memoir, narrative, story, autobiography, memorial, recital
|
||||||
|
holy blessed, devoted, hallowed, saintly, consecrated, divine, sacred, set apart abominable, cursed, polluted, unconsecrated, unholy, wicked, common, impure, secular, unhallowed, unsanctified, worldly
|
||||||
|
home abode, dwelling, habitation, hearthstone, ingleside, domicil, fireside, hearth, house, residence
|
||||||
|
honest candid, frank, ingenuous, true, equitable, genuine, just, trustworthy, fair, good, sincere, trusty, faithful, honorable, straightforward, upright deceitful, faithless, hypocritical, perfidious, unfaithful, dishonest, false, lying, traitorous, unscrupulous, disingenuous, fraudulent, mendacious, treacherous, untrue
|
||||||
|
horizontal even, flat, level, plain, plane broken, inclined, rolling, rugged, sloping, hilly, irregular, rough, slanting, uneven
|
||||||
|
humane benevolent, compassionate, human, pitying, benignant, forgiving, kind, sympathetic, charitable, gentle, kind-hearted, tender, clement, gracious, merciful, tender-hearted
|
||||||
|
hunt chase, hunting, inquisition, pursuit, search
|
||||||
|
hypocrisy affectation, formalism, pretense, sanctimony, cant, pharisaism, sanctimoniousness, sham, dissimulation, pietism candor, genuineness, ingenuousness, sincerity, truth, frankness, honesty, openness, transparency, truthfulness
|
||||||
|
hypocrite cheat, deceiver, dissembler, impostor, pretender
|
||||||
|
hypothesis conjecture, scheme, supposition, system, guess, speculation, surmise, theory certainty, demonstration, discovery, evidence, fact, proof
|
||||||
|
idea apprehension, design, impression, plan, archetype, fancy, judgment, purpose, belief, fantasy, model, sentiment, conceit, ideal, notion, supposition, concept, image, opinion, theory, conception, imagination, pattern, thought actuality, fact, reality, substance
|
||||||
|
ideal archetype, model, pattern, prototype, standard, idea, original accomplishment, action, doing, fact, practise, achievement, attainment, embodiment, incarnation, reality, act, development, execution, performance, realization
|
||||||
|
idiocy fatuity, foolishness, incapacity, stupidity, folly, imbecility, senselessness acuteness, brilliancy, common sense, sagacity, soundness, astuteness, capacity, intelligence, sense, wisdom
|
||||||
|
idle inactive, inert, slothful, trifling, unoccupied, indolent, lazy, sluggish, unemployed, vacant active, busy, diligent, employed, industrious, occupied, working
|
||||||
|
ignorant ill-informed, unenlightened, unlearned, untaught, illiterate, uninformed, unlettered, untutored, uneducated, uninstructed, unskilled educated, instructed, learned, sage, skilled, trained, well-informed, wise
|
||||||
|
imagination fancy, fantasy, phantasy
|
||||||
|
immediately at once, instanter, presently, straightway, directly, instantly, right away, this instant, forthwith, now, right off, without delay after a while, by and by, hereafter, in the future, some time
|
||||||
|
immerse bury, dip, douse, duck, immerge, plunge, sink, submerge
|
||||||
|
imminent impending, threatening chimerical, contingent, doubtful, improbable, problematical, unexpected, unlikely
|
||||||
|
impediment bar, clog, encumbrance, obstacle, barrier, difficulty, hindrance, obstruction advantage, aid, assistance, benefit, help, relief, succor
|
||||||
|
impudence assurance, impertinence, intrusiveness, presumption, boldness, incivility, officiousness, rudeness, effrontery, insolence, pertness, sauciness, forwardness bashfulness, diffidence, lowliness, modesty, coyness, humility, meekness, submissiveness
|
||||||
|
incongruous absurd, ill-matched, inharmonious, conflicting, inapposite, irreconcilable, contradictory, inappropriate, mismatched, contrary, incommensurable, mismated, discordant, incompatible, repugnant, discrepant, inconsistent, unsuitable accordant, agreeing, compatible, consistent, harmonious, suitable
|
||||||
|
induction deduction, inference
|
||||||
|
industrious active, busy, employed, occupied, assiduous, diligent, engaged, sedulous
|
||||||
|
industry application, diligence, labor, persistence, assiduity, effort, pains, sedulousness, attention, exertion, patience, constancy, intentness, perseverance changeableness, idleness, inconstancy, neglect, remissness, fickleness, inattention, indolence, negligence, sloth
|
||||||
|
infinite absolute, illimitable, limitless, unconditioned, boundless, immeasurable, measureless, unfathomable, countless, innumerable, numberless, unlimited, eternal, interminable, unbounded, unmeasured bounded, finite, measurable, restricted, small, brief, limited, moderate, shallow, transient, circumscribed, little, narrow, short, transitory, evanescent
|
||||||
|
influence actuate, draw, impel, induce, move, stir, compel, drive, incite, instigate, persuade, sway, dispose, excite, incline, lead, prompt, urge deter, dissuade, impede, prevent, restrain, retard, discourage, hinder, inhibit
|
||||||
|
inherent congenital, indispensable, innate, native, essential, indwelling, inseparable, natural, immanent, infixed, internal, subjective, inborn, ingrained, intrinsic, inbred, inhering, inwrought accidental, extrinsic, outward, superficial, supplemental, casual, fortuitous, subsidiary, superfluous, transient, external, incidental, superadded, superimposed, unconnected
|
||||||
|
injury blemish, disadvantage, hurt, loss, prejudice, damage, evil, impairment, mischief, wrong, detriment, harm, injustice, outrage advantage, benefit, boon, improvement, service, amelioration, blessing, help, remedy, utility
|
||||||
|
injustice grievance, injury, unfairness, unrighteousness, wrong, iniquity equity, faithfulness, impartiality, lawfulness, righteousness, fairness, honesty, integrity, rectitude, uprightness, fair play, honor, justice, right
|
||||||
|
innocent blameless, guiltless, inoffensive, spotless, clean, harmless, pure, stainless, clear, immaculate, right, upright, faultless, innocuous, righteous, virtuous, guileless, innoxious, sinless
|
||||||
|
inquisitive curious, meddlesome, peeping, scrutinizing, inquiring, meddling, prying, searching, intrusive apathetic, heedless, indifferent, unconcerned, uninterested, careless, inattentive
|
||||||
|
insanity aberration, delirium, frenzy, madness, alienation, dementia, hallucination, mania, craziness, derangement, lunacy, monomania clearness, good sense, lucidity, rationality, sanity
|
||||||
|
interpose arbitrate, intercept, intermeddle, meddle, intercede, interfere, interrupt, mediate avoid, keep aloof, keep out, retire, stand back, hold aloof, keep away, let alone, stand aside, stand off, hold off, keep clear, let be, stand away, withdraw
|
||||||
|
involve complicate, embroil, implicate, include, embarrass, entangle, imply, overwhelm disconnect, disentangle, distinguish, explicate, extricate, remove, separate
|
||||||
|
journey excursion, pilgrimage, transit, trip, expedition, tour, travel, voyage
|
||||||
|
judge arbiter, arbitrator, justice, referee, umpire
|
||||||
|
justice equity, impartiality, legality, rightfulness, fairness, integrity, rectitude, truth, fair play, justness, right, uprightness, faithfulness, law, righteousness, virtue, honor, lawfulness dishonesty, inequity, partiality, unlawfulness, untruth, favoritism, injustice, unfairness, unreasonableness, wrong
|
||||||
|
keep carry, defend, hold, preserve, retain, carry on, detain, maintain, protect, support, celebrate, fulfil, obey, refrain, sustain, conduct, guard, observe, restrain, withhold
|
||||||
|
kill assassinate, despatch, massacre, put to death, slay, butcher, execute, murder, slaughter
|
||||||
|
kin affinity, blood, descent, kind, race, alliance, consanguinity, family, kindred, relationship, birth
|
||||||
|
knowledge acquaintance, erudition, learning, recognition, apprehension, experience, light, scholarship, cognition, information, lore, science, cognizance, intelligence, perception, wisdom, comprehension, intuition ignorance, inexperience, misconception, rudeness, illiteracy, misapprehension, misunderstanding, unfamiliarity
|
||||||
|
language barbarism, expression, patois, vernacular, dialect, idiom, speech, vocabulary, diction, mother tongue, tongue
|
||||||
|
large abundant, coarse, gigantic, long, ample, colossal, grand, massive, big, commodious, great, spacious, broad, considerable, huge, vast, bulky, enormous, immense, wide, capacious, extensive brief, infinitesimal, little, minute, petty, slender, tiny, diminutive, insignificant, mean, narrow, scanty, slight, trifling, inconsiderable, limited, microscopic, paltry, short, small, trivial
|
||||||
|
law canon, economy, legislation, principle, code, edict, mandate, regulation, command, enactment, order, rule, commandment, formula, ordinance, statute, decree, jurisprudence, polity
|
||||||
|
liberty emancipation, freedom, independence, license captivity, imprisonment, oppression, slavery, compulsion, necessity, serfdom, superstition, constraint, obligation, servitude, thraldom
|
||||||
|
light blaze, gleam, glow, shimmer, flame, gleaming, illumination, shine, flare, glimmer, incandescence, shining, flash, glistening, luster, sparkle, flicker, glistering, scintillation, twinkle, glare, glitter, sheen, twinkling blackness, darkness, dusk, gloominess, shade, dark, dimness, gloom, obscurity, shadow
|
||||||
|
likely apt, conceivable, liable, probable, credible, conjectural, presumable, reasonable doubtful, improbable, questionable, unreasonable, dubious, incredible, unlikely
|
||||||
|
listen attend, hark, harken, hear, heed, list be deaf to, ignore, neglect, scorn, slight
|
||||||
|
literature belles-lettres, literary productions, publications, books, literary works, writings
|
||||||
|
load burden, charge, encumbrance, incubus, pack, cargo, clog, freight, lading, weight
|
||||||
|
lock bar, catch, fastening, hook, bolt, clasp, hasp, latch
|
||||||
|
look behold, discern, inspect, see, view, contemplate, gaze, regard, stare, watch, descry, glance, scan, survey
|
||||||
|
love affection, charity, friendship, regard, attachment, devotion, liking, tenderness, attraction, fondness
|
||||||
|
make become, constrain, fabricate, manufacture, bring about, construct, fashion, occasion, bring into being, create, force, perform, bring to pass, do, frame, reach, cause, effect, get, render, compel, establish, make out, require, compose, execute, make up, shape, constitute
|
||||||
|
marriage conjugal union, espousals, nuptials, spousals, wedding, espousal, matrimony, spousal, union, wedlock bachelorhood, celibacy, divorce, maidenhood, virginity, widowhood
|
||||||
|
masculine male, manful, manlike, manly, mannish, virile
|
||||||
|
massacre butchery, carnage, havoc, slaughter
|
||||||
|
meddlesome impertinent, intrusive, meddling, obtrusive, officious modest, reserved, retiring, shy, unassuming, unobtrusive
|
||||||
|
melody harmony, music, symphony, unison
|
||||||
|
memory recollection, reminiscence, retrospect, retrospection, remembrance forgetfulness, oblivion, obliviousness, oversight, unconsciousness
|
||||||
|
mercy benevolence, favor, kindness, mildness, benignity, forbearance, lenience, pardon, blessing, forgiveness, leniency, pity, clemency, gentleness, lenity, tenderness, compassion, grace cruelty, implacability, punishment, rigor, sternness, hardness, justice, revenge, severity, vengeance, harshness, penalty
|
||||||
|
meter euphony, measure, rhythm, verse
|
||||||
|
mind brain, instinct, reason, spirit, consciousness, intellect, sense, thought, disposition, intelligence, soul, understanding body, brawn, brute force, material substance, matter
|
||||||
|
minute circumstantial, diminutive, little, slender, comminuted, exact, particular, small, critical, fine, precise, tiny, detailed
|
||||||
|
misfortune adversity, disappointment, ill fortune, ruin, affliction, disaster, ill luck, sorrow, bereavement, distress, misadventure, stroke, blow, failure, mischance, trial, calamity, hardship, misery, tribulation, chastening, harm, mishap, trouble, chastisement, ill, reverse, visitation blessing, consolation, gratification, pleasure, success, boon, good fortune, happiness, prosperity, triumph, comfort, good luck, joy, relief
|
||||||
|
mob canaille, dregs of the people, masses, rabble, crowd, lower classes, populace, the vulgar
|
||||||
|
model archetype, facsimile, original, representation, copy, image, pattern, standard, design, imitation, prototype, type, example, mold
|
||||||
|
modesty backwardness, constraint, reserve, timidity, bashfulness, coyness, shyness, unobtrusiveness, coldness, diffidence abandon, boldness, forwardness, impudence, pertness, sociability, arrogance, conceit, frankness, indiscretion, sauciness, assumption, confidence, freedom, loquaciousness, self-conceit, assurance, egotism, haughtiness, loquacity, self-sufficiency
|
||||||
|
money bills, cash, funds, property, bullion, coin, gold, silver, capital, currency, notes, specie
|
||||||
|
morose acrimonious, dogged, ill-natured, splenetic, churlish, gloomy, severe, sulky, crabbed, gruff, snappish, sullen, crusty, ill-humored, sour, surly amiable, complaisant, gentle, kind, pleasant, benignant, friendly, good-natured, loving, sympathetic, bland, genial, indulgent, mild, tender
|
||||||
|
motion act, change, movement, process, transition, action, move, passage, transit immobility, quiescence, quiet, repose, rest, stillness
|
||||||
|
mourn bemoan, deplore, lament, regret, rue, sorrow, bewail, grieve be joyful, exult, joy, make merry, rejoice, triumph
|
||||||
|
mutual common, correlative, interchangeable, joint, reciprocal detached, distinct, separate, severed, unconnected, unrequited, disconnected, disunited, separated, sundered, unreciprocated, unshared, dissociated
|
||||||
|
mysterious abstruse, inexplicable, recondite, cabalistic, inscrutable, secret, dark, mystic, transcendental, enigmatical, mystical, unfathomable, hidden, obscure, unfathomed, incomprehensible, occult, unknown
|
||||||
|
name agnomen, denomination, prenomen, surname, appellation, designation, style, title, cognomen, epithet
|
||||||
|
native indigenous, innate, natal, natural, original acquired, alien, artificial, assumed, foreign, unnatural
|
||||||
|
nautical marine, maritime, naval, ocean, oceanic
|
||||||
|
neat clean, dapper, nice, prim, tidy, cleanly, natty, orderly, spruce, trim dirty, negligent, slouchy, uncared for, disorderly, rough, slovenly, unkempt, dowdy, rude, soiled, untidy
|
||||||
|
necessary essential, infallible, required, unavoidable, indispensable, needed, requisite, undeniable, inevitable, needful casual, needless, optional, useless, contingent, non-essential, unnecessary, worthless
|
||||||
|
necessity compulsion, fatality, requisite, destiny, fate, sine qua non, emergency, indispensability, unavoidableness, essential, indispensableness, urgency, exigency, need, want, extremity, requirement choice, doubt, dubiousness, freedom, possibility, contingency, doubtfulness, fortuity, option, uncertainty
|
||||||
|
neglect carelessness, heedlessness, negligence, scorn, default, inadvertence, omission, slackness, disregard, inattention, oversight, slight, disrespect, indifference, remissness, thoughtlessness, failure, neglectfulness
|
||||||
|
new fresh, modern, new-made, upstart, juvenile, new-fangled, novel, young, late, new-fashioned, recent, youthful
|
||||||
|
nimble active, alert, bustling, prompt, speedy, spry, agile, brisk, lively, quick, sprightly, swift clumsy, dilatory, dull, heavy, inactive, inert, slow, sluggish, unready
|
||||||
|
normal common, natural, ordinary, regular, typical, usual abnormal, irregular, peculiar, singular, unprecedented, exceptional, monstrous, rare, uncommon, unusual
|
||||||
|
notwithstanding altho(ugh), howbeit, nevertheless, tho(ugh), but, however, still, yet
|
||||||
|
notwithstanding despite, in spite of
|
||||||
|
oath adjuration, curse, profane swearing, affidavit, cursing, profanity, anathema, denunciation, reprobation, ban, execration, swearing, blaspheming, imprecation, sworn statement, blasphemy, malediction, vow benediction, benison, blessing
|
||||||
|
obscure abstruse, darksome, dusky, involved, ambiguous, deep, enigmatical, muddy, cloudy, dense, hidden, mysterious, complex, difficult, incomprehensible, profound, complicated, dim, indistinct, turbid, dark, doubtful, intricate, unintelligible
|
||||||
|
obsolete ancient, archaic, obsolescent, out of date, antiquated, disused, old, rare
|
||||||
|
obstinate contumacious, headstrong, mulish, resolute, decided, heady, obdurate, resolved, determined, immovable, opinionated, stubborn, dogged, indomitable, persistent, unconquerable, firm, inflexible, pertinacious, unflinching, fixed, intractable, refractory, unyielding amenable, dutiful, pliable, tractable, complaisant, gentle, pliant, undecided, compliant, irresolute, submissive, wavering, docile, obedient, teachable, yielding
|
||||||
|
obstruct arrest, check, embarrass, interrupt, stay, bar, choke, hinder, oppose, stop, barricade, clog, impede, retard accelerate, aid, facilitate, free, open, promote, advance, clear, forward, further, pave the way for
|
||||||
|
old aged, decrepit, immemorial, senile, ancient, elderly, olden, time-honored, antiquated, gray, patriarchal, time-worn, antique, hoary, remote, venerable
|
||||||
|
operation action, effect, force, performance, result, agency, execution, influence, procedure failure, ineffectiveness, inutility, powerlessness, uselessness, inaction, inefficiency
|
||||||
|
order command, injunction, mandate, requirement, direction, instruction, prohibition allowance, consent, leave, liberty, license, permission, permit
|
||||||
|
ostentation boast, flourish, parade, pompousness, vaunt, boasting, pageant, pomp, show, vaunting, display, pageantry, pomposity diffidence, quietness, retirement, timidity, modesty, reserve, shrinking, unobtrusiveness
|
||||||
|
oversight care, control, management, surveillance, charge, direction, superintendence, watch, command, inspection, supervision, watchfulness
|
||||||
|
pain ache, distress, suffering, torture, agony, pang, throe, twinge, anguish, paroxysm, torment, wo(e) comfort, delight, ease, enjoyment, peace, rapture, relief, solace
|
||||||
|
palliate apologize for, conceal, extenuate, hide, screen, cloak, cover, gloss over, mitigate, veil
|
||||||
|
pardon absolve, condone, forgive, pass by, remit, acquit, excuse, overlook, pass over castigate, chastise, convict, doom, recompense, sentence, chasten, condemn, correct, punish, scourge, visit
|
||||||
|
pardon absolution, amnesty, forgiveness, oblivion, acquittal, forbearance, mercy, remission penalty, punishment, retaliation, retribution, vengeance
|
||||||
|
part atom, fraction, member, section, component, fragment, particle, segment, constituent, ingredient, piece, share, division, instalment, portion, subdivision, element
|
||||||
|
particle atom, grain, mite, scrap, whit, corpuscle, iota, molecule, shred, element, jot, scintilla, tittle aggregate, entirety, mass, quantity, sum, sum total, total, whole
|
||||||
|
patience calmness, forbearance, long-suffering, sufferance, composure, fortitude, resignation, endurance, leniency, submission
|
||||||
|
pay allowance, hire, recompense, salary, compensation, honorarium, remuneration, stipend, earnings, payment, requital, wages, fee
|
||||||
|
people commonwealth, nation, race, state, tribe, community, population
|
||||||
|
perceive apprehend, comprehend, conceive, understand fail of, ignore, lose, misapprehend, misconceive, miss, overlook
|
||||||
|
perfect absolute, consummate, holy, spotless, accurate, correct, ideal, stainless, blameless, entire, immaculate, unblemished, complete, faultless, sinless, undefiled, completed, finished bad, defective, imperfect, meager, scant, blemished, deficient, incomplete, perverted, short, corrupt, deformed, inferior, poor, spoiled, corrupted, fallible, insufficient, ruined, worthless, defaced, faulty, marred
|
||||||
|
permanent abiding, enduring, lasting, steadfast, changeless, fixed, perpetual, unchangeable, constant, immutable, persistent, unchanging, durable, invariable, stable
|
||||||
|
permission allowance, authorization, leave, license, authority, consent, liberty, permit denial, objection, prevention, refusal, resistance, hindrance, opposition, prohibition
|
||||||
|
pernicious bad, evil, mischievous, pestilential, baneful, foul, noisome, poisonous, deadly, harmful, noxious, ruinous, deleterious, hurtful, perverting, unhealthful, destructive, injurious, pestiferous, unwholesome, detrimental, insalubrious advantageous, favorable, helpful, profitable, serviceable, beneficent, good, invigorating, rejuvenating, useful, beneficial, healthful, life-giving, salutary, wholesome
|
||||||
|
perplexity amazement, bewilderment, distraction, doubt, astonishment, confusion, disturbance, embarrassment
|
||||||
|
persuade allure, dispose, incline, move, bring over, entice, induce, prevail on or upon, coax, impel, influence, urge, convince, incite, lead, win over deter, discourage, dissuade, hinder, hold back, repel, restrain
|
||||||
|
pertness boldness, forwardness, liveliness, sprightliness, briskness, impertinence, sauciness, flippancy, impudence, smartness bashfulness, demureness, diffidence, humility, modesty, shyness
|
||||||
|
perverse contrary, froward, petulant, untoward, factious, intractable, stubborn, wayward, fractious, obstinate, ungovernable, wilful accommodating, complaisant, genial, kind, amenable, compliant, governable, obliging
|
||||||
|
physical bodily, corporeal, natural, tangible, corporal, material, sensible, visible hyperphysical, intangible, invisible, moral, unreal, immaterial, intellectual, mental, spiritual, unsubstantial
|
||||||
|
pique displeasure, irritation, offense, resentment, umbrage, grudge approval, contentment, delight, gratification, pleasure, satisfaction, complacency
|
||||||
|
pitiful abject, lamentable, paltry, sorrowful, base, miserable, pathetic, touching, contemptible, mournful, piteous, woful, despicable, moving, pitiable, wretched august, dignified, grand, lofty, sublime, beneficent, exalted, great, mighty, superb, commanding, glorious, helpful, noble, superior
|
||||||
|
pity commiseration, condolence, sympathy, tenderness, compassion, mercy barbarity, ferocity, harshness, pitilessness, severity, brutality, hard-heartedness, inhumanity, rigor, sternness, cruelty, hardness, mercilessness, ruthlessness, truculence
|
||||||
|
plant seed, seed down, set, set out, sow eradicate, extirpate, root up, uproot, weed out
|
||||||
|
plead advocate, ask, beseech, implore, solicit, argue, beg, entreat, press, urge
|
||||||
|
pleasant agreeable, good-natured, kindly, pleasing, attractive, kind, obliging, pleasurable arrogant, displeasing, glum, ill-humored, repelling, austere, dreary, grim, ill-natured, repulsive, crabbed, forbidding, harsh, offensive, unkind, disagreeable, gloomy, hateful, repellent, unpleasant
|
||||||
|
plentiful abounding, bountiful, generous, plenteous, abundant, complete, large, profuse, adequate, copious, lavish, replete, affluent, enough, liberal, rich, ample, exuberant, luxuriant, sufficient, bounteous, full, overflowing, teeming deficient, inadequate, narrow, scanty, small, drained, insufficient, niggardly, scarce, sparing, exhausted, mean, poor, scrimped, stingy, impoverished, miserly, scant, short, straitened
|
||||||
|
poetry meter, numbers, poesy, song, metrical composition, poem, rime, verse prosaic speech, prosaic writing, prose
|
||||||
|
polite accomplished, courtly, genteel, urbane, civil, cultivated, gracious, well-behaved, complaisant, cultured, obliging, well-bred, courteous, elegant, polished, well-mannered awkward, clownish, ill-mannered, insulting, uncouth, bluff, coarse, impertinent, raw, unmannerly, blunt, discourteous, impolite, rude, unpolished, boorish, ill-behaved, impudent, rustic, untaught, brusk, ill-bred, insolent, uncivil, untutored
|
||||||
|
polity constitution, policy, form or system of government
|
||||||
|
portion lot, parcel, part, proportion, share
|
||||||
|
poverty beggary, distress, mendicancy, pauperism, privation, destitution, indigence, need, penury, want
|
||||||
|
power ability, competency, expertness, readiness, aptitude, dexterity, faculty, skill, capability, efficacy, force, strength, capacity, efficiency, might, susceptibility, cleverness, energy, qualification, talent, cogency awkwardness, helplessness, inability, incompetence, stupidity, dulness, imbecility, inaptitude, inefficiency, unskilfulness, feebleness, impotence, incapacity, maladroitness, weakness
|
||||||
|
praise acclaim, approbation, compliment, laudation, acclamation, approval, encomium, panegyric, adulation, cheering, eulogy, plaudit, applause, cheers, flattery, sycophancy abuse, condemnation, disapproval, obloquy, scorn, animadversion, contempt, disparagement, reproach, slander, blame, denunciation, hissing, reproof, vilification, censure, disapprobation, ignominy, repudiation, vituperation
|
||||||
|
pray ask, bid, entreat, invoke, request, beg, call upon, implore, petition, supplicate, beseech, conjure, importune, plead
|
||||||
|
precarious doubtful, hazardous, risky, unsettled, dubious, insecure, unassured, unstable, equivocal, perilous, uncertain, unsteady actual, firm, infallible, stable, sure, undoubted, assured, immutable, real, steady, undeniable, unquestionable, certain, incontestable, settled, strong
|
||||||
|
precedent antecedent, case, instance, pattern, authority, example, obiter dictum, warrant
|
||||||
|
predestination fate, foreknowledge, foreordination, necessity accident, choice, freedom, independence, chance, free agency, free will, uncertainty
|
||||||
|
prejudice bias, preconception, presumption, partiality, prepossession, unfairness certainty, conviction, evidence, reason, conclusion, demonstration, proof, reasoning
|
||||||
|
pretense affectation, disguise, pretext, simulation, air, dissimulation, ruse, subterfuge, assumption, excuse, seeming, trick, cloak, mask, semblance, wile, color, pretension, show actuality, fact, guilelessness, ingenuousness, reality, sincerity, candor, frankness, honesty, openness, simplicity, truth
|
||||||
|
prevent anticipate, forestall, obviate, preclude
|
||||||
|
previous antecedent, foregoing, front, preceding, anterior, former, introductory, preliminary, earlier, forward, precedent, prior after, consequent, hind, hindmost, latter, subsequent, concluding, following, hinder, later, posterior, succeeding
|
||||||
|
price charge, cost, expenditure, expense, outlay, value, worth
|
||||||
|
pride arrogance, ostentation, self-exaltation, assumption, presumption, self-respect, conceit, reserve, superciliousness, disdain, self-complacency, vainglory, haughtiness, self-conceit, vanity, insolence, self-esteem humility, lowliness, meekness, modesty, self-abasement, self-distrust
|
||||||
|
primeval aboriginal, indigenous, patriarchal, primitive, ancient, native, primal, primordial, autochthonic, old, primary, pristine, immemorial, original, prime, uncreated adventitious, foreign, late, new, recent, exotic, fresh, modern, novel
|
||||||
|
profit advantage, expediency, proceeds, service, avail, gain, receipts, usefulness, benefit, good, return, utility, emolument, improvement, returns, value damage, detriment, harm, injury, ruin, destruction, disadvantage, hurt, loss, waste
|
||||||
|
progress advance, development, improvement, proficiency, advancement, growth, increase, progression, attainment check, delay, falling off, retrogression, stop, decline, falling back, relapse, stay, stoppage
|
||||||
|
prohibit debar, forbid, inhibit, preclude, disallow, hinder, interdict, prevent allow, empower, let, require, authorize, enjoin, license, sanction, command, give consent, order, suffer, consent to, give leave, permit, tolerate, direct, give permission, put up with, warrant
|
||||||
|
promote advance, encourage, forward, prefer, raise, aid, exalt, foster, push, urge forward, assist, excite, further, push on, urge on, elevate, foment, help
|
||||||
|
propitiation atonement, expiation, reconciliation, satisfaction alienation, curse, penalty, reprobation, vengeance, chastisement, estrangement, punishment, retribution, wrath, condemnation, offense
|
||||||
|
propitious auspicious, benignant, favorable, gracious, kindly, benign, clement, friendly, kind, merciful adverse, forbidding, ill-disposed, repellent, unfriendly, antagonistic, hostile, inauspicious, unfavorable, unpropitious
|
||||||
|
proposal bid, offer, overture, proposition acceptance, denial, disapproval, refusal, rejection, repulse
|
||||||
|
propose
|
||||||
|
protract continue, delay, elongate, lengthen, procrastinate, defer, draw out, extend, postpone, prolong abbreviate, conclude, curtail, hurry, reduce, abridge, contract, hasten, limit, shorten
|
||||||
|
proverb adage, axiom, maxim, saw, aphorism, byword, motto, saying, apothegm, dictum, precept, truism
|
||||||
|
prowess bravery, gallantry, intrepidity, courage, heroism, valor cowardice, cowardliness, effeminacy, fear, pusillanimity, timidity
|
||||||
|
prudence care, discretion, judgment, carefulness, forecast, judiciousness, caution, foresight, providence, circumspection, forethought, wisdom, consideration, frugality folly, improvidence, indiscretion, rashness, thoughtlessness, heedlessness, imprudence, prodigality, recklessness, wastefulness
|
||||||
|
purchase acquire, barter for, get, procure, secure, bargain for, buy, obtain barter, dispose of, exchange, put to sale, sell
|
||||||
|
pure absolute, guiltless, simple, unmixed, chaste, holy, spotless, unpolluted, classic, immaculate, stainless, unspotted, classical, incorrupt, true, unstained, clean, innocent, unadulterated, unsullied, clear, mere, unblemished, untainted, continent, perfect, uncorrupted, untarnished, genuine, real, undefiled, upright, guileless, sheer, unmingled, virtuous adulterated, foul, indecent, obscene, tainted, defiled, gross, indelicate, polluted, tarnished, dirty, immodest, lewd, stained, unchaste, filthy, impure, mixed, sullied, unclean
|
||||||
|
put deposit, lay, place, set
|
||||||
|
queer anomalous, erratic, odd, strange, bizarre, extraordinary, peculiar, uncommon, comical, fantastic, preposterous, unique, crotchety, funny, quaint, unmatched, curious, grotesque, ridiculous, unusual, droll, laughable, singular, whimsical, eccentric, ludicrous common, familiar, normal, regular, customary, natural, ordinary, usual
|
||||||
|
quicken accelerate, drive on, hasten, promote, advance, expedite, hurry, speed, despatch, facilitate, make haste, urge, drive, further, press forward, urge on check, clog, delay, drag, hinder, impede, obstruct, retard
|
||||||
|
quote cite, extract, plagiarize, repeat, excerpt, paraphrase, recite
|
||||||
|
racy flavorous, lively, pungent, spicy, forcible, piquant, rich, spirited cold, flat, insipid, stale, tasteless, dull, flavorless, prosy, stupid, vapid
|
||||||
|
radical complete, ingrained, perfect, constitutional, innate, positive, entire, native, primitive, essential, natural, thorough, extreme, organic, thoroughgoing, fundamental, original, total conservative, incomplete, palliative, slight, tentative, inadequate, moderate, partial, superficial, trial
|
||||||
|
rare curious, odd, scarce, unique, extraordinary, peculiar, singular, unparalleled, incomparable, precious, strange, unprecedented, infrequent, remarkable, uncommon, unusual
|
||||||
|
reach arrive, attain, come to, enter, gain, get to, land depart, embark, go, go away, leave, set out, set sail, start, weigh anchor
|
||||||
|
real actual, demonstrable, genuine, true, authentic, developed, positive, unquestionable, certain, essential, substantial, veritable conceived, feigned, illusory, supposed, unreal, fabulous, fictitious, imaginary, supposititious, untrue, fanciful, hypothetical, reported, theoretical, visionary
|
||||||
|
reason argue, debate, discuss, establish, question, contend, demonstrate, dispute, prove, wrangle, controvert
|
||||||
|
reason account, cause, end, motive, principle, aim, consideration, ground, object, purpose, argument, design
|
||||||
|
reasoning argument, argumentation, debate, ratiocination
|
||||||
|
rebellious contumacious, mutinous, uncontrollable, disobedient, refractory, ungovernable, insubordinate, seditious, unmanageable, intractable compliant, docile, manageable, subservient, controllable, dutiful, obedient, tractable, deferential, gentle, submissive, yielding
|
||||||
|
record account, enrolment, instrument, register, archive, entry, inventory, roll, catalogue, enumeration, memorandum, schedule, chronicle, history, memorial, scroll, document, inscription, muniment
|
||||||
|
recover be cured or healed, heal, recuperate, restore, be restored, reanimate, regain, resume, cure, recruit, repossess, retrieve die, fail, grow worse, relapse, sink
|
||||||
|
refinement civilization, cultivation, culture, elegance, politeness barbarism, brutality, coarseness, rudeness, savagery, boorishness, clownishness, grossness, rusticity, vulgarity
|
||||||
|
refute confound, confute, disprove, overthrow, repel
|
||||||
|
reliable trustworthy, trusty
|
||||||
|
religion devotion, godliness, morality, piety, theology, faith, holiness, pietism, righteousness, worship atheism, godlessness, irreligion, sacrilege, ungodliness, blasphemy, impiety, profanity, unbelief, wickedness
|
||||||
|
reluctant averse, disinclined, loath, slow, backward, indisposed, opposed, unwilling desirous, disposed, eager, favorable, inclined, willing
|
||||||
|
remark annotation, comment, note, observation, utterance
|
||||||
|
rend break, cleave, mangle, rive, sever, sunder, burst, lacerate, rip, rupture, slit, tear heal, join, mend, reunite, secure, sew, solder, stitch, unite, weld
|
||||||
|
renounce abandon, disavow, disown, recant, repudiate, abjure, discard, forswear, refuse, retract, deny, disclaim, recall, reject, revoke acknowledge, assert, cherish, defend, maintain, proclaim, uphold, advocate, avow, claim, hold, own, retain, vindicate
|
||||||
|
repentance compunction, contriteness, regret, self-condemnation, contrition, penitence, remorse, sorrow approval, content, obduracy, self-complacency, comfort, hardness, obstinacy, self-congratulation, complacency, impenitence, self-approval, stubbornness
|
||||||
|
report account, narrative, rehearsal, rumor, story, description, recital, relation, statement, tale, narration, record
|
||||||
|
reproof admonition, chiding, disapproval, reprimand, animadversion, comment, objurgation, reproach, blame, condemnation, rebuke, reproval, censure, criticism, reflection, upbraiding, check, denunciation, reprehension applause, approval, encomium, eulogy, panegyric, praise, approbation, commendation
|
||||||
|
reprove admonish, condemn, reprimand, blame, expostulate with, reproach, censure, find fault with, take to task, chasten, rebuke, upbraid, check, remonstrate with, warn, chide, reprehend abet, approve, countenance, impel, instigate, applaud, cheer, encourage, incite, urge on
|
||||||
|
requite avenge, punish, remunerate, revenge, compensate, quit, repay, reward, pay, reciprocate, retaliate, satisfy, pay off, recompense, return, settle with absolve, excuse, forgive, overlook, pass over, acquit, forget, neglect, pardon, slight
|
||||||
|
rest calm, pause, quietness, slumber, calmness, peace, quietude, stay, cessation, peacefulness, recreation, stillness, ease, quiescence, repose, stop, intermission, quiet, sleep, tranquillity agitation, disturbance, movement, stir, tumult, commotion, excitement, restlessness, strain, unrest, disquiet, motion, rush, toil, work
|
||||||
|
restive balky, impatient, rebellious, restless, fidgety, intractable, recalcitrant, skittish, fractious, mulish, refractory, stubborn, fretful, mutinous, resentful, unruly, frisky, obstinate, restiff, vicious docile, manageable, passive, quiet, tractable, gentle, obedient, peaceable, submissive, yielding
|
||||||
|
restrain abridge, constrain, hold in, keep under, bridle, curb, keep, repress, check, hinder, keep back, restrict, circumscribe, hold, keep down, suppress, confine, hold back, keep in, withhold aid, arouse, encourage, free, incite, release, animate, emancipate, excite, impel, let loose, set free
|
||||||
|
retirement loneliness, privacy, seclusion, solitude association, companionship, company, converse, fellowship, society
|
||||||
|
revelation apocalypse, disclosure, manifestation cloud, concealment, mystery, shrouding, cloudiness, hiding, obscuration, veiling
|
||||||
|
revenge avenging, retaliation, retribution, vengeance, requital compassion, forgiveness, mercy, pardon, pity, reconciliation, excuse, grace
|
||||||
|
revolution anarchy, insurrection, revolt, confusion, lawlessness, riot, disintegration, mutiny, sedition, disorder, rebellion, tumult, insubordination authority, domination, government, obedience, sovereignty, command, dominion, law, order, submission, control, empire, loyalty, rule, supremacy
|
||||||
|
revolve roll, rotate, turn bind, chafe, grind, slide, slip, stand, stick
|
||||||
|
riddle conundrum, enigma, paradox, problem, puzzle answer, axiom, explanation, proposition, solution
|
||||||
|
right claim, franchise, liberty, prerogative, exemption, immunity, license, privilege
|
||||||
|
rise arise, ascend, emanate, flow, issue, proceed, spring decline, descend, drop, fall, go down, set, settle, sink
|
||||||
|
robber bandit, depredator, freebooter, pirate, brigand, despoiler, highwayman, plunderer, buccaneer, footpad, marauder, raider, burglar, forager, pillager, thief
|
||||||
|
royal august, kingly, majestic, princely, kinglike, magnificent, munificent, regal beggarly, contemptible, mean, poor, servile, slavish, vile
|
||||||
|
rustic agricultural, coarse, pastoral, uncouth, artless, countrified, plain, unpolished, awkward, country, rude, unsophisticated, boorish, hoidenish, rural, untaught, bucolic, inelegant, sylvan, verdant, clownish, outlandish accomplished, cultured, polished, refined, urbane, city-like, elegant, polite, urban, well-bred
|
||||||
|
sacrament ceremony, eucharist, observance, rite, solemnity, communion, Lord's Supper, ordinance, service
|
||||||
|
sagacious able, intelligent, perspicacious, sensible, acute, keen, quick of scent, sharp, apt, keen-sighted, quick-scented, sharp-witted, clear-sighted, keen-witted, rational, shrewd, discerning, judicious, sage, wise absurd, foolish, ignorant, obtuse, silly, sottish, undiscerning, dull, futile, irrational, senseless, simple, stupid, unintelligent
|
||||||
|
sale bargain, barter, change, deal, exchange, trade
|
||||||
|
sample case, exemplification, instance, example, illustration, specimen abnormality, aggregate, exception, monstrosity, total, whole
|
||||||
|
satisfy cloy, fill, sate, suffice, content, glut, satiate, surfeit check, disappoint, restrain, starve, straiten, deny, refuse, restrict, stint, tantalize
|
||||||
|
scholar disciple, learner, pupil, savant, student dunce, fool, idiot, idler, ignoramus, illiterate person
|
||||||
|
science art, knowledge
|
||||||
|
security bail, earnest, gage, pledge, surety
|
||||||
|
self-abnegation self-control, self-devotion, self-renunciation, self-denial, self-immolation, self-sacrifice self-gratification, self-indulgence, selfishness, self-seeking, self-will
|
||||||
|
send cast, despatch, emit, impel, propel, dart, discharge, fling, lance, sling, delegate, dismiss, forward, launch, throw, depute, drive, hurl, project, transmit bring, convey, give, hold, receive, carry, get, hand, keep, retain
|
||||||
|
sensation emotion, feeling, perception, sense
|
||||||
|
sensibility feeling, impressibility, sensitiveness, susceptibility coldness, deadness, hardness, insensibility, numbness, unconsciousness
|
||||||
|
severe austere, inflexible, rigorous, uncompromising, hard, morose, stern, unmitigated, harsh, relentless, stiff, unrelenting, inexorable, rigid, strict, unyielding affable, easy, gentle, lenient, pliable, sweet, tractable, bland, genial, indulgent, mild, soft, tender, yielding
|
||||||
|
shake agitate, jar, quake, shiver, totter, brandish, joggle, quaver, shudder, tremble, flap, jolt, quiver, sway, vibrate, fluctuate, jounce, reel, swing, wave, flutter, oscillate, rock, thrill, waver
|
||||||
|
shelter cover, guard, protect, shield, defend, harbor, screen, ward betray, cast out, expel, expose, give up, refuse, reject, surrender
|
||||||
|
sign emblem, mark, presage, symbol, token, indication, note, prognostic, symptom, type, manifestation, omen, signal
|
||||||
|
sin crime, fault, misdeed, vice, criminality, guilt, offense, viciousness, delinquency, ill-doing, transgression, wickedness, depravity, immorality, ungodliness, wrong, evil, iniquity, unrighteousness, wrong-doing blamelessness, goodness, integrity, rectitude, sinlessness, excellence, holiness, morality, right, uprightness, godliness, innocence, purity, righteousness, virtue
|
||||||
|
sing carol, chant, chirp, chirrup, hum, warble
|
||||||
|
skeptic agnostic, deist, doubter, infidel, unbeliever, atheist, disbeliever, freethinker believer, Christian
|
||||||
|
sketch brief, draft, outline, plan, design, drawing, picture, skeleton
|
||||||
|
skilful accomplished, apt, dexterous, happy, proficient, adept, clever, expert, ingenious, skilled, adroit, deft, handy, practised, trained awkward, clumsy, inexpert, shiftless, unskilled, untrained, bungling, helpless, maladroit, unhandy, untaught
|
||||||
|
slander asperse, decry, disparage, revile, backbite, defame, libel, traduce, calumniate, depreciate, malign, vilify defend, eulogize, extol, laud, praise, vindicate
|
||||||
|
slang cant, colloquialism, vulgarism, vulgarity
|
||||||
|
slow dawdling, dilatory, gradual, lingering, slack, delaying, drowsy, inactive, moderate, sluggish, deliberate, dull, inert, procrastinating, tardy
|
||||||
|
sneer fling, gibe, jeer, mock, scoff, taunt
|
||||||
|
socialism collectivism, communism, fabianism
|
||||||
|
sound noise, note, tone
|
||||||
|
speak announce, converse, discourse, say, articulate, declaim, enunciate, talk, chat, declare, express, tell, chatter, deliver, pronounce, utter
|
||||||
|
speech address, dissertation, oration, speaking, discourse, harangue, oratory, talk, disquisition, language, sermon, utterance hush, silence, speechlessness, stillness, taciturnity
|
||||||
|
spontaneous automatic, impulsive, involuntary, voluntary, free, instinctive, unbidden, willing
|
||||||
|
spy detective, emissary, scout
|
||||||
|
stain blot, discolor, dishonor, soil, sully, tinge, color, disgrace, dye, spot, tarnish, tint
|
||||||
|
state affirm, aver, declare, predicate, set forth, allege, avouch, depose, pronounce, specify, assert, avow, express, propound, swear, asseverate, certify, inform, protest, tell, assure, claim, maintain, say, testify contradict, controvert, disprove, gainsay, refute, retract, contravene, deny, dispute, oppose, repudiate, waive
|
||||||
|
steep abrupt, high, precipitous, sharp, sheer easy, flat, gentle, gradual, horizontal, level, low, slight
|
||||||
|
storm agitation, disturbance, tempest calm, fair weather, hush, peace, serenity, stillness, tranquillity
|
||||||
|
story account, legend, narrative, recital, relation, anecdote, myth, novel, record, tale, incident, narration annals, biography, chronicle, history, memoir
|
||||||
|
stupidity apathy, insensibility, slowness, stupefaction, dulness, obtuseness, sluggishness, stupor acuteness, brilliancy, keenness, sagacity, alertness, cleverness, quickness, sense, animation, intelligence, readiness, sensibility
|
||||||
|
stupor apathy, fainting, stupefaction, syncope, asphyxia, insensibility, swoon, torpor, coma, lethargy, swooning, unconsciousness
|
||||||
|
subsidy aid, bounty, indemnity, reward, support, allowance, gift, pension, subvention, tribute, bonus, grant, premium
|
||||||
|
subvert destroy, overthrow, ruin, supplant, extinguish, overturn, supersede, suppress conserve, keep, perpetuate, preserve, sustain, uphold
|
||||||
|
succeed achieve, attain, flourish, prevail, prosper, thrive, win be defeated, come short, fail, fall short, lose, miss, miscarry
|
||||||
|
suggestion hint, implication, innuendo, insinuation, intimation
|
||||||
|
supernatural miraculous, preternatural, superhuman common, commonplace, everyday, natural, ordinary, usual
|
||||||
|
support bear, cherish, keep, maintain, sustain, carry, hold up, keep up, prop, uphold abandon, break down, demolish, destroy, let go, throw down, betray, cast down, desert, drop, overthrow, wreck
|
||||||
|
suppose conjecture, deem, guess, imagine, surmise, think ascertain, be sure, conclude, discover, know, prove
|
||||||
|
surrender abandon, cede, give over, relinquish, alienate, give, give up, sacrifice, capitulate, give oneself up, let go, yield
|
||||||
|
synonymous alike, equivalent, like, similar, correspondent, identical, same, synonymic, corresponding, interchangeable
|
||||||
|
system manner, method, mode, order, regularity, rule chaos, derangement, disarrangement, disorder, irregularity, confusion
|
||||||
|
taciturn close, mute, reticent, speechless, dumb, reserved, silent, uncommunicative communicative, free, garrulous, loquacious, talkative, unreserved
|
||||||
|
tasteful artistic, delicate, esthetic, fastidious, nice, chaste, delicious, esthetical, fine, tasty, dainty, elegant, exquisite clumsy, displeasing, grotesque, inartistic, rough, coarse, distasteful, harsh, inharmonious, rude, deformed, fulsome, hideous, meretricious, rugged, disgusting, gaudy, horrid, offensive, tawdry
|
||||||
|
teach discipline, give instruction, inform, nurture, drill, give lessons, initiate, school, educate, inculcate, instill, train, enlighten, indoctrinate, instruct, tutor
|
||||||
|
temerity audacity, heedlessness, presumption, foolhardiness, over-confidence, rashness, hardihood, precipitancy, recklessness, hastiness, precipitation, venturesomeness care, caution, circumspection, cowardice, hesitation, timidity, wariness
|
||||||
|
term article, denomination, member, phrase, condition, expression, name, word
|
||||||
|
terse brief, concise, neat, short, compact, condensed, pithy, succinct, compendious, laconic, sententious diffuse, lengthy, long, prolix, tedious, verbose, wordy
|
||||||
|
testimony affidavit, attestation, deposition, proof, affirmation, certification, evidence, witness
|
||||||
|
therefore accordingly, consequently, then, whence, because, hence, thence, wherefore
|
||||||
|
throng concourse, crowd, host, jam, mass, multitude, press
|
||||||
|
time age, duration, epoch, period, sequence, term, date, eon, era, season, succession, while
|
||||||
|
tip cant, dip, incline, list, slope, careen, heel over, lean, slant, tilt
|
||||||
|
tire exhaust, fatigue, harass, jade, wear out, weary, fag invigorate, recreate, refresh, relax, relieve, repose, rest, restore
|
||||||
|
tool apparatus, implement, machine, utensil, appliance, instrument, mechanism, weapon
|
||||||
|
topic division, issue, motion, proposition, subject, head, matter, point, question, theme
|
||||||
|
trace footmark, impression, remains, token, trail, footprint, mark, remnant, track, vestige, footstep, memorial, sign
|
||||||
|
transact accomplish, carry on, do, perform, act, conduct, negotiate, treat
|
||||||
|
transaction act, action, affair, business, deed, doing, proceeding
|
||||||
|
transcendental a priori, intuitive, original, primordial, transcendent
|
||||||
|
transient brief, fleeting, fugitive, short, ephemeral, flitting, momentary, temporary, evanescent, flying, passing, transitory abiding, eternal, immortal, lasting, perpetual, undying, enduring, everlasting, imperishable, permanent, persistent, unfading
|
||||||
|
union coalition, conjunction, juncture, unification, combination, junction, oneness, unity analysis, decomposition, disjunction, disunion, divorce, separation, contrariety, disconnection, dissociation, division, schism, severance
|
||||||
|
usual accustomed, everyday, general, ordinary, public, common, familiar, habitual, prevailing, regular, customary, frequent, normal, prevalent, wonted exceptional, infrequent, rare, strange, unparalleled, extraordinary, out-of-the-way, singular, uncommon, unusual
|
||||||
|
utility advantage, expediency, serviceableness, avail, profit, use, benefit, service, usefulness disadvantage, futility, inadequacy, inutility, uselessness, folly, impolicy, inexpediency, unprofitableness, worthlessness
|
||||||
|
vacant blank, leisure, unfilled, untenanted, void, empty, unemployed, unoccupied, vacuous, waste brimful, busy, filled, inhabited, overflowing, brimmed, crammed, full, jammed, packed, brimming, crowded, gorged, occupied, replete
|
||||||
|
vain abortive, futile, shadowy, unsatisfying, baseless, idle, trifling, unserviceable, bootless, inconstant, trivial, unsubstantial, deceitful, ineffectual, unavailing, useless, delusive, nugatory, unimportant, vapid, empty, null, unprofitable, visionary, fruitless, profitless, unreal, worthless adequate, effective, powerful, solid, useful, advantageous, efficient, profitable, sound, valid, beneficial, expedient, real, substantial, valuable, competent, potent, serviceable, sufficient, worthy
|
||||||
|
venal hireling, mercenary, purchasable, salable disinterested, honest, incorruptible, public-spirited, unpurchasable, generous, honorable, patriotic
|
||||||
|
venerate adore, honor, respect, revere, reverence contemn, detest, dishonor, scoff at, slight, despise, disdain, disregard, scorn, spurn
|
||||||
|
veneration adoration, awe, dread, reverence contempt, disdain, dishonor, disregard, scorn
|
||||||
|
venial excusable, pardonable, slight, trivial inexcusable, inexpiable, mortal, unpardonable, unjustifiable
|
||||||
|
veracity candor, honesty, reality, truthfulness, frankness, ingenuousness, truth, verity deceit, duplicity, falsehood, fiction, lie, deception, error, falseness, guile, mendacity, delusion, fabrication, falsity, imposture, untruth
|
||||||
|
verbal literal, oral, vocal
|
||||||
|
victory achievement, conquest, success, triumph, advantage, mastery, supremacy defeat, disappointment, failure, miscarriage, retreat, destruction, disaster, frustration, overthrow, rout
|
||||||
|
vigilant alert, cautious, on the lookout, wary, awake, circumspect, sleepless, watchful, careful, on the alert, wakeful, wide-awake careless, heedless, inconsiderate, oblivious, drowsy, inattentive, neglectful, thoughtless, dull, incautious, negligent, unwary
|
||||||
|
virtue chastity, honesty, probity, truth, duty, honor, purity, uprightness, excellence, integrity, rectitude, virtuousness, faithfulness, justice, righteousness, worth, goodness, morality, rightness, worthiness evil, vice, viciousness, wickedness, wrong
|
||||||
|
wander deviate, diverge, go astray, range, rove, swerve, digress, err, ramble, roam, stray, veer
|
||||||
|
way alley, course, lane, path, route, avenue, driveway, pass, pathway, street, bridle-path, highroad, passage, road, thoroughfare, channel, highway, passageway, roadway, track
|
||||||
|
wisdom attainment, insight, prudence, depth, judgment, reason, discernment, judiciousness, reasonableness, discretion, knowledge, sagacity, enlightenment, learning, sense, erudition, prescience, skill, foresight, profundity, understanding, information absurdity, folly, imbecility, miscalculation, senselessness, error, foolishness, imprudence, misjudgment, silliness, fatuity, idiocy, indiscretion, nonsense, stupidity
|
||||||
|
wit banter, fun, joke, waggery, burlesque, humor, playfulness, waggishness, drollery, jest, pleasantry, witticism, facetiousness, jocularity, raillery dulness, seriousness, sobriety, solemnity, stolidity, stupidity, gravity
|
||||||
|
work achievement, doing, labor, product, action, drudgery, occupation, production, business, employment, performance, toil, deed, exertion ease, idleness, leisure, recreation, relaxation, repose, rest, vacation
|
||||||
|
yet besides, further, hitherto, now, still, thus far
|
||||||
|
youthful adolescent, callow, childlike, immature, puerile, boyish, childish, girlish, juvenile, young
|
Can't render this file because it contains an unexpected character in line 70 and column 165.
|
376
samples/Sample_TextGame/gamedata/riddles_enc.csv
Normal file
376
samples/Sample_TextGame/gamedata/riddles_enc.csv
Normal file
@ -0,0 +1,376 @@
|
|||||||
|
"Jvgu guvrirf V pbafbeg, Jvgu gur Ivyrfg, va fubeg, V'z dhvgr ng rnfr va qrcenivgl, Lrg nyy qvivarf hfr zr, Naq fninagf pna'g ybfr zr, Sbe V nz gur pragre bs tenivgl.",I
|
||||||
|
"V zbir jvgubhg jvatf, Orgjrra fvyxra fgevat, V yrnir nf lbh svaq, Zl fhofgnapr oruvaq.",Fcvqre
|
||||||
|
"Jung syvrf sberire, Erfgf arire?",Jvaq
|
||||||
|
"V nccrne va gur zbeavat. Ohg nz nyjnlf gurer. Lbh pna arire frr zr. Gubhtu V nz rireljurer. Ol avtug V nz tbar, gubhtu V fbzrgvzrf arire jnf. Abguvat pna qrsrng zr. Ohg V nz rnfvyl tbar.",Fhayvtug
|
||||||
|
"V penjy ba gur rnegu. Naq evfr ba n cvyyne.",Funqbj
|
||||||
|
"Gurl ner znal naq bar, gurl jnir naq gurl qehz, Hfrq gb pbire n fgngr, gurl tb jvgu lbh rireljurer.",Unaqf
|
||||||
|
"Jung zhfg or va gur bira lrg pna abg or onxrq? Tebjf va gur urng lrg fuhaf gur yvtug bs qnl? Jung fvaxf va jngre ohg evfrf jvgu nve? Ybbxf yvxr fxva ohg vf svar nf unve?",Lrnfg
|
||||||
|
"V unir ubyrf ba gur gbc naq obggbz. V unir ubyrf ba zl yrsg naq ba zl evtug. Naq V unir ubyrf va gur zvqqyr, Lrg V fgvyy ubyq jngre.",Fcbatr
|
||||||
|
"Jung pna or fjnyybjrq, Ohg pna nyfb fjnyybj lbh?",Cevqr
|
||||||
|
"Lbh trg znal bs zr, ohg arire rabhtu. Nsgre gur ynfg bar, lbhe yvsr fbba jvyy fahss. Lbh znl unir bar bs zr ohg bar qnl n lrne, Jura gur ynfg bar vf tbar, lbhe yvsr qvfnccrnef.",Oveguqnl
|
||||||
|
"V eha nebhaq gur pvgl, ohg V arire zbir.",Jnyy
|
||||||
|
"Nf n jubyr, V nz obgu fnsr naq frpher. Orurnq zr, V orpbzr n cynpr bs zrrgvat. Orurnq zr ntnva, V nz gur cnegare bs ernql. Erfgber zr, V orpbzr gur qbznva bs ornfgf.",Fgnoyr
|
||||||
|
"Gjb ubefrf, fjvsgrfg geniryvat, unearffrq va n cnve, naq tenmvat rire va cynprf. Qvfgnag sebz gurz.",Rlrf
|
||||||
|
"Ng gur fbhaq bs zr, zra znl qernz. Be fgnzc gurve srrg. Ng gur fbhaq bs zr, jbzra znl ynhtu. Be fbzrgvzrf jrrc.",Zhfvp
|
||||||
|
"Gb haeniry zr lbh arrq n fvzcyr xrl, ab xrl gung jnf znqr ol ybpxfzvgu'f unaq. Ohg n xrl gung bayl V jvyy haqrefgnaq.",Evqqyr
|
||||||
|
"Ybat naq guvax, erq jvguva, jvgu n anvy ng gur raq.",Svatre
|
||||||
|
"V'z fbzrgvzrf juvgr naq nyjnlf jebat. V pna oernx n urneg naq uheg gur fgebat. V pna ohvyq ybir be grne vg qbja. V pna znxr n fzvyr be oevat n sebja.",Yvr
|
||||||
|
"Lbh pna ghzoyr va vg, ebyy va vg, ohea vg, navzny rng vg. Hfrq gb pbire sybbef, fgvyy hfrq orlbaq fgnyy qbbef. Serfuraf jungrire vg vf cynprq ba. Nofbeof jungrire vf cbherq vagb vg.",Unl
|
||||||
|
"V pbzr va jvagre. V pnaabg frr, urne, be srry. V pna'g rng, Ohg lbh pna rng cnegf bs zr.",Fabjzna
|
||||||
|
"Fbzrgvzrf V nz ybhq. Naq ivrjrq jvgu qvfgnfgr. Cbxr bhg zl 'rlr', gura V'z ba gur sebag bs lbhe snpr.",Abvfr
|
||||||
|
"Jung vf vg gung unf sbhe yrtf, bar urnq, naq n sbbg?",Orq
|
||||||
|
"Jung znxrf n ybhq abvfr jura punatvat vgf wnpxrg. Orpbzrf ynetre ohg jrvtuf yrff?",Cbcpbea
|
||||||
|
"V nz nyjnlf uhatel, V zhfg nyjnlf or srq. Gur svatre V yvpx jvyy fbba ghea erq.",Sver
|
||||||
|
"Fbzrguvat jubyyl haerny, lrg frrzf erny gb V. Guvax zl sevraq, gryy zr jurer qbrf vg yvr?",Zvaq
|
||||||
|
"Ab znggre ubj yvggyr be ubj zhpu lbh hfr zr, lbh punatr zr rirel zbagu.",Pnyraqne
|
||||||
|
"Jung pna ohea gur rlrf, fgvat gur zbhgu, lrg or pbafhzrq?",Fnyg
|
||||||
|
"Jung na svyy n ebbz ohg gnxrf hc ab fcnpr?",Yvtug
|
||||||
|
"Vg bpphef bapr va rirel zvahgr. Gjvpr va rirel zbzrag naq lrg arire va bar uhaqerq gubhfnaq lrnef.",Z
|
||||||
|
"Jvgu cbvagrq snatf vg fvgf va jnvg. Jvgu cvrepvat sbepr vg qbyrf bhg sngr, bire oybbqyrff ivpgvzf cebpynvzvat vgf zvtug. Rgreanyyl wbvavat va n fvatyr ovgr.",Fgncyre
|
||||||
|
"Vg ubyqf zbfg xabjyrqtr gung unf rire orra fnvq. Ohg vf abg gur oenva, vf abg gur urnq. Gb srnguref naq gurve znfgref, vg'f obgu onar naq obba. Bar rzcgl, naq bar shyy.",Cncre
|
||||||
|
"Hcba zr lbh pna gernq, gubhtu fbsgyl haqre pbire. Naq V jvyy gnxr lbh cynprf, gung lbh unir lrg gb qvfpbire. V'z uvtu, naq V'z ybj, gubhtu syng va gur zvqqyr. Naq gubhtu n wbl gb gur puvyqera, nqhygf guvax bs zr yvggyr.",Fgnvef
|
||||||
|
"N zvyr sebz raq gb raq, lrg nf pybfr gb nf n sevraq. N cerpvbhf pbzzbqvgl, serryl tvira. Frra ba gur qrnq naq ba gur yvivat. Sbhaq ba gur evpu, cbbe, fubeg naq gnyy. Ohg funerq nzbat puvyqera zbfg bs nyy.",Fzvyr
|
||||||
|
"V unir n uhaqerq yrtf, ohg pnaabg fgnaq. V unir n ybat arpx, ohg ab urnq. V pnaabg frr. V'z arng naq gvql nf pna or.",Oebbz
|
||||||
|
"Syng nf n yrns, ebhaq nf n evat. Unf gjb rlrf, pna'g frr n guvat.",Ohggba
|
||||||
|
"V qba'g guvax be rng be fyhzore. Be zbir nebhaq be srne guhaqre. Whfg yvxr lbh V ybbx gur fnzr ohg V pna'g unez lbh be or lbhe onar.",Qbyy
|
||||||
|
"Va zneoyr unyyf nf juvgr nf zvyx, yvarq jvgu n fxva nf fbsg nf fvyx. Jvguva n sbhagnva pelfgny-pyrne. N tbyqra nccyr qbgu nccrne. Ab qbbef gurer ner gb guvf fgebatubyq, lrg guvrirf oernx va naq fgrny gur tbyq.",Rtt
|
||||||
|
"Jung vf vg gung lbh zhfg tvir orsber lbh pna xrrc vg.",Jbeq
|
||||||
|
"V qvt bhg gval pnirf naq fgber tbyq naq fvyire va gurz. V nyfb ohvyq oevqtrf bs fvyire naq znxr pebjaf bs tbyq. Gurl ner gur fznyyrfg lbh pbhyq vzntvar. Fbbare be yngre rirelobql arrqf zl uryc. Lrg znal crbcyr ner nsenvq gb yrg zr uryc gurz.",Qragvfg
|
||||||
|
"Jung vf ybat naq fyvz, jbexf va yvtug. Unf ohg bar rlr, naq na njshy ovgr?",Arrqyr
|
||||||
|
"Jung yvrf va n ghaary bs qnexarff. Gung pna bayl nggnpx jura chyyrq onpx?",Ohyyrg
|
||||||
|
"Jung unf fvk snprf naq gjragl-bar rlrf?",Qvr
|
||||||
|
"Hagvy V nz zrnfherq. V nz abg xabja, lrg ubj lbh zvff zr jura V unir sybja.",Gvzr
|
||||||
|
"Guerr yvirf unir V. Tragyr rabhtu gb fbbgur gur fxva. Yvtug rabhtu gb pnerff gur fxl. Uneq rabhtu gb penpx ebpxf.",Jngre
|
||||||
|
"V jrne n erq ebor, jvgu fgnss va unaq, naq n fgbar va zl guebng.",Pureel
|
||||||
|
"N jneevbe nzbatfg gur sybjref, ur ornef n guehfgvat fjbeq. Ur hfrf vg jurarire ur zhfg, gb qrsraq uvf tbyqra ubneq.",Orr
|
||||||
|
"V uvqr ohg zl urnq vf bhgfvqr.",Anvy
|
||||||
|
"N ubhfr shyy, n lneq shyy, n puvzarl shyy, ab bar pna trg n fcbbashy.",Fzbxr
|
||||||
|
"Lbh pna fcva, jurry naq gjvfg. Ohg guvf guvat pna ghea jvgubhg zbivat.",Zvyx
|
||||||
|
"Unyb bs jngre, gbathr bs jbbq. Fxva bs fgbar, ybat V'ir fgbbq. Zl svatref fubeg ernpu gb gur fxl. Vafvqr zl urneg zra yvir naq qvr.",Pnfgyr
|
||||||
|
"Jura gurl ner pnhtug, gurl ner guebja njnl. Jura gurl rfpncr, lbh vgpu nyy qnl.",Syrnf
|
||||||
|
"Jung qbrf zna ybir zber guna yvsr, srne zber guna qrngu be zbegny fgevsr. Jung gur cbbe unir, gur evpu erdhver, naq jung pbagragrq zra qrfver. Jung gur zvfre fcraqf, naq gur fcraqguevsg fnirf. Naq nyy zra pneel gb gurve tenirf.",Abguvat
|
||||||
|
"Va jr tb, bhg jr tb. Nyy nebhaq naq va n ebj. Nyjnlf, nyjnlf fgrnql sybj. Jura jr'yy fgbc, lbh'yy arire xabja. Va jr tb, bhg jr tb.",Gvqrf
|
||||||
|
"N pybhq jnf zl zbgure, gur jvaq vf zl sngure. Zl fba vf gur pbby fgernz, naq zl qnhtugre vf gur sehvg bs gur ynaq. N envaobj vf zl orq, gur rnegu zl svany erfgvat cynpr. Naq V'z gur gbezrag bs zna.",Enva
|
||||||
|
"Obea bs rnegu, ohg jvgu abar bs vgf fgeratgu. Zbyqrq ol synzr, ohg jvgu abar bs vgf cbjre. Funcrq",Tynff
|
||||||
|
"Erzbir gur bhgfvqr. Pbbx gur vafvqr. Rng gur bhgfvqr. Guebj njnl gur vafvqr.",Pbea
|
||||||
|
"Guvf vf va n ernyz bs gehr naq va n ernyz snyfr, ohg lbh rkcrevrapr zr nf lbh ghea naq gbff.",Qernz
|
||||||
|
"Gurer vf na napvrag vairagvba. Fgvyy hfrq va fbzr cnegf bs gur jbeyq gbqnl. Gung nyybjf crbcyr gb frr guebhtu jnyyf.",Jvaqbj
|
||||||
|
"Fbzr yvir va zr, fbzr yvir ba. Naq fbzr funir zr gb fgevqr hcba. V eneryl yrnir zl angvir ynaq. Hagvy zl qrngu V nyjnlf fgnaq. Uvtu naq ybj V znl or sbhaq. Obgu nobir naq orybj tebhaq.",Gerr
|
||||||
|
"Zrgny be obar V znl or, znal grrgu V unir naq nyjnlf onerq. Lrg zl ovgr unezf ab bar. Naq ynqvrf qryvtug va zl gbhpu.",Pbzo
|
||||||
|
"V nz n sver'f orfg sevraq. Jura sng, zl obql svyyf jvgu jvaq. Jura chfurq gb guva, guebhtu zl abfr V oybj. Gura lbh pna jngpu gur rzoref tybj.",Oryybjf
|
||||||
|
"Rirel qnja ortvaf jvgu zr. Ng qhfx V'yy or gur svefg lbh frr, naq qnloernx pbhyqa'g pbzr jvgubhg. Jung zvqqnl pragref nyy nobhg. Qnvfrf tebj sebz zr, V'z gbyq. Naq jura V pbzr, V raq nyy pbqr, ohg va gur fha V jba'g or sbhaq. Lrg fgvyy, rnpu qnl V'yy or nebhaq.",Q
|
||||||
|
"Lbh urneg vg fcrnx, sbe vg unf n uneq gbathr. Ohg vg pnaabg oerngur, sbe vg unf abg n yhat.",Oryy
|
||||||
|
"V phg guebhtu rivy yvxr n qbhoyr rqtrq fjbeq, naq punbf syrrf ng zl nccebnpu. Onynapr V fvatyr-unaqrqyl hcenvfr, guebhtu onggyrf sbhtug jvgu urneg naq zvaq, vafgrnq bs jvgu zl tnmr.",Whfgvpr
|
||||||
|
"Gur rvtug bs hf zbir sbegu naq onpx. Gb cebgrpg bhe xvat sebz gur sbrf nggnpx.",Cnjaf
|
||||||
|
"Ur unf bar naq n crefba unf gjb. N pvgvmra unf guerr. Naq n uhzna orvat unf sbhe. N crefbanyvgl unf svir. Naq na vaunovgnag bs rnegu unf fvk.",Flyynoyr
|
||||||
|
"Vs lbh oernx zr, V qb abg fgbc jbexvat. Vs lbh gbhpu zr, V znl or fanerq. Vs lbh ybfr zr, abguvat jvyy znggre.",Urneg
|
||||||
|
"Jung'f va gur zvqqyr bs abjurer?",U
|
||||||
|
"Jung sbepr naq fgeratgu pnaabg trg guebhtu. V, jvgu n tragyr gbhpu, pna qb. Znal va gur fgerrg jbhyq fgnaq. Jrer V abg n sevraq ng unaq.",Xrl
|
||||||
|
"Bsgra uryq ohg arire gbhpurq. Nyjnlf jrg ohg arire ehfgf. Bsgra ovgf ohg fryqbz ovg. Gb hfr vg jryy lbh zhfg unir jvg.",Gbathr
|
||||||
|
"Nf ebhaq nf na nccyr. Nf qrrc nf n phc. Nyy gur xvat'f ubefrf pna'g chyy vg hc.",Jryy
|
||||||
|
"Ur fgnaqf orfvqr gur ebnq. Va n checyr pnc ng gnggrerq terra pybnx. Gubfr jub gbhpu uvz, phefr uvz.",Guvfgyr
|
||||||
|
"Cbjre rabhtu gb fznfu fuvcf naq pehfu ebbsf. Lrg vg fgvyy zhfg srne gur fha.",Vpr
|
||||||
|
"Jung fheebhaqf gur jbeyq, lrg qjryyf jvguva n guvzoyr?",Fcnpr
|
||||||
|
"V pnaabg or bgure guna jung V nz, hagvy gur zna jub znqr zr qvrf. Cbjre naq tybel jvyy snyy gb zr svanyyl. Bayl jura ur ynfg pybfrf uvf rlrf.",Cevapr
|
||||||
|
"Jung vf vg gung znxrf grnef jvgubhg fbeebj. Naq gnxrf vgf wbhearl gb urnira?",Fzbxr
|
||||||
|
"Vafvqr n terng oyhr pnfgyr yvirf n ful lbhat znvq. Fur oyhfurf va gur zbeavat naq pbzrf abg bhg ng avtug.",Fha
|
||||||
|
"Guvf guvat ehaf ohg pnaabg jnyx, fbzrgvzrf fvatf ohg arire gnyxf. Ynpxf nezf, unf unaqf; ynpxf n urnq ohg unf n snpr.",Pybpx
|
||||||
|
"N jbeq V xabj, fvk yrggref vg pbagnvaf. Fhogenpg whfg bar naq gjryir erznvaf.",Qbmraf
|
||||||
|
"V tb va uneq naq qel. V pbzr bhg fbsg naq fgvpxl. Lbh pna oybj zr.",Thz
|
||||||
|
"V nz gur lryybj urz bs gur frn'f oyhr fxveg.",Ornpu
|
||||||
|
"N fxva unir V, zber rlrf guna bar. V pna or irel avpr jura V nz qbar.",Cbgngb
|
||||||
|
"V unir sbhe yrtf ohg ab gnvy. Hfhnyyl V nz urneq bayl ng avtug.",Sebt
|
||||||
|
"N gval ornq, yvxr sentvyr tynff, fgehat nybat n pbeq bs tenff.",Qrj
|
||||||
|
"Oernx vg naq vg vf orggre, vzzrqvngryl frg naq uneqre gb oernx ntnva.",Erpbeq
|
||||||
|
"Rnpu zbeavat V nccrne gb yvr ng lbhe srrg, nyy qnl V sbyybj ab znggre ubj snfg lbh eha. Lrg V arneyl crevfu va gur zvqqnl fha.",Funqbj
|
||||||
|
"Jung qb lbh guebj bhg gb hfr naq gnxr va jura lbh'er qbar?",Napube
|
||||||
|
"Jung vf vg juvpu ohvyqf guvatf hc? Ynlf zbhagnvaf ybj? Qevrf hc ynxrf, naq znxrf guvatf tebj? Pnerf abg n juvz nobhg lbhe cnffvat? Naq vf yvxr srj bgure guvatf, orpnhfr vg vf rireynfgvat?",Gvzr
|
||||||
|
"V nz gur sbhagnva sebz juvpu ab bar pna qevax. Sbe znal V nz pbafvqrerq n arprffnel yvax. Yvxr tbyq gb nyy V nz fbhtug sbe, ohg zl pbagvahrq qrngu oevatf jrnygu sbe nyy gb jnag zber.",Bvy
|
||||||
|
"Fyrrcvat qhevat gur qnl, V uvqr njnl. Jngpushy guebhtu gur avtug, V bcra ng qnja'f yvtug. Ohg bayl sbe gur oevrsrfg gvzr, qb V fuvar. Naq gura V uvqr njnl. Naq fyrrc guebhtu gur qnl.",Fhaevfr
|
||||||
|
"N frrq nz V, guerr yrggref znxr zl anzr. Gnxr njnl gjb naq V fgvyy fbhaq gur fnzr.",Crn
|
||||||
|
"Va gur zvqqyr bs avtug, V fheebhaq gur tbat. Va gur zvqqyr bs fvtug, V raq gur fbat.",T
|
||||||
|
"Ybbx vagb zl snpr naq V'z rirelobql. Fpengpu zl onpx naq V'z abobql.",Zveebe
|
||||||
|
"Gjb oebguref jr ner, terng oheqraf jr orne. Nyy qnl jr ner ovggreyl cerffrq. Lrg guvf V jvyy fnl, jr ner shyy nyy gur qnl, naq rzcgl jura tb gb erfg.",Obbgf
|
||||||
|
"Gurl pna or uneoberq, ohg srj ubyq jngre. Lbh pna ahefr gurz, ohg bayl ol ubyqvat gurz ntnvafg fbzrbar ryfr. Lbh pna pneel gurz, ohg abg jvgu lbhe nezf. Lbh pna ohel gurz, ohg abg va gur rnegu.",Tehqtr
|
||||||
|
"Jung vf vg gung jnf tvira gb lbh, orybatf bayl gb lbh. Naq lrg lbhe sevraqf hfr vg zber guna lbh qb?",Anzr
|
||||||
|
"Ol Zbba be ol Fha, V funyy or sbhaq. Lrg V nz haqbar, vs gurer'f ab yvtug nebhaq.",Funqbj
|
||||||
|
"Jung qb lbh hfr gb ubr n ebj, fynl n sbr, naq jevat jvgu jbr?",Unaqf
|
||||||
|
"Jr geniry zhpu, lrg cevfbaref ner, naq pybfr pbasvarq gb obbg. Lrg jvgu nal ubefr, jr jvyy xrrc gur cnpr, naq jvyy nyjnlf tb ba sbbg.",Fchef
|
||||||
|
"Jvgubhg n oevqyr, be n fnqqyr, npebff n guvat V evqr n-fgenqqyr. Naq gubfr V evqr, ol uryc bs zr, gubhtu nyzbfg oyvaq, ner znqr gb frr.",Tynffrf
|
||||||
|
"V syl guebhtu gur nve ba fznyy srngurerq jvatf, frrxvat bhg yvsr naq qrfgeblvat nyy guvatf.",Neebj
|
||||||
|
"V nz gur erq gbathr bs gur rnegu, gung ohevrf pvgvrf.",Ynin
|
||||||
|
"V ybbx ng lbh, lbh ybbx ng zr, V envfr zl evtug, lbh envfr lbhe yrsg.",Zveebe
|
||||||
|
"Jung vf gur guvat juvpu, bapr cbherq bhg, pnaabg or tngurerq ntnva?",Enva
|
||||||
|
"Vg vf n cneg bs hf, naq gura ercynprq. Vg rfpncrf bhg obqvrf, gb n orggre cynpr. Gur jbeyq orpbzrf vgf fvmrnoyr ubzr. Vgf cnffvbaf haerfgenvag, gur cynarg vg ebnzf.",Jngre
|
||||||
|
"Jung jbeq fgnegf jvgu 'R', raqf jvgu 'R', ohg bayl unf bar yrggre? Vg vf abg gur yrggre 'R'.",Rairybcr
|
||||||
|
"N ubyr va n cbyr, gubhtu V svyy n ubyr va juvgr. V'z hfrq zber ol gur qnl, naq yrff ol gur avtug.",Rlr
|
||||||
|
"V syl, lrg V unir ab jvatf. V pel, lrg V unir ab rlrf. Qnexarff sbyybjf zr. Ybjre yvtug V arire frr.",Pybhq
|
||||||
|
"V'z shyy bs ubyrf, lrg V'z shyy bs jngre.",Fcbatr
|
||||||
|
"Ybat naq fyvaxl yvxr n gebhg, arire fvatf gvyy vg'f thgf pbzr bhg.",Tha
|
||||||
|
"Jung navzny xrrcf gur orfg gvzr?",Jngpuqbt
|
||||||
|
"Jung xvaq bs ebbz unf ab jvaqbjf be qbbef?",Zhfuebbz
|
||||||
|
"V unir yrtf ohg jnyx abg, n fgebat onpx ohg jbex abg. Gjb tbbq nezf ohg ernpu abg. N frng ohg fvg naq gneel abg.",Punve
|
||||||
|
"Vg'f va lbhe unaq gubhtu lbh pna abg srry vg. Bayl lbh naq gvzr pna erirny vg.",Sngr
|
||||||
|
"Abg obea, ohg sebz n Zbgure'f obql qenja. V unat hagvy unys bs zr vf tbar. V fyrrc va n pnir hagvy V tebj byq. Gura inyhrq sbe zl uneqrarq tbyq.",Purrfr
|
||||||
|
"V nz gur bhgfgergpurq svatref gung frvmr naq ubyq gur jvaq. Jvfqbz sybjf sebz zr va bgure unaqf. Hcba zr ner fjrrg qernzf qernzg, zl zrerfg gbhpu oevatf ynhtugre.",Srngure
|
||||||
|
"Unaqf fur unf ohg qbrf abg ubyq. Grrgu fur unf ohg qbrf abg ovgr. Srrg fur unf ohg gurl ner pbyq. Rlrf fur unf ohg jvgubhg fvtug.",Qbyy
|
||||||
|
"Bayl gjb onpxobarf naq gubhfnaqf bs evof.",Envyebnq
|
||||||
|
"Uneq veba ba ubefr. Pbj'f uvqr ba zna.",Fubr
|
||||||
|
"Jung jbeq vf gur fnzr jevggra sbejneq, onpxjneq naq hcfvqr qbja?",Abba
|
||||||
|
"V pnaabg or sryg, frra be gbhpurq. Lrg V pna or sbhaq va rirelobql. Zl rkvfgrapr vf nyjnlf va qrongr. Lrg V unir zl bja fglyr bs zhfvp.",Fbhy
|
||||||
|
"V nz frra va gur jngre. Vs frra va gur fxl, V nz va gur envaobj, n wnl'f srngure, naq yncvf ynmhyv.",Oyhr
|
||||||
|
"Lbh hfr vg orgjrra lbhe urnq naq lbhe gbrf, gur zber vg jbexf gur guvaare vg tebjf.",Fbnc
|
||||||
|
"Sngureyrff naq zbgureyrff. Obea jvgubhg fva, ebnerq jura vg pnzr vagb gur jbeyq. Naq arire fcbxr ntnva.",Guhaqre
|
||||||
|
"Jurer pna lbh svaq ebnqf jvgubhg pnef, sberfgf jvgubhg gerrf naq pvgvrf jvgubhg ubhfrf?",Znc
|
||||||
|
"N yrngurel fanxr, jvgu n fgvatvat ovgr. V'yy fgnl pbvyrq hc, hayrff V zhfg svtug.",Juvc
|
||||||
|
"Gnxr bar bhg naq fpengpu zl urnq, V nz abj oynpx ohg bapr jnf erq.",Zngpu
|
||||||
|
"Zbhagnvaf jvyy pehzoyr naq grzcyrf jvyy snyy. Naq ab zna pna fheivir vgf raqyrff pnyy.",Gvzr
|
||||||
|
"Jung unf jvatf, ohg pna abg syl. Vf rapybfrq, ohg pna bhgfvqr nyfb yvr. Pna bcra vgfrys hc, be pybfr vgfrys njnl. Vf gur cynpr bs xvatf naq dhrraf naq qbttrery bs rirel zrnaf. Jung vf vg hcba juvpu V fgnaq? Juvpu pna yrnq hf gb qvssrerag ynaqf.",Fgntr
|
||||||
|
"V'z gur fbhepr bs nyy rzbgvba, ohg V'z pntrq va n juvgr cevfba.",Urneg
|
||||||
|
"V nz gur gbby, sbe vafcvevat znal. Ohl zr va gur fgber, sbe abg zhpu zber guna n craal. Qba'g birehfr zr, be zl hfrshyarff jvyy tb.",Cra
|
||||||
|
"Jung tbrf guebhtu n qbbe ohg arire tbrf va. Naq arire pbzrf bhg?",Xrlubyr
|
||||||
|
"Jung tbrf hc jura gur enva pbzrf qbja?",Hzoeryyn
|
||||||
|
"V bpphe gjvpr va rgreavgl. Naq V'z nyjnlf jvguva fvtug.",G
|
||||||
|
"Gjvtf naq fcurerf naq cbyrf naq cyngrf. Wbva naq ovaq gb ernfba znxr.",Fxryrgba
|
||||||
|
"Gur fha onxrf gurz, gur unaq oernxf gurz, gur sbbg gernqf ba gurz, naq gur zbhgu gnfgrf gurz.",Tencrf
|
||||||
|
"V unir znal srnguref gb uryc zr syl. V unir n obql naq urnq, ohg V'z abg nyvir. Vg vf lbhe fgeratgu juvpu qrgrezvarf ubj sne V tb. Lbh pna ubyq zr va lbhe unaq, ohg V'z arire guebja.",Neebj
|
||||||
|
"Jung'f oynpx jura lbh trg vg, erq jura lbh hfr vg, naq juvgr jura lbh'er nyy guebhtu jvgu vg?",Punepbny
|
||||||
|
"Jung unf sbhe yrtf va gur zbeavat, gjb yrtf va gur nsgreabba, naq guerr yrtf va gur riravat?",Zna
|
||||||
|
"Gnxr bss zl fxva, V jba'g pel, ohg lbh jvyy.",Bavba
|
||||||
|
"Ubyq gur gnvy, juvyr V svfu sbe lbh.",Arg
|
||||||
|
"V nz fb fvzcyr gung V pna bayl cbvag. Lrg V thvqr zra nyy bire gur jbeyq.",Pbzcnff
|
||||||
|
"Veba ebbs, tynff jnyyf, oheaf naq oheaf naq arire snyyf.",Ynagrea
|
||||||
|
"Yngr nsgreabbaf V bsgra ongur. V'yy fbnx va jngre cvcvat ubg. Zl rffrapr tbrf guebhtu. Zl frr guebhtu pybgurf. Hfrq hc nz V - V'ir tbar gb cbg.",Grnont
|
||||||
|
"Jung pna'g lbh frr, urne be srry, hagvy vgf gbb yngr. Jung funqbjf ybir, naq fubcxrrcref ungr?",Guvrs
|
||||||
|
"Jung pna oevat onpx gur qrnq. Znxr hf pel, znxr hf ynhtu, znxr hf lbhat. Obea va na vafgnag lrg ynfgf n yvsr gvzr?",Zrzbel
|
||||||
|
"V unir n arpx ohg ab urnq. V unir n obql ohg ab nez. V unir n obggbz ohg ab yrt.",Obggyr
|
||||||
|
"N gubhfnaq pbyberq sbyqf fgergpu gbjneq gur fxl. Ngbc n graqre fgenaq, evfvat sebz gur ynaq, hagvy xvyyrq ol znvqra'f unaq. Creuncf n gbxra bs ybir, creuncf gb fnl tbbqolr.",Sybjre
|
||||||
|
"Tbyq va n yrngure ont, fjvatvat ba n gerr, zbarl nsgre ubarl va vgf gvzr. Vyyf bs n fpheil perj pherq ol gur frn, ernfba va vgf frnfba ohg ab eulzr.",Benatr
|
||||||
|
"N fybj, fbyrza fdhner-qnapr bs jneevbef srvagvat. Bar ol bar gurl snyy, jneevbef snvagvat, guvegl-gjb ba fvkgl-sbhe.",Purff
|
||||||
|
"Ur unf zneevrq znal jbzra ohg unf arire zneevrq.",Cevrfg
|
||||||
|
"Va lbhe sver lbh urne zr fpernz, pernxvat naq juvavat, lrg V nz qrnq orsber lbh ynl zr va lbhe urnegu.",Ybt
|
||||||
|
"V jrnxra nyy zra sbe ubhef rnpu qnl. V fubj lbh fgenatr ivfvbaf juvyr lbh ner njnl. V gnxr lbh ol avtug, ol qnl gnxr lbh onpx. Abar fhssre gb unir zr, ohg qb sebz zl ynpx.",Fyrrc
|
||||||
|
"V fnj n fgenatr perngher. Ybat, uneq, naq fgenvtug, guehfgvat vagb n ebhaq, qnex bcravat. Cercnevat gb qvfpunetr vgf ybnq bs yvirf. Chssvat naq fdhrnyvat abvfrf nppbzcnavrq vg, gura n svany fperrpu nf vg fybjrq naq fgbccrq.",Genva
|
||||||
|
"Ynetr nf n zbhagnva, fznyy nf n crn, raqyrffyl fjvzzvat va n jngreyrff frn.",Nfgrebvq
|
||||||
|
"V qb abg oerngur, ohg V eha naq whzc. V qb abg rng, ohg V fjvz naq fgergpu. V qb abg qevax, ohg V fyrrc naq fgnaq. V qb abg guvax, ohg V tebj naq cynl. V qb abg frr, ohg lbh frr zr rirelqnl.",Yrt
|
||||||
|
"Jura yvdhvq fcynfurf zr, abar frrcf guebhtu. Jura V nz zbirq n ybg, yvdhvq V fcrj. Jura V nz uvg, pbybe V punatr. Naq pbybe, V pbzr va dhvgr n enatr. Jung V pbire vf irel pbzcyrk, naq V nz irel rnfl gb syrk.",Fxva
|
||||||
|
"Tvir vg sbbq naq vg jvyy yvir, tvir vg jngre naq vg jvyy qvr.",Sver
|
||||||
|
"N ahg penpxre hc va n gerr.",Fdhveery
|
||||||
|
"Jung unccraf rirel frpbaq, zvahgr, zbagu, naq praghel. Ohg abg rirel ubhe, jrrx, lrne, be qrpnqr?",A
|
||||||
|
"Vg unf ab gbc be obggbz, ohg vg pna ubyq syrfu, obarf, naq oybbq nyy ng gur fnzr gvzr.",Evat
|
||||||
|
"V nz serr sbe gur gnxvat. Guebhtu nyy bs lbhe yvsr, gubhtu tvira ohg bapr ng ovegu. V nz yrff guna abguvat va jrvtug, ohg jvyy sryy gur fgebatrfg bs lbh vs uryq.",Oerngu
|
||||||
|
"Zl svefg vf va oybbq naq nyfb va onggyr. Zl frpbaq vf va npbea, bnx, naq nccyr. Zl guveq naq sbhegu ner obgu gur fnzr. Va gur pragre bs fbeebj naq gjvpr va ersenva. Zl svsgu fgnegf rgreavgl raqvat urer. Zl ynfg vf gur svefg bs ynfg, Bu Qrne.",Oneery
|
||||||
|
"Jura V'z zrgny be jbbq, V uryc lbh trg ubzr. Jura V'z syrfu naq V'z oybbq. Va gur qnexarff V ebnz.",Ong
|
||||||
|
"V znepu orsber nezvrf, n gubhfnaq fnyhgr zr. Zl snyy pna oevat ivpgbel, ohg ab bar jbhyq fubbg zr. Gur jvaq vf zl ybire, bar-yrttrq nz V. Anzr zr naq frr zr ng ubzr va gur fxl.",Synt
|
||||||
|
"Gbby bs guvrs, gbl bs dhrra. Nyjnlf hfrq gb or hafrra. Fvta bs wbl, fvta bs fbeebj. Tvivat nyy yvxrarff obeebjrq.",Znfx
|
||||||
|
"Jung svir-yrggre jbeq orpbzrf fubegre jura lbh nqq gjb zber yrggref?",Fubeg
|
||||||
|
"Jung vf cebabhaprq yvxr bar yrggre, jevggra jvgu guerr yrggref. Naq orybatf gb nyy navznyf?",Rlr
|
||||||
|
"Jung vf vg gung tvira bar, lbh'yy unir rvgure gjb be abar?",Pubvpr
|
||||||
|
"Vg vf terngre guna Tbq naq zber rivy guna gur qrivy. Gur cbbe unir vg, gur evpu arrq vg, naq vs lbh rng vg lbh'yy qvr.",Abguvat
|
||||||
|
"Jung trgf ovttre gur zber lbh gnxr njnl sebz vg?",Ubyr
|
||||||
|
"Gur zber bs vg gurer vf, gur yrff lbh frr.",Qnexarff
|
||||||
|
"Gb pebff gur jngre V'z gur jnl, sbe jngre V'z nobir. V gbhpu vg abg naq, gehgu gb fnl, V arvgure fjvz abe zbir.",Oevqtr
|
||||||
|
"Nf ornhgvshy nf gur frggvat fha, nf qryvpngr nf gur zbeavat qrj. Na natry'f qhfgvat sebz gur fgnef. Gung pna ghea gur Rnegu vagb n sebfgrq zbba.",Fabj
|
||||||
|
"Jura frg ybbfr V syl njnl. Arire fb phefrq nf jura V tb nfgenl.",Sneg
|
||||||
|
"Ubj sne jvyy n oyvaq qbt jnyx vagb n sberfg?",Unysjnl
|
||||||
|
"Zl svefg vf va jvryq, frire obarf naq zneebj. Zl frpbaq vf va oynqr, sbetrq va pbyq fgrry. Zl guveq vf na neonyrfg, naq nyfb va neebjf. Zl sbhegu vf va cbjre, cyhatrq guebhtu n fuvryq. Zl svsgu vf va ubabe, naq nyfb va ibjf. Zl ynfg jvyy chg na raq gb vg nyy.",Jrncba
|
||||||
|
"Snpr jvgu n gerr, fxva yvxr gur frn. N terng ornfg V nz. Lrg irezva sevtugraf zr.",Ryrcunag
|
||||||
|
"V fyrrc ol qnl, V syl ol avtug. V unir ab srnguref gb nvq zl syvtug.",Ong
|
||||||
|
"V nz zbgure naq sngure, ohg arire ovegu be ahefr. V'z eneryl fgvyy, ohg V arire jnaqre.",Gerr
|
||||||
|
"Jung tbrf va gur jngre erq, naq pbzrf bhg oynpx?",Veba
|
||||||
|
"Tebjf sebz gur tebhaq, ohfurf naq tenff, yrnirf bs lryybj, erq naq oebja, haehyl cynagf, trg gur nkr, gevz gur urqtr onpx qbja.",Unve
|
||||||
|
"Jung pna gbhpu fbzrbar bapr naq ynfg gurz n yvsr gvzr?",Ybir
|
||||||
|
"N qentbaf gbbgu va n zbegnyf unaq, V xvyy, V znvz, V qvivqr gur ynaq.",Fjbeq
|
||||||
|
"Lbh jvyy svaq zr jvgu sbhe yrtf, ohg ab unve. Crbcyr evqr zr sbe ubhef, ohg V qba'g tb naljurer jvgubhg arrqvat gb or ghttrq. Wrexrq be ghearq ba, V nyjnlf znantr gb or ernql sbe jbex.",Qrfx
|
||||||
|
"Ab fbbare fcbxra guna oebxra.",Fvyrapr
|
||||||
|
"Gubhtu qrfreg zra bapr pnyyrq zr Tbq, gbqnl zra pnyy zr znq. Sbe V jnt zl gnvy jura V nz natel. Naq tebjy jura V nz tynq.",Png
|
||||||
|
"Na bcra raqrq oneery, vg vf funcrq yvxr n uvir. Vg vf svyyrq jvgu gur syrfu, naq gur syrfu vf nyvir.",Guvzoyr
|
||||||
|
"Jung xvaq bs crg nyjnlf fgnlf ba gur sybbe?",Pnecrg
|
||||||
|
"Jung syvrf jvgubhg jvatf? Jung cnffrf nyy guvatf? Jung zraqf nyy fbeebj? Jung oevatf gur zbeebj?",Gvzr
|
||||||
|
"Jung unf n arpx naq ab urnq, gjb nezf ohg ab unaqf?",Fuveg
|
||||||
|
"Gjb va n pbeare, bar va n ebbz, abar va n ubhfr, ohg bar va n furygre.",E
|
||||||
|
"Jung qbrf ab zna jnag, lrg ab zna jnag gb ybfr?",Jbex
|
||||||
|
"V nz gur urneg gung qbrf abg orng. Vs phg, V oyrrq jvgubhg oybbq. V pna syl, ohg unir ab jvatf. V pna sybng, ohg unir ab svaf. V pna fvat, ohg unir ab zbhgu.",Jbbq
|
||||||
|
"Jrvtug va zl oryyl, gerrf ba zl onpx, anvyf va zl evof, srrg V qb ynpx.",Obng
|
||||||
|
"Jung vf gung bire gur urnq naq haqre gur ung?",Unve
|
||||||
|
"V ovaq vg naq vg jnyxf. V ybbfr vg naq vg fgbcf.",Fnaqny
|
||||||
|
"Zl ibvpr vf graqre, zl jnvfg vf fyraqre naq V'z bsgra vaivgrq gb cynl. Lrg jurerire V tb, V zhfg gnxr zl obj be ryfr V unir abguvat gb fnl.",Ivbyva
|
||||||
|
"Ybiryl naq ebhaq, V fuvar jvgu cnyr yvtug, tebja va gur qnexarff, n ynql'f qryvtug.",Crney
|
||||||
|
"Gur fgenatrfg perngher lbh'yy rire svaq unf gjb rlrf va sebag naq n uhaqerq oruvaq.",Crnpbpx
|
||||||
|
"N yvggyr cbby jvgu gjb ynlref bs jnyy nebhaq vg. Bar juvgr naq fbsg naq gur bgure qnex naq uneq. Nzvqfg n yvtug oebja tenffl ynja jvgu na bhgyvar bs n terra tenff.",Pbpbahg
|
||||||
|
"V bcra jvqr naq gvtug V fuhg, Funec nz V naq cncre-phg svatref gbb, fb qb gnxr pner, V'z tbbq naq onq, fb orfg orjner.",Fpvffbef
|
||||||
|
"Bayl bar pbybe, ohg abg bar fvmr. Fghpx ng gur obggbz, lrg rnfvyl syvrf. Cerfrag va fha, ohg abg va enva. Qbvat ab unez, naq srryvat ab cnva.",Funqbj
|
||||||
|
"N ubhfr bs jbbq va n uvqqra cynpr. Ohvyg jvgubhg anvyf be tyhr. Uvtu nobir gur rnegura tebhaq. Vg ubyqf cnyr trzf bs oyhr.",Arfg
|
||||||
|
"Jub fcraqf gur qnl ng gur jvaqbj, tbrf gb gur gnoyr sbe zrnyf. Naq uvqrf ng avtug?",Syl
|
||||||
|
"Gur ortvaavat bs rgreavgl, gur raq bs gvzr naq fcnpr, gur ortvaavat bs rirel raq, gur raq bs rirel cynpr.",R
|
||||||
|
"Nyjnlf byq, fbzrgvzrf arj. Arire fnq, fbzrgvzrf oyhr. Arire rzcgl, fbzrgvzrf shyy. Arire chfurf, nyjnlf chyyf.",Zbba
|
||||||
|
"V ohooyr naq ynhtu naq fcvg jngre va lbhe snpr. V nz ab ynql, naq V qba'g jrne ynpr.",Sbhagnva
|
||||||
|
"Zl grrgu ner funec, zl onpx vf fgenvtug, gb phg guvatf hc vg vf zl sngr.",Fnj
|
||||||
|
"V ybir gb qnapr naq gjvfg naq cenapr. V funxr zl gnvy, nf njnl V fnvy. Jvatyrff V syl vagb gur fxl.",Xvgr
|
||||||
|
"V hfhnyyl jrne n lryybj pbng. V hfhnyyl unir n qnex urnq. V znxr znexf jurerire V tb.",Crapvy
|
||||||
|
"Zl yvsr vf bsgra n ibyhzr bs tevrs, lbhe uryc vf arrqrq gb ghea n arj yrns. Fgvss vf zl fcvar naq zl obql vf cnyr. Ohg V'z nyjnlf ernql gb gryy n gnyr.",Obbx
|
||||||
|
"V pbfg ab zbarl gb hfr, be pbafpvbhf rssbeg gb gnxr cneg bs. Naq nf sne nf lbh pna frr, gurer vf abguvat gb zr. Ohg jvgubhg zr, lbh ner qrnq.",Nve
|
||||||
|
"Fbyqvref yvar hc fcnprq jvgu cevqr. Gjb ybat ebjf yvarq fvqr ol fvqr. Bar fbyr havg pna qrpvqr, vs gur ebjf jvyy havg be qvivqr.",Mvccre
|
||||||
|
"Jung zrnfherf bhg gvzr. Hagvy va gvzr nyy vf fznfurq gb vg?",Fnaq
|
||||||
|
"V ghea nebhaq bapr. Jung vf bhg jvyy abg trg va. V ghea nebhaq ntnva. Jung vf va jvyy abg trg bhg.",Xrl
|
||||||
|
"Jub vf ur gung ehaf jvgubhg n yrt. Naq uvf ubhfr ba uvf onpx?",Fanvy
|
||||||
|
"Jura gur qnl nsgre gbzbeebj vf lrfgreqnl. Gbqnl jvyy or nf sne sebz Jrqarfqnl. Nf gbqnl jnf sebz Jrqarfqnl. Jura gur qnl orsber lrfgreqnl jnf gbzbeebj. Jung vf gur qnl nsgre guvf qnl?",Guhefqnl
|
||||||
|
"Jung unf ebbgf nf abobql frrf, vf gnyyre guna gerrf. Hc, hc vg tbrf, naq lrg arire tebjf?",Zbhagnva
|
||||||
|
"Pbzr hc naq yrg hf tb. Tb qbja naq urer jr fgnl.",Napube
|
||||||
|
"Gurl unir abg syrfu, abe srnguref, abe fpnyrf, abe obar. Lrg gurl unir svatref naq guhzof bs gurve bja.",Tybirf
|
||||||
|
"Ybat fyvz naq fyraqre. Qnex nf ubzrznqr guhaqre. Xrra rlrf naq crnxrq abfr. Fpnerf gur Qrivy jurerire vg tbrf.",Fanxr
|
||||||
|
"Jung vf chg ba n gnoyr, phg, ohg arire rngra?",Qrpx
|
||||||
|
"Gur funec fyvz oynqr, gung phgf gur jvaq.",Tenff
|
||||||
|
"Nygubhtu zl pbj vf qrnq, V fgvyy orng ure
Jung n enpxrg fur znxrf.",Qehz
|
||||||
|
"Vg fng hcba n jvyybj gerr, naq fnat fbsgyl hagb zr. Rnfvat zl cnva naq fbeebj jvgu vgf fbat. V jvfurq gb syl, ohg gneevrq ybat. Naq va zl fhssrevat, gur jvyybj jnf yvxr n pbby pyrne fcevat. Jung jnf vg gung urycrq zr fb? Gb fcraq zl gvzr va zl jbr.",Oveq
|
||||||
|
"V unir sbhe jvatf ohg pnaabg syl. V arire ynhtu naq arire pel. Ba gur fnzr fcbg nyjnlf sbhaq, gbvyvat njnl jvgu yvggyr fbhaq.",Jvaqzvyy
|
||||||
|
"V nz arire dhvgr jung V nccrne gb or. Fgenvtug-sbejneq V frrz, ohg vg'f bayl fxva qrrc. Sbe zlfgrel zbfg bsgra yvrf orarngu zl fvzcyr fcrrpu. Funecra lbhe jvgf, bcra lbhe rlrf, ybbx orlbaq zl rkgrevbef, ernq zr onpxjneqf, sbejneqf, hcfvqr qbja. Guvax naq nafjre gur dhrfgvba...Jung nz V?",Evqqyr
|
||||||
|
"Nyy nobhg gur ubhfr, jvgu uvf ynql ur qnaprf, lrg ur nyjnlf jbexf, naq arire ebznaprf.",Oebbz
|
||||||
|
"V jnyxrq naq jnyxrq naq ng ynfg V tbg vg. V qvqa'g jnag vg. Fb V fgbccrq naq ybbxrq sbe vg. Jura V sbhaq vg, V guerj vg njnl.",Gubea
|
||||||
|
"Gjb va n jubyr naq sbhe va n cnve. Naq fvk va n gevb lbh frr. Naq rvtug'f n dhnegrg ohg jung lbh zhfg trg. Vf gur anzr gung svgf whfg bar bs zr?",Unys
|
||||||
|
"V qevir zra znq sbe ybir bs zr. Rnfvyl orngra, arire serr.",Tbyq
|
||||||
|
"V tb nebhaq va pvepyrf, ohg nyjnlf fgenvtug nurnq. Arire pbzcynva, ab znggre jurer V nz yrq.",Jurry
|
||||||
|
"Lbh hfr n xavsr gb fyvpr zl urnq. Naq jrrc orfvqr zr jura V nz qrnq.",Bavba
|
||||||
|
"Gheaf hf ba bhe onpxf, naq bcra hc bhe fgbznpuf. Lbh jvyy or gur jvfrfg bs zra gubhtu ng fgneg n yhzzbk.",Obbxf
|
||||||
|
"Gubhfnaqf ynl hc tbyq jvguva guvf ubhfr. Ohg ab zna znqr vg. Fcrnef cnfg pbhagvat thneq guvf ubhfr, ohg ab zna jneqf vg.",Orruvir
|
||||||
|
"Jung tbrf nebhaq gur jbeyq naq fgnlf va n pbeare?",Fgnzc
|
||||||
|
"Jung unf gb or oebxra orsber vg pna or hfrq?",Rtt
|
||||||
|
"Perngherf bs cbjre, perngherf bs tenqr, perngherf bs ornhgl, perngherf bs fgeratgu. Nf sbe gurve yvirf, gurl frg rirelguvat'f cnpr. Sbe nyy guvatf zhfg pbzr gb yvir. Haqre gurve rzrenyq rzoenpr. Rvgure va gurve yvsr be va gurve qrngu.",Gerrf
|
||||||
|
"Qbhoyr zl ahzore, V'z yrff guna n fpber. Unys bs zl ahzore vf yrff guna sbhe. Nqq bar gb zl qbhoyr jura onxref ner arne. Qnlf bs gur jrrx ner fgvyy terngre, V srne.",Fvk
|
||||||
|
"Va ohpxyrf be ynpr, gurl uryc frg gur cnpr. Gur snegure lbh tb, gur guvaare gurl tebj.",Fubrf
|
||||||
|
"Jura lbhat, V nz fjrrg va gur fha. Jura zvqqyr-ntrq, V znxr lbh tnl. Jura byq, V nz inyhrq zber guna rire.",Jvar
|
||||||
|
"Sbejneq V'z urnil, ohg onpxjneqf V'z abg.",Gba
|
||||||
|
"Uneq gb pngpu, rnfl gb ubyq. Pna'g or frra, hayrff vg'f pbyq.",Oerngu
|
||||||
|
"V nz gjb-snprq ohg orne bayl bar. V unir ab yrtf ohg geniry jvqryl. Zra fcvyy zhpu oybbq bire zr. Xvatf yrnir gurve vzcevag ba zr. V unir terngrfg cbjre jura tvira njnl, lrg yhfg sbe zr xrrcf zr ybpxrq njnl.",Pbva
|
||||||
|
"Gjb yvggyr ubyrf va gur fvqr bs n uvyy. Whfg nf lbh pbzr gb gur pureel-erq zvyy.",Abfr
|
||||||
|
"Jura lbh fgbc naq ybbx, lbh pna nyjnlf frr zr. Vs lbh gel gb gbhpu, lbh pnaabg srry zr. V pnaabg zbir, ohg nf lbh arne zr, V jvyy zbir njnl sebz lbh.",Ubevmba
|
||||||
|
"N qnttre guehfg ng zl bja urneg, qvpgngrf gur jnl V'z fjnlrq. Yrsg V fgnaq, naq evtug V lvryq, gb gur gjvfgvat bs gur oynqr.",Ybpx
|
||||||
|
"Jung vafgehzrag pna znxr nal fbhaq naq or urneg, ohg abg gbhpurq be frra?",Ibvpr
|
||||||
|
"Jung tbrf shegure gur fybjre vg tbrf?",Zbarl
|
||||||
|
"V pna eha ohg abg jnyx. Jurerire V tb, gubhtug sbyybjf pybfr oruvaq.",Abfr
|
||||||
|
"Hfrq yrsg be evtug, V trg gb geniry bire pbooyrfgbar be teniry. Hfrq hc, V ivr sbe fjrrg fhpprff, hfrq qbja, V pnhfr zra terng qherff.",Guhzo
|
||||||
|
"Jung tbrf guebhtu gur qbbe jvgubhg cvapuvat vgfrys? Jung fvgf ba gur fgbir jvgubhg oheavat vgfrys? Jung fvgf ba gur gnoyr naq vf abg nfunzrq?",Fha
|
||||||
|
"Gur zbba vf zl sngure. Gur frn vf zl zbgure. V unir n zvyyvba oebguref. V qvr jura V ernpu ynaq.",Jnir
|
||||||
|
"Jung nyjnlf tbrf gb orq jvgu uvf fubrf ba?",Ubefr
|
||||||
|
"Zl guhaqre pbzrf orsber gur yvtugavat. Zl yvtugavat pbzrf orsber gur pybhqf. Zl enva qevrf nyy gur ynaq vg gbhpurf.",Ibypnab
|
||||||
|
"Zl ybir, jura V tnmr ba gul ornhgvshy snpr. Pnerrevat nybat, lrg nyjnlf va cynpr, gur gubhtug unf bsgra pbzr vagb zl zvaq. Vs V rire funyy frr gul tybevbhf oruvaq.",Zbba
|
||||||
|
"Jung fgnegf jvgu n 'G', raqf jvgu n 'G', naq unf G va vg?",Grncbg
|
||||||
|
"Gbqnl ur vf gurer gb gevc lbh hc. Naq ur jvyy gbegher lbh gbzbeebj. Lrg ur vf nyfb gurer gb rnfr gur cnva, jura lbh ner ybfg va tevrs naq fbeebj.",Nypbuby
|
||||||
|
"V pna or zbirq. V pna or ebyyrq. Ohg abguvat jvyy V ubyq. V'z erq naq V'z oyhr, naq V pna or bgure pbybef gbb. Univat ab urnq, gubhtu fvzvyne va funcr. V unir ab rlrf - lrg zbir nyy bire gur cynpr.",Onyy
|
||||||
|
"Vafvqr n oheavat ubhfr, guvf guvat vf orfg gb znxr. Naq orfg gb znxr vg dhvpxyl, orsber gur sver'f gbb zhpu gb gnxr.",Unfgr
|
||||||
|
"Jung vf ebhaq nf n qvfucna, qrrc nf n gho, naq fgvyy gur bprnaf pbhyqa'g svyy vg hc?",Fvrir
|
||||||
|
"Zl svefg vf va fbzr ohg abg va nyy. Zl frpbaq vf vagb ohg abg va gnyy. Zl guveq va yvggyr ohg ab va ovt. Zl sbhegu va cbeg ohg abg va cvt. Zl jubyr vf znqr va angher'f jnl. Sbe pybguvat, ehtf hfrq rirel qnl.",Fvyx
|
||||||
|
"Trgf evq bs onq barf, fubeg naq gnyy. Gvtugraf jura hfrq, bar fvmr svgf nyy.",Abbfr
|
||||||
|
"Jung trgf jrggre gur zber vg qevrf.",Gbjry
|
||||||
|
"N yvggyr ubhfr shyy bs zrng, ab qbbe gb tb va naq rng.",Ahg
|
||||||
|
"N orttne'f oebgure jrag bhg gb frn naq qebjarq. Ohg gur zna jub qebjarq unq ab oebgure. Jub jnf gur orttne gb gur zna jub qebjarq?",Fvfgre
|
||||||
|
"V pna or jevggra, V pna or fcbxra, V pna or rkcbfrq, V pna or oebxra.",Arjf
|
||||||
|
"N ubeevq zbafgre uvqrf sebz gur qnl, jvgu znal yrtf naq znal rlrf. Jvgu fvyire punvaf vg pngpurf cerl. Naq rngf vg nyy orsber vg qvrf. Lrg va rirel pbggntr qbrf vg fgnl. Naq rirel pnfgyr orarngu gur fxl.",Fcvqre
|
||||||
|
"Svir uhaqerq ortvaf vg, svir uhaqerq raqf vg. Svir va gur zvqqyr vf frra. Svefg bs nyy svtherf, gur svefg bs nyy yrggref. Gnxr hc gurve fgngvbaf orgjrra. Wbva nyy gbtrgure, naq gura lbh jvyy oevat orsber lbh gur anzr bs na rzvarag xvat.",Qnivq
|
||||||
|
"Gnyy va gur zbeavat, fubeg ng abba, tbar ng avtug. Ohg V'yy or onpx fbba.",Funqbj
|
||||||
|
"Va gur avtug n zbhagnva, va gur zbeavat n zrnqbj.",Orq
|
||||||
|
"Jung pna or urneq naq pnhtug ohg arire frra?",Erznex
|
||||||
|
"V pna fvmmyr yvxr onpba, V nz znqr jvgu na rtt. V unir cyragl bs onpxobar, ohg ynpx n tbbq yrt. V crry ynlref yvxr bavbaf, ohg fgvyy erznva jubyr. V pna or ybat, yvxr n syntcbyr, lrg svg va n ubyr.",Fanxr
|
||||||
|
"Vs n zna pneevrq zl oheqra, ur jbhyq oernx uvf onpx. V nz abg evpu, ohg yrnir fvyire va zl genpx.",Fanvy
|
||||||
|
"Uvtu obea, zl gbhpu vf tragyr. Cherfg juvgr vf zl ynpr. Fvyrapr vf zl xvatqbz. Terra vf gur pbybe bs zl qrngu.",Fabj
|
||||||
|
"Lbh urneq zr orsber, lrg lbh urne zr ntnva, gura V qvr. Hagvy lbh pnyy zr ntnva.",Rpub
|
||||||
|
"Jung jrnef n pbng va gur jvagre naq cnagf va gur fhzzre?",Qbt
|
||||||
|
"V'z abg ernyyl zber guna ubyrf gvrq gb zber ubyrf. V'z fgebat nf tbbq fgrry, gubhtu abg nf fgvss nf n cbyr.",Punva
|
||||||
|
"V nz gur guveq sebz n fcnexyr oevtug, V guevir guebhtubhg gur qnl naq avtug. Qrrc va gur cngu bs n pbjf juvgr qevax. V'ir unq gubhfnaqf bs zvyyvbaf bs lrnef gb guvax. Ohg bar bs zl perngherf vf xvyyvat zr. Naq fb gur dhrfgvba V nfx gb gurr, vf jub nz V?",Rnegu
|
||||||
|
"Hc ba uvtu V jnir njnl ohg abg n jbeq pna V fnl.",Synt
|
||||||
|
"V nz jubyr ohg vapbzcyrgr. V unir ab rlrf, lrg V frr. Lbh pna frr, naq frr evtug guebhtu zr. Zl ynetrfg cneg vf bar sbhegu bs jung V bapr jnf.",Fxryrgba
|
||||||
|
"Gurl'er hc arne gur fxl, ba fbzrguvat irel gnyy. Fbzrgvzrf gurl qvr, bayl gura qb gurl snyy.",Yrnirf
|
||||||
|
"Gbff zr bhg bs gur jvaqbj. Lbh'yy svaq n tevrivat jvsr. Chyy zr onpx ohg guebhtu gur qbbe, naq jngpu fbzrbar tvir yvsr.",A
|
||||||
|
"N gvzr jura gurl'er terra. N gvzr jura gurl'er oebja. Ohg obgu bs gurfr gvzrf, pnhfr zr gb sebja. Ohg whfg va orgjrra, sbe n irel fubeg juvyr. Gurl'er cresrpg naq lryybj. Naq pnhfr zr gb fzvyr.",Onananf
|
||||||
|
"V ohvyq hc pnfgyrf. V grne qbja zbhagnvaf. V znxr fbzr zra oyvaq. V uryc bguref gb frr.",Fnaq
|
||||||
|
"Ebhaq nf n ohggba, qrrc nf n jryy. Vs lbh jnag zr gb gnyx, lbh zhfg svefg chyy zl gnvy.",Oryy
|
||||||
|
"N ubhfr jvgu gjb bpphcnagf, fbzrgvzrf bar, eneryl guerr. Oernx gur jnyyf, rng gur obneqref, gura guebj njnl zr.",Crnahg
|
||||||
|
"Zl svefg znfgre unf sbhe yrtf, zl frpbaq znfgre unf gjb. Zl svefg V freir va yvsr, zl frpbaq V freir va qrngu. Gbhtu V nz, lrg fbsg orfvqr. Ntnvafg ynqvrf purrxf V bsgra erfvqr.",She
|
||||||
|
"V unir bar rlr. Frr arne naq sne. V ubyq gur zbzragf lbh gernfher naq gur guvatf gung znxr lbh jrrc.",Pnzren
|
||||||
|
"Gurer ner gjb zrnavatf gb zr. Jvgu bar V znl arrq gb or oebxra, jvgu gur bgure V ubyq ba. Zl snibevgr punenpgrevfgvp vf zl punezvat qvzcyr.",Gvr
|
||||||
|
"Jvgu funec rqtrq jvg naq cbvagrq cbvfr. Vg pna frggyr qvfchgrf jvgubhg znxvat n abvfr.",Fjbeq
|
||||||
|
"Yvtugre guna jung V nz znqr bs, zber bs zr vf uvqqra guna vf frra. V nz gur onar bs gur znevare. N gbbgu jvguva gur frn.",Vproret
|
||||||
|
"V unir bar, lbh unir bar. Vs lbh erzbir gur svefg yrggre, n ovg erznvaf. Vs lbh erzbir gur frpbaq, ovg fgvyy erznvaf. Vs lbh erzbir gur guveq, vg fgvyy erznvaf.",Unovg
|
||||||
|
"Xvatf naq dhrraf znl pyvat gb cbjre. Naq gur wrfgre'f tbg uvf pnyy. Ohg, nf lbh znl nyy qvfpbire. Gur pbzzba bar bhgenaxf gurz nyy.",Npr
|
||||||
|
"Tyvggrevat cbvagf gung qbjajneq guehfg. Fcnexyvat fcrnef gung arire ehfg.",Vpvpyrf
|
||||||
|
"Zl svefg vf va svfu ohg ab va fanvy. Zl frpbaq vf va enoovg ohg ab va gnvy. Zl guveq vf va hc ohg abg va qbja. Zl sbhegu vf va gvnen ohg abg va pebja. Zl svsgu vf va gerr lbh cynvayl frr. Zl jubyr n sbbq sbe lbh naq zr.",Sehvg
|
||||||
|
"Jung V nz svyyrq, V pna cbvag gur jnl. Jura V nz rzcgl. Abguvat zbirf zr. V unir gjb fxvaf. Bar jvgubhg naq bar jvguva.",Tybirf
|
||||||
|
"Zl svefg vf va jvaqbj ohg abg va cnar. Zl frpbaq'f va ebnq ohg abg va ynar. Zl guveq vf va biny ohg abg va ebhaq. Zl sbhegu vf va urnevat ohg abg va fbhaq. Zl jubyr vf xabja nf n fvta bs crnpr. Naq sebz abnu'f nex jba dhvpx eryrnfr.",Qbir
|
||||||
|
"Vs lbh qebc zr V'z fher gb penpx. Ohg tvir zr n fzvyr naq V'yy nyjnlf fzvyr onpx.",Zveebe
|
||||||
|
"V znxr lbh jrnx ng gur jbefg bs nyy gvzrf. V xrrc lbh fnsr, V xrrc lbh svar. V znxr lbhe unaqf fjrng. Naq lbhe urneg tebj pbyq. V ivfvg gur jrnx, ohg fryqbz gur obyq.",Srne
|
||||||
|
"V eha guebhtu uvyyf. V irre nebhaq zbhagnvaf. V yrnc bire eviref. Naq penjy guebhtu gur sberfgf. Fgrc bhg lbhe qbbe gb svaq zr.",Ebnq
|
||||||
|
"Lbh pna frr abguvat ryfr jura lbh ybbx va zl snpr. V jvyy ybbx lbh va gur rlr naq V jvyy arire yvr.",Zveebe
|
||||||
|
"V unir fcyvg gur bar vagb svir. V nz gur pvepyr gung srj jvyy fcl. V nz gur cngu gung oernxf naq tvirf. V nz gur obj ab zna znl oraq.",Envaobj
|
||||||
|
"N uneirfg fbja naq erncrq ba gur fnzr qnl va na hacybjrq svryq. Juvpu vapernfrf jvgubhg tebjvat, erznvaf jubyr gubhtu vg vf rngra jvguva naq jvgubhg. Vf hfryrff naq lrg gur fgncyr bs angvbaf.",Jne
|
||||||
|
"Fanxr pbvyrq ebhaq naq ebhaq. Fanxr qrrc orybj gur tebhaq. Fanxr gung'f arire unq n urnq. Fanxr gung ovaqf ohg abg jvgu qernq.",Ebcr
|
||||||
|
"Zl svefg vf va bprna ohg arire va frn. Zl frpbaq'f va jnfc ohg arire va orr. Zl guveq vf va tyvqre naq nyfb va syvtug. Zl jubyr vf n perngher gung pbzrf bhg ng avtug.",Bjy
|
||||||
|
"Qvrf unys vgf yvsr. Yvirf gur erfg. Qnaprf jvgubhg zhfvp. Oerngurf jvgubhg oerngu.",Gerr
|
||||||
|
"Jung ehaf nebhaq nyy qnl. Gura yvrf haqre gur orq. Jvgu vgf gbathr unatvat bhg?",Fubr
|
||||||
|
"Vg'f gehr V oevat freravgl. Naq unat nebhaq gur fgnef. Ohg lrg V yvir va zvfrel, lbh'yy svaq zr oruvaq onef. Jvgu guvrirf naq ivyynvaf V pbafbeg. Va cevfba V'yy or sbhaq. Ohg V jbhyq arire tb gb pbheg. Hayrff gurer'f zber guna bar.",F
|
||||||
|
"Lbh zhfg xrrc guvf guvat. Vgf ybff jvyy nssrpg lbhe oebguref. Sbe bapr lbhef vf ybfg, vg jvyy fbba or ybfg ol bguref.",Grzcre
|
||||||
|
"Jung pna lbh pngpu ohg abg guebj?",Pbyq
|
||||||
|
"Oynpx jr ner naq zhpu nqzverq. Zra frrx hf vs gurl ner gverq. Jr gver gur ubefr, pbzsbeg zna. Thrff guvf evqqyr vs lbh pna.",Pbny
|
||||||
|
"V unir n snpr, lrg ab frafrf. Ohg V qba'g ernyyl pner, orpnhfr gvzr vf bs gur rffrapr.",Pybpx
|
||||||
|
"Vs lbh unir vg, lbh jnag gb funer vg. Vs lbh funer vg, lbh qba'g unir vg.",Frperg
|
||||||
|
"Gurer vf bar va rirel pbeare naq gjb va rirel ebbz.",B
|
||||||
|
"Vg pbzrf bayl orsber, vg pbzrf bayl nsgre. Evfrf bayl va qnexarff, ohg evfrf bayl va yvtug. Vg vf nyjnlf gur fnzr, ohg vf lrg nyjnlf qvssrerag.",Zbba
|
||||||
|
"Nf fbsg nf fvyx, nf juvgr nf zvyx, nf ovggre nf tnyy, n guvpx terra jnyy, naq n terra pbng pbiref zr nyy.",Jnyahg
|
||||||
|
"Jr ner yvggyr nvel perngherf, nyy bs qvssrerag ibvpr naq srngherf, bar bs hf va tynff vf frg. Bar bs hf lbh'yy svaq va wrg. Nabgure lbh znl frr va gva. Naq gur sbhegu n obk jvguva. Vs gur svsgu lbh fubhyq chefhr, vg pna arire syl sebz lbh.",Ibjryf
|
||||||
|
"Guerr yvggyr yrggref. N cnenqbk gb fbzr. Gur jbefr gung vg vf, gur orggre vg orpbzrf.",Cha
|
||||||
|
"Nyzbfg rirelbar arrqf vg, nfxf sbe vg, tvirf vg. Ohg nyzbfg abobql gnxrf vg.",Nqivpr
|
||||||
|
"Qvssrerag yvtugf qb znxr zr fgenatr, guhf vagb qvssrerag fvmrf V jvyy punatr.",Chcvy
|
||||||
|
"Gra zra'f fgeratgu, gra zra'f yratgu. Gra zra pna'g oernx vg, lrg n lbhat obl jnyxf bss jvgu vg.",Ebcr
|
||||||
|
"Fbzr gel gb uvqr, fbzr gel gb purng. Ohg gvzr jvyy fubj, jr nyjnlf jvyy zrrg. Gel nf lbh zvtug, gb thrff zl anzr. V cebzvfr lbh'yy xabj, jura lbh V qb pynvz.",Qrngu
|
||||||
|
"V'z n tbq. V'z n cynarg. V zrnfher urng.",Zrephel
|
||||||
|
"V'z juvgr, V'z ebhaq, ohg abg nyjnlf nebhaq. Fbzrgvzrf lbh frr zr, fbzrgvzrf lbh qba'g.",Zbba
|
||||||
|
"Crbcyr ner uverq gb trg evq bs zr. V'z bsgra uvqvat haqre lbhe orq. Va gvzr V'yy nyjnlf erghea lbh frr. Ovgr zr naq lbh'er fheryl qrnq.",Qhfg
|
||||||
|
"Qvr jvgubhg zr, arire gunax zr. Jnyx evtug guebhtu zr, arire srry zr. Nyjnlf jngpuvat, arire fcrnxvat. Nyjnlf yhexvat, arire frra.",Nve
|
||||||
|
"Juvgr oveq, srngureyrff, sylvat bhg bs cnenqvfr. Sylvat bire frn naq ynaq. Qlvat va zl unaq.",Fabj
|
||||||
|
"Zl yvsr pna or zrnfherq va ubhef. V freir ol orvat qribherq. Guva, V nz dhvpx. Sng, V nz fybj. Jvaq vf zl sbr.",Pnaqyr
|
||||||
|
"Jung tbrf hc ohg arire pbzrf qbja?",Ntr
|
||||||
|
"Jr ner nyy nebhaq, lrg gb hf lbh ner unys oyvaq. Fhayvtug znxrf hf vaivfvoyr, naq qvssvphyg gb svaq.",Fgnef
|
||||||
|
"Jung'f ynetr ba Fngheqnl naq Fhaqnl. Fznyy ba Ghrfqnl, Jrqarfqnl, naq Guhefqnl, naq qvfnccrnef ba Zbaqnl naq Sevqnl?",F
|
||||||
|
"Jung qb lbh svyy jvgu rzcgl unaqf?",Tybirf
|
||||||
|
"Tbrf bire nyy gur uvyyf naq ubyybjf. Ovgrf uneq, ohg arire fjnyybjf.",Sebfg
|
||||||
|
"Fgrnygul nf n funqbj va gur qrnq bs avtug, phaavat ohg nssrpgvbangr vs tvira n ovgr. Arire bjarq ohg bsgra ybirq. Ng zl fcbeg pbafvqrerq pehry, ohg gung'f orpnhfr lbh arire xabj zr ng nyy.",Png
|
||||||
|
"N erq qehz juvpu fbhaqf jvgubhg orvat gbhpurq, naq tebjf fvyrag, jura vg vf gbhpurq.",Urneg
|
||||||
|
"Zl frpbaq vf cresbezrq ol zl svefg, naq vg vf gubhtug n guvrs ol gur znexf bs zl jubyr zvtug or pnhtug.",Sbbgfgrc
|
||||||
|
"Gur zna jub znqr vg qvqa'g arrq vg. Gur zna jub obhtug vg qvqa'g hfr vg. Gur zna jub hfrq vg qvqa'g jnag vg.",Pbssva
|
||||||
|
"N uvyy shyy, n ubyr shyy, lrg lbh pnaabg pngpu n objy shyy.",Zvfg
|
||||||
|
"V nz n obk gung ubyqf oynpx naq juvgr xrlf jvgubhg ybpxf. Lrg gurl pna haybpx lbhe fbhy.",Cvnab
|
||||||
|
"Jung vf bsgra erghearq, ohg arire obeebjrq/",Gunaxf
|
||||||
|
"N zhggrerq ehzoyr jnf urneq sebz gur cra, naq V, va zl jnyxvat fgbccrq gb ybbx va. Jung jnf guvf V fnj? N znffvir ornfg, ubbsrq, naq wnjrq. Jvgu fcvxrf hcba vgf zvtugl oebj, V jngpurq nf ur fgehpx gur ghes naq cebjyrq. Naq lrg sbe nyy bs uvf zntavsvprapr, ur pbhyqa'g trg bhg bs gung jbbqra srapr.",Ohyy
|
||||||
|
"Jung jbeq unf xfg va gur zvqqyr, va gur ortvaavat, naq ng gur raq?",Vaxfgnaq
|
||||||
|
"Fb pbyq, qnzc naq qnex guvf cynpr. Gb fgnl lbh jbhyq ersenva, lrg gubfr jub bpphcl guvf cynpr qb arire pbzcynva.",Tenir
|
||||||
|
"Jung xvaq bs ahg vf rzcgl ng gur pragre naq unf ab furyy.",Qbhtuahg
|
||||||
|
"V unir n gvgyr naq znal cntrf. V nz n tragrry bs tragrry qrfprag. V nz n xvyyre irgrena bs jne. V nz n fynir gb zl ybeq cyrqtrq gb uvf freivpr.",Xavtug
|
||||||
|
"Bs gurfr guvatf - V unir gjb. Bar sbe zr - naq bar sbe lbh. Naq jura lbh nfx nobhg gur cevpr, V fvzcyl fzvyr naq abq gjvpr.",Funevat
|
||||||
|
"Ng avtug V pbzr jvgubhg orvat srgpurq. Ol qnl V nz ybfg jvgubhg orvat fgbyra.",Fgnef
|
||||||
|
"Evccrq sebz zl zbgure'f jbzo. Orngra naq ohearq, V orpbzr n oybbq guvefgl xvyyre.",Veba
|
||||||
|
"V'z irel grzcgvat, fb vgf fnvq, V unir n fuval pbng bs erq, naq zl syrfu vf juvgr orarngu. V fzryy fb fjrrg, gnfgr tbbq gb rng, naq uryc gb thneq lbhe grrgu.",Nccyr
|
||||||
|
"Gurl znqr zr n zbhgu, ohg qvqa'g tvir zr oerngu. Jngre tvirf zr yvsr, ohg gur fha oevatf zr qrngu.",Fabjzna
|
||||||
|
"V nz nf fvzcyr nf n pvepyr. Jbeguyrff nf n yrnqre, ohg jura V sbyybj n tebhc. Gurve fgeratgu vapernfrf grasbyq. Ol zlfrys V nz cenpgvpnyyl abguvat. Arvgure artngvir be cbfvgvir.",0
|
||||||
|
"V fnj n zna va juvgr, ur ybbxrq dhvgr n fvtug. Ur jnf abg byq, ohg ur fgbbq va gur pbyq. Naq jura ur sryg gur fha, ur fgnegrq gb eha. Jub pbhyq ur or? Cyrnfr nafjre zr.",Fabjzna
|
||||||
|
"Jr ner svir yvggyr bowrpgf bs na rirelqnl fbeg. Lbh jvyy svaq hf nyy va n graavf pbheg.",Ibjryf
|
||||||
|
"Jung nyjnlf ehaf ohg arire jnyxf, bsgra zhezhef, arire gnyxf. Unf n orq ohg arire fyrrcf, unf n zbhgu ohg arire rngf?",Evire
|
||||||
|
"V pna or penpxrq, V pna or znqr. V pna or gbyq, V pna or cynlrq.",Wbxr
|
||||||
|
"Zl puvyqera ner arne naq sne. Ab znggre gung V xabj jurer gurl ner. Gur tvsg V tvir gurz znxr gurve qnl. Ohg vs V jrer tbar gurl jbhyq jnaqre njnl.",Fha
|
||||||
|
"Fpernzvat, fbnevat frrxvat fxl. Sybjref bs sver sylvat uvtu. Rnfgrea neg sebz napvrag gvzr. Anzr zr abj naq fbyir guvf eulzr.",Sverjbex
|
||||||
|
"Jub vf vg gung ebjf dhvpxyl jvgu sbhe bnef, ohg arire pbzrf bhg sebz haqre uvf bja ebbs?",Ghegyr
|
||||||
|
"Jub jbexf jura ur cynlf naq cynlf jura ur jbexf?",Zhfvpvna
|
||||||
|
"Zl svefg vf gjvpr va nccyr ohg abg bapr va gneg. Zl frpbaq vf va yvire ohg abg va urneg. Zl guveq vf va tvnag naq nyfb va tubfg. Jubyr V'z orfg jura V nz gbnfg.",Cvt
|
||||||
|
"Ernpuvat fgvssyl sbe gur fxl, V oner zl svatref jura vgf pbyq. Va jnezgu V jrne na rzrenyq tybir naq va orgjrra V qerff va tbyq.",Gerr
|
||||||
|
"N cerpvbhf fgbar, nf pyrne nf qvnzbaq. Frrx vg bhg juvyr gur fha'f arne gur ubevmba. Gubhtu lbh pna jnyx ba jngre jvgu vgf cbjre, gel gb xrrc vg, naq vg'yy inavfu va na ubhe.",Vpr
|
||||||
|
"Unys-jnl hc gur uvyy, V frr lbh ng ynfg, ylvat orarngu zr jvgu lbhe fbhaqf naq fvtugf. N pvgl va gur gjvyvtug, qvz naq infg, jvgu fzbxvat ebbsf, fbsg oryyf, naq tyrnzvat yvtugf.",Cnfg
|
||||||
|
"V urneq bs n jbaqre, bs jbeqf zbgu-rngra. Gung vf n fgenatr guvat, V gubhtug, jrveq. Gung n zna'f fbat or fjnyybjrq ol n jbez. Uvf oyvaqrq fragraprf, uvf orqfvqr fgnaq-ol ehfgyrq va gur avtug - naq gur eboore-thrfg. Abg bar jvg gur jvfre. Sbe gur jbeqf ur unq zhzoyrq.",Obbxjbez
|
||||||
|
"Jung unf n fvatyr rlr ohg pnaabg frr?",Arrqyr
|
||||||
|
"V'z yvtug nf n srngure, lrg gur fgebatrfg zna pna'g ubyq zr sbe zber guna 5 zvahgrf. Jung nz V?",Oerngu
|
||||||
|
"Jung tbrf va gur jngre oynpx naq pbzrf bhg erq?",Ybofgre
|
||||||
|
"Jung vf oebja naq fgvpxl?",Fgvpx
|
||||||
|
"Jung nfxf ohg arire nafjref?",Bjy
|
||||||
|
"Jung ybfrf vgf urnq va gur zbeavat naq trgf vg onpx ng avtug?",Cvyybj
|
||||||
|
"Jung ohvyqvat unf gur zbfg fgbevrf?",Yvoenel
|
||||||
|
"V bpphe bapr va n zvahgr...",Z
|
||||||
|
"V cnff orsber gur fha, ohg znxr ab funqbj. Jung nz V?",jvaq
|
||||||
|
"Yvtugre guna n srngure, ohg n zna pnaabg ubyq zr sbe ybat...",oerngu
|
||||||
|
"V unir n uhaqerq yrtf naq pnaabg fgnaq, n ybat arpx ohg ab urnq, naq V rng gur znvq'f yvsr.",oebbz
|
|
9884
samples/Sample_TextGame/gamedata/words.txt
Normal file
9884
samples/Sample_TextGame/gamedata/words.txt
Normal file
File diff suppressed because it is too large
Load Diff
0
samples/Sample_TextGame/saves/do_not_delete.txt
Normal file
0
samples/Sample_TextGame/saves/do_not_delete.txt
Normal file
51
samples/SquidTasksSamples.sln
Normal file
51
samples/SquidTasksSamples.sln
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.30804.86
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sample_TextGame", "Sample_TextGame\Sample_TextGame.vcxproj", "{9095CB85-E1B0-4D03-9A3C-B3D277A1E300}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sample_Template", "Sample_Template\Sample_Template.vcxproj", "{E48F8265-C836-4564-9525-AFB12295CF64}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sample_Tests", "Sample_Tests\Sample_Tests.vcxproj", "{ABA88D0D-D79F-4371-BA63-D441662242B4}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{9095CB85-E1B0-4D03-9A3C-B3D277A1E300}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{9095CB85-E1B0-4D03-9A3C-B3D277A1E300}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{9095CB85-E1B0-4D03-9A3C-B3D277A1E300}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{9095CB85-E1B0-4D03-9A3C-B3D277A1E300}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{9095CB85-E1B0-4D03-9A3C-B3D277A1E300}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{9095CB85-E1B0-4D03-9A3C-B3D277A1E300}.Release|x64.Build.0 = Release|x64
|
||||||
|
{9095CB85-E1B0-4D03-9A3C-B3D277A1E300}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{9095CB85-E1B0-4D03-9A3C-B3D277A1E300}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{E48F8265-C836-4564-9525-AFB12295CF64}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{E48F8265-C836-4564-9525-AFB12295CF64}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{E48F8265-C836-4564-9525-AFB12295CF64}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{E48F8265-C836-4564-9525-AFB12295CF64}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{E48F8265-C836-4564-9525-AFB12295CF64}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{E48F8265-C836-4564-9525-AFB12295CF64}.Release|x64.Build.0 = Release|x64
|
||||||
|
{E48F8265-C836-4564-9525-AFB12295CF64}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{E48F8265-C836-4564-9525-AFB12295CF64}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{ABA88D0D-D79F-4371-BA63-D441662242B4}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{ABA88D0D-D79F-4371-BA63-D441662242B4}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{ABA88D0D-D79F-4371-BA63-D441662242B4}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{ABA88D0D-D79F-4371-BA63-D441662242B4}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{ABA88D0D-D79F-4371-BA63-D441662242B4}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{ABA88D0D-D79F-4371-BA63-D441662242B4}.Release|x64.Build.0 = Release|x64
|
||||||
|
{ABA88D0D-D79F-4371-BA63-D441662242B4}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{ABA88D0D-D79F-4371-BA63-D441662242B4}.Release|x86.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {B4AFD98E-6CC4-4427-A0B0-7E2A037C4A1F}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Logging/LogMacros.h"
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
DECLARE_LOG_CATEGORY_EXTERN(LogSquidTasks, Log, All);
|
@ -0,0 +1,20 @@
|
|||||||
|
#include "Modules/ModuleInterface.h"
|
||||||
|
#include "Modules/ModuleManager.h"
|
||||||
|
#include "SquidTasksLog.h"
|
||||||
|
|
||||||
|
DEFINE_LOG_CATEGORY(LogSquidTasks);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
class FSquidTasksModule : public IModuleInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void StartupModule() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void ShutdownModule() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
IMPLEMENT_MODULE(FSquidTasksModule, SquidTasks);
|
@ -0,0 +1,98 @@
|
|||||||
|
#include "TaskDemoActor.h"
|
||||||
|
|
||||||
|
#include "SquidTasksLog.h"
|
||||||
|
#include "SquidTasks/FunctionGuard.h"
|
||||||
|
#include "Components/BoxComponent.h"
|
||||||
|
#include "Components/TextRenderComponent.h"
|
||||||
|
#include "DrawDebugHelpers.h"
|
||||||
|
|
||||||
|
// Utility tasks (local to this compilation unit)
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
Task<> CountSeconds(UBoxComponent* BoxComp, UTextRenderComponent* TextRenderComp)
|
||||||
|
{
|
||||||
|
// Restore text state when this coroutine collapses
|
||||||
|
auto RestoreTextGuard = MakeFnGuard([TextRenderComp, Text = TextRenderComp->Text, Color = TextRenderComp->TextRenderColor] {
|
||||||
|
TextRenderComp->SetText(Text);
|
||||||
|
TextRenderComp->SetTextRenderColor(Color);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Count the seconds
|
||||||
|
float SecondsElapsed = 0.0f;
|
||||||
|
TextRenderComp->SetTextRenderColor(FColor::Green);
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
TextRenderComp->SetText(FText::FromString(FString::SanitizeFloat(SecondsElapsed)));
|
||||||
|
co_await WaitSeconds(1.0f, GameTime(BoxComp));
|
||||||
|
++SecondsElapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Task<> DebugDrawBoxComponent(UBoxComponent* BoxComp)
|
||||||
|
{
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// Calculate correct color (green when overlapping, otherwise red)
|
||||||
|
bool bIsOverlapping = BoxComp->GetOverlapInfos().Num() > 0;
|
||||||
|
FColor Color = bIsOverlapping ? FColor::Green : FColor::Red;
|
||||||
|
|
||||||
|
// Draw the box
|
||||||
|
DrawDebugBox(BoxComp->GetWorld(), BoxComp->GetCenterOfMass(), BoxComp->GetScaledBoxExtent(), Color);
|
||||||
|
|
||||||
|
// Wait until next frame
|
||||||
|
co_await Suspend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- ATaskDemoActor ---//
|
||||||
|
ATaskDemoActor::ATaskDemoActor()
|
||||||
|
{
|
||||||
|
// Create box component (as root)
|
||||||
|
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
|
||||||
|
BoxComp->SetBoxExtent(FVector{ 200.0f, 200.0f, 200.0f }, false);
|
||||||
|
RootComponent = BoxComp;
|
||||||
|
|
||||||
|
// Create text render component
|
||||||
|
TextRenderComp = CreateDefaultSubobject<UTextRenderComponent>(TEXT("TextRenderComp"));
|
||||||
|
TextRenderComp->SetupAttachment(BoxComp);
|
||||||
|
TextRenderComp->HorizontalAlignment = EHTA_Center;
|
||||||
|
TextRenderComp->VerticalAlignment = EVRTA_TextCenter;
|
||||||
|
TextRenderComp->Text = FText::FromString(TEXT("Enter the box"));
|
||||||
|
TextRenderComp->SetWorldSize(52.0f);
|
||||||
|
|
||||||
|
// Make this actor tick
|
||||||
|
PrimaryActorTick.bCanEverTick = true;
|
||||||
|
}
|
||||||
|
void ATaskDemoActor::BeginPlay()
|
||||||
|
{
|
||||||
|
Super::BeginPlay();
|
||||||
|
TaskMgr.RunManaged(ManageActor());
|
||||||
|
TaskMgr.RunManaged(DebugDrawBoxComponent(BoxComp));
|
||||||
|
}
|
||||||
|
void ATaskDemoActor::Tick(float DT)
|
||||||
|
{
|
||||||
|
Super::Tick(DT);
|
||||||
|
TaskMgr.Update();
|
||||||
|
}
|
||||||
|
void ATaskDemoActor::EndPlay(const EEndPlayReason::Type EPR)
|
||||||
|
{
|
||||||
|
TaskMgr.KillAllTasks();
|
||||||
|
Super::EndPlay(EPR);
|
||||||
|
}
|
||||||
|
Task<> ATaskDemoActor::ManageActor()
|
||||||
|
{
|
||||||
|
TASK_NAME(__FUNCTION__);
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// Wait until anything overlaps this volume
|
||||||
|
co_await WaitUntil([BoxComp = BoxComp] {
|
||||||
|
return BoxComp->GetOverlapInfos().Num() > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run a sub-task that counts off seconds while something is overlapping the volume
|
||||||
|
co_await CountSeconds(BoxComp, TextRenderComp).CancelIf([BoxComp = BoxComp] {
|
||||||
|
return BoxComp->GetOverlapInfos().Num() == 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SquidTasks/Task.h"
|
||||||
|
#include "SquidTasks/TaskManager.h"
|
||||||
|
|
||||||
|
#include "TaskDemoActor.generated.h"
|
||||||
|
|
||||||
|
class UBoxComponent;
|
||||||
|
class UTextRenderComponent;
|
||||||
|
|
||||||
|
// Task Demo Actor
|
||||||
|
UCLASS()
|
||||||
|
class ATaskDemoActor : public AActor
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
public:
|
||||||
|
ATaskDemoActor();
|
||||||
|
|
||||||
|
virtual void BeginPlay() override;
|
||||||
|
virtual void Tick(float DT) override;
|
||||||
|
virtual void EndPlay(const EEndPlayReason::Type EPR) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Task Demo") UBoxComponent* BoxComp = nullptr;
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Task Demo") UTextRenderComponent* TextRenderComp = nullptr;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TaskManager TaskMgr;
|
||||||
|
Task<> ManageActor();
|
||||||
|
};
|
@ -0,0 +1,128 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @defgroup FunctionGuard Function Guard
|
||||||
|
/// @brief Scope guard that calls a function as it leaves scope.
|
||||||
|
/// @{
|
||||||
|
///
|
||||||
|
/// A FunctionGuard is an scope guard object that stores a functor that will be called from its destructor. By
|
||||||
|
/// convention, scope guards are move-only objects that are intended for allocation on the stack, to ensure that certain
|
||||||
|
/// operations are performed exactly once (when their scope collapses).
|
||||||
|
///
|
||||||
|
/// Because tasks can be canceled while suspended (and thus do not reach the end of the function), any cleanup code at
|
||||||
|
/// the end of a task isn't guaranteed to execute. Because FunctionGuard is an RAII object, it gives programmers an
|
||||||
|
/// opportunity to schedule guaranteed cleanup code, no matter how a task terminates.
|
||||||
|
///
|
||||||
|
/// Consider the following example of a task that manages a character's "charge attack" in a combat-oriented game:
|
||||||
|
///
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||||
|
///
|
||||||
|
/// class Character : public Actor
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
/// Task<> ChargeAttackState()
|
||||||
|
/// {
|
||||||
|
/// bool bIsFullyCharged = false;
|
||||||
|
/// if(Input->IsAttackButtonPressed())
|
||||||
|
/// {
|
||||||
|
/// StartCharging(); // Start playing charge effects
|
||||||
|
/// auto stopChargingGuard = MakeFnGuard([&]{
|
||||||
|
/// StopCharging(); // Stop playing charge effects
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// // Wait for N seconds (canceling if button is no longer held)
|
||||||
|
/// bIsFullyCharged = co_await WaitSeconds(chargeTime).CancelIf([&] {
|
||||||
|
/// return !Input->IsAttackButtonPressed();
|
||||||
|
/// });
|
||||||
|
/// } // <-- This is when StopCharging() will be called
|
||||||
|
/// FireShot(bIsFullyCharged);
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
///
|
||||||
|
/// In the above example, we can guarantee that StopCharging will logically be called exactly once for every call to
|
||||||
|
/// StartCharging(), even the ChargeAttackState() task is killed or canceled. Furthermore, we know that StopCharging()
|
||||||
|
/// will always be called prior to the call to FireShot().
|
||||||
|
///
|
||||||
|
/// In practice, it is often desirable to create more domain-specific scope guards for specific use cases, but
|
||||||
|
/// FunctionGuard provides a simple general-purpose tool for writing robust, water-tight coroutine logic without the
|
||||||
|
/// overhead of creating bespoke support classes.
|
||||||
|
|
||||||
|
//--- User configuration header ---//
|
||||||
|
#include "TasksConfig.h"
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
|
||||||
|
template <typename tFn = TFunction<void()>>
|
||||||
|
class FunctionGuard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FunctionGuard() = default; /// Default constructor
|
||||||
|
FunctionGuard(nullptr_t) /// Null-pointer constructor
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FunctionGuard(tFn in_fn) /// Functor constructor
|
||||||
|
: m_fn(MoveTemp(in_fn))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~FunctionGuard() /// Destructor
|
||||||
|
{
|
||||||
|
Execute();
|
||||||
|
}
|
||||||
|
FunctionGuard(FunctionGuard&& in_other) noexcept /// Move constructor
|
||||||
|
: m_fn(MoveTemp(in_other.m_fn))
|
||||||
|
{
|
||||||
|
in_other.Forget();
|
||||||
|
}
|
||||||
|
FunctionGuard& operator=(FunctionGuard<tFn>&& in_other) noexcept /// Move assignment operator
|
||||||
|
{
|
||||||
|
m_fn = MoveTemp(in_other.m_fn);
|
||||||
|
in_other.Forget();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
FunctionGuard& operator=(nullptr_t) noexcept /// Null-pointer assignment operator (calls Forget() to clear the functor)
|
||||||
|
{
|
||||||
|
Forget();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
operator bool() const /// Convenience conversion operator that calls IsBound()
|
||||||
|
{
|
||||||
|
return IsBound();
|
||||||
|
}
|
||||||
|
bool IsBound() noexcept /// Returns whether functor has been bound to this FunctionGuard
|
||||||
|
{
|
||||||
|
return m_fn;
|
||||||
|
}
|
||||||
|
void Execute() /// Executes and clears the functor (if bound)
|
||||||
|
{
|
||||||
|
if(m_fn)
|
||||||
|
{
|
||||||
|
m_fn.GetValue()();
|
||||||
|
Forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Forget() noexcept /// Clear the functor (without calling it)
|
||||||
|
{
|
||||||
|
m_fn.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TOptional<tFn> m_fn; // The function to call when this scope guard is destroyed
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create a function guard (directly stores the concretely-typed functor in the FunctionGuard)
|
||||||
|
template <typename tFn>
|
||||||
|
FunctionGuard<tFn> MakeFnGuard(tFn in_fn)
|
||||||
|
{
|
||||||
|
return FunctionGuard<tFn>(MoveTemp(in_fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a generic function guard (preferable when re-assigning new functor values to the same variable)
|
||||||
|
inline FunctionGuard<> MakeGenericFnGuard(TFunction<void()> in_fn)
|
||||||
|
{
|
||||||
|
return FunctionGuard<>(MoveTemp(in_fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
|
||||||
|
///@} end of FunctionGuard group
|
@ -0,0 +1,220 @@
|
|||||||
|
// WARNING: This is an internal implementation header, which must be included from a specific location/namespace
|
||||||
|
// That is the reason that this header does not contain a #pragma once, nor namespace guards
|
||||||
|
|
||||||
|
// Helper struct representing a transition event to a new FSM state
|
||||||
|
struct TransitionEvent
|
||||||
|
{
|
||||||
|
Task<> newTask;
|
||||||
|
StateId newStateId;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base class for defining links between states
|
||||||
|
class LinkBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~LinkBase() = default;
|
||||||
|
virtual TOptional<TransitionEvent> EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Type-safe link handle
|
||||||
|
class LinkHandle
|
||||||
|
{
|
||||||
|
bool IsOnCompleteLink() const
|
||||||
|
{
|
||||||
|
return m_linkType == eType::OnComplete;
|
||||||
|
}
|
||||||
|
bool HasCondition() const
|
||||||
|
{
|
||||||
|
return m_isConditionalLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Link-type enum
|
||||||
|
enum class eType
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
OnComplete,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Friends
|
||||||
|
template<class, class> friend class StateHandle;
|
||||||
|
friend class ::TaskFSM;
|
||||||
|
|
||||||
|
// Constructors (friend-only)
|
||||||
|
LinkHandle() = delete;
|
||||||
|
LinkHandle(TSharedPtr<LinkBase> in_link, eType in_linkType, bool in_isConditional)
|
||||||
|
: m_link(MoveTemp(in_link))
|
||||||
|
, m_linkType(in_linkType)
|
||||||
|
, m_isConditionalLink(in_isConditional)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
TOptional<TransitionEvent> EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const
|
||||||
|
{
|
||||||
|
return m_link->EvaluateLink(in_onTransitionFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TSharedPtr<LinkBase> m_link; // The underlying link
|
||||||
|
eType m_linkType; // Whether the link is normal or OnComplete
|
||||||
|
bool m_isConditionalLink; // Whether the link has an associated condition predicate
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal FSM state object
|
||||||
|
template<class tStateInput, class tStateConstructorFn>
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
State(tStateConstructorFn in_stateCtorFn, StateId in_stateId, FString in_debugName)
|
||||||
|
: stateCtorFn(in_stateCtorFn)
|
||||||
|
, stateId(in_stateId)
|
||||||
|
, debugName(in_debugName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
tStateConstructorFn stateCtorFn;
|
||||||
|
StateId stateId;
|
||||||
|
FString debugName;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal FSM state object (exit state specialization)
|
||||||
|
template<>
|
||||||
|
struct State<void, void>
|
||||||
|
{
|
||||||
|
State(StateId in_stateId, FString in_debugName)
|
||||||
|
: stateId(in_stateId)
|
||||||
|
, debugName(in_debugName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
StateId stateId;
|
||||||
|
FString debugName;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal link definition object
|
||||||
|
template<class ReturnT, class tStateConstructorFn, class tPredicateFn>
|
||||||
|
class Link : public LinkBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Link(TSharedPtr<State<ReturnT, tStateConstructorFn>> in_targetState, tPredicateFn in_predicate)
|
||||||
|
: m_targetState(MoveTemp(in_targetState))
|
||||||
|
, m_predicate(in_predicate)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual TOptional<TransitionEvent> EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const final
|
||||||
|
{
|
||||||
|
TOptional<TransitionEvent> result;
|
||||||
|
if(TOptional<ReturnT> payload = m_predicate())
|
||||||
|
{
|
||||||
|
if(in_onTransitionFn)
|
||||||
|
{
|
||||||
|
in_onTransitionFn();
|
||||||
|
}
|
||||||
|
result = TransitionEvent{ m_targetState->stateCtorFn(payload.GetValue()), m_targetState->stateId };
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedPtr<State<ReturnT, tStateConstructorFn>> m_targetState;
|
||||||
|
tPredicateFn m_predicate;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal link definition object (no-payload specialization)
|
||||||
|
template<class tStateConstructorFn, class tPredicateFn>
|
||||||
|
class Link<void, tStateConstructorFn, tPredicateFn> : public LinkBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Link(TSharedPtr<State<void, tStateConstructorFn>> in_targetState, tPredicateFn in_predicate)
|
||||||
|
: m_targetState(MoveTemp(in_targetState))
|
||||||
|
, m_predicate(in_predicate)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual TOptional<TransitionEvent> EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const final
|
||||||
|
{
|
||||||
|
TOptional<TransitionEvent> result;
|
||||||
|
if(m_predicate())
|
||||||
|
{
|
||||||
|
if(in_onTransitionFn)
|
||||||
|
{
|
||||||
|
in_onTransitionFn();
|
||||||
|
}
|
||||||
|
result = TransitionEvent{ m_targetState->stateCtorFn(), m_targetState->stateId };
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedPtr<State<void, tStateConstructorFn>> m_targetState;
|
||||||
|
tPredicateFn m_predicate;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal link definition object (exit-state specialization)
|
||||||
|
template<class tPredicateFn>
|
||||||
|
class Link<void, void, tPredicateFn> : public LinkBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Link(TSharedPtr<State<void, void>> in_targetState, tPredicateFn in_predicate)
|
||||||
|
: m_targetState(MoveTemp(in_targetState))
|
||||||
|
, m_predicate(in_predicate)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual TOptional<TransitionEvent> EvaluateLink(const tOnStateTransitionFn& in_onTransitionFn) const final
|
||||||
|
{
|
||||||
|
TOptional<TransitionEvent> result;
|
||||||
|
if(m_predicate())
|
||||||
|
{
|
||||||
|
if(in_onTransitionFn)
|
||||||
|
{
|
||||||
|
in_onTransitionFn();
|
||||||
|
}
|
||||||
|
result = TransitionEvent{ Task<>(), m_targetState->stateId };
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedPtr<State<void, void>> m_targetState;
|
||||||
|
tPredicateFn m_predicate;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialized type traits that deduce the first argument type of an arbitrary callable type
|
||||||
|
template <typename tRet, typename tArg>
|
||||||
|
static tArg get_first_arg_type(TFunction<tRet(tArg)> f); // Return type is first argument type
|
||||||
|
|
||||||
|
template <typename tRet>
|
||||||
|
static void get_first_arg_type(TFunction<tRet()> f); // Return type is void (function has no arguments)
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct function_traits : public function_traits<decltype(&T::operator())> // Generic callable objects (use operator())
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tRet, typename... tArgs> // Function
|
||||||
|
struct function_traits<tRet(tArgs...)>
|
||||||
|
{
|
||||||
|
using tFunction = TFunction<tRet(tArgs...)>;
|
||||||
|
using tArg = decltype(get_first_arg_type(tFunction()));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tRet, typename... tArgs> // Function ptr
|
||||||
|
struct function_traits<tRet(*)(tArgs...)>
|
||||||
|
{
|
||||||
|
using tFunction = TFunction<tRet(tArgs...)>;
|
||||||
|
using tArg = decltype(get_first_arg_type(tFunction()));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tClass, typename tRet, typename... tArgs> // Member function ptr (const)
|
||||||
|
struct function_traits<tRet(tClass::*)(tArgs...) const>
|
||||||
|
{
|
||||||
|
using tFunction = TFunction<tRet(tArgs...)>;
|
||||||
|
using tArg = decltype(get_first_arg_type(tFunction()));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tClass, typename tRet, typename... tArgs> // Member function ptr
|
||||||
|
struct function_traits<tRet(tClass::*)(tArgs...)>
|
||||||
|
{
|
||||||
|
using tFunction = TFunction<tRet(tArgs...)>;
|
||||||
|
using tArg = decltype(get_first_arg_type(tFunction()));
|
||||||
|
};
|
@ -0,0 +1,896 @@
|
|||||||
|
// WARNING: This is an internal implementation header, which must be included from a specific location/namespace
|
||||||
|
// That is the reason that this header does not contain a #pragma once, nor namespace guards
|
||||||
|
|
||||||
|
enum class eTaskRef;
|
||||||
|
template <typename tRet> class TaskPromise;
|
||||||
|
class TaskInternalBase;
|
||||||
|
template <typename tRet> class TaskInternal;
|
||||||
|
|
||||||
|
//--- tTaskReadyFn ---//
|
||||||
|
using tTaskReadyFn = TFunction<bool()>;
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto CancelTaskIf(Task<tRet, RefType, Resumable>&& in_task, tTaskCancelFn in_cancelFn);
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto StopTaskIf(Task<tRet, RefType, Resumable>&& in_task, tTaskCancelFn in_cancelFn);
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable, typename tTimeFn>
|
||||||
|
auto StopTaskIf(Task<tRet, RefType, Resumable>&& in_task, tTaskCancelFn in_cancelFn, tTaskTime in_timeout, tTimeFn in_timeFn);
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable, typename T>
|
||||||
|
auto StopTaskIf(Task<tRet, RefType, Resumable>&& in_task, tTaskCancelFn in_cancelFn, tTaskTime in_timeout);
|
||||||
|
|
||||||
|
//--- Suspend-If Awaiter ---//
|
||||||
|
struct SuspendIf
|
||||||
|
{
|
||||||
|
SuspendIf(bool in_suspend)
|
||||||
|
: m_suspend(in_suspend)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
bool await_ready() noexcept { return !m_suspend; }
|
||||||
|
void await_suspend(std::coroutine_handle<>) noexcept {}
|
||||||
|
void await_resume() noexcept {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_suspend;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- Task Debug Stack Formatter ---//
|
||||||
|
struct TaskDebugStackFormatter
|
||||||
|
{
|
||||||
|
// Format function (formats a debug output string) [virtual]
|
||||||
|
virtual FString Format(const FString& in_str) const
|
||||||
|
{
|
||||||
|
FString result = Indent(0);
|
||||||
|
int32_t indent = 0;
|
||||||
|
int32_t start = 0;
|
||||||
|
int32_t found = 0;
|
||||||
|
while((found = in_str.FindChar('\n', start)) != INDEX_NONE)
|
||||||
|
{
|
||||||
|
int32_t end = found + 1;
|
||||||
|
if((found < in_str.Len() - 1) && (in_str[found + 1] == '`')) // indent
|
||||||
|
{
|
||||||
|
++indent;
|
||||||
|
++end;
|
||||||
|
}
|
||||||
|
else if((found >= 1) && (in_str[found - 1] == '`')) // dedent
|
||||||
|
{
|
||||||
|
--indent;
|
||||||
|
--found;
|
||||||
|
}
|
||||||
|
result += in_str.Mid(start, found - start) + '\n' + Indent(indent);
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
result += in_str.Mid(start);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
virtual FString Indent(int32_t in_indent) const
|
||||||
|
{
|
||||||
|
return FString::ChrN(in_indent * 2, ' ');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static FString FormatDebugString(FString in_str)
|
||||||
|
{
|
||||||
|
in_str.ReplaceCharInline('\n', ' ');
|
||||||
|
in_str.LeftChopInline(32, false);
|
||||||
|
return in_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- SetDebugName Awaiter ---//
|
||||||
|
#if SQUID_ENABLE_TASK_DEBUG
|
||||||
|
struct SetDebugName
|
||||||
|
{
|
||||||
|
// Sets a Task's debug name field
|
||||||
|
SetDebugName(const char* in_name)
|
||||||
|
: m_name(in_name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
SetDebugName(const char* in_name, TFunction<FString()> in_dataFn)
|
||||||
|
: m_name(in_name)
|
||||||
|
, m_dataFn(in_dataFn)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename tRet> friend class TaskPromiseBase;
|
||||||
|
const char* m_name = nullptr;
|
||||||
|
TFunction<FString()> m_dataFn;
|
||||||
|
};
|
||||||
|
#endif //SQUID_ENABLE_TASK_DEBUG
|
||||||
|
|
||||||
|
//--- AddStopTask Awaiter ---//
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
struct AddStopTaskAwaiter
|
||||||
|
{
|
||||||
|
AddStopTaskAwaiter(Task<tRet, RefType, Resumable>& in_taskToStop)
|
||||||
|
: m_taskToStop(&in_taskToStop)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename tRet> friend class TaskPromiseBase;
|
||||||
|
Task<tRet, RefType, Resumable>* m_taskToStop = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto AddStopTask(Task<tRet, RefType, Resumable>& in_taskToStop)
|
||||||
|
{
|
||||||
|
return AddStopTaskAwaiter<tRet, RefType, Resumable>(in_taskToStop);
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- RemoveStopTask Awaiter ---//
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
struct RemoveStopTaskAwaiter
|
||||||
|
{
|
||||||
|
RemoveStopTaskAwaiter(Task<tRet, RefType, Resumable>& in_taskToStop)
|
||||||
|
: m_taskToStop(&in_taskToStop)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename tRet> friend class TaskPromiseBase;
|
||||||
|
Task<tRet, RefType, Resumable>* m_taskToStop = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto RemoveStopTask(Task<tRet, RefType, Resumable>& in_taskToStop)
|
||||||
|
{
|
||||||
|
return RemoveStopTaskAwaiter<tRet, RefType, Resumable>(in_taskToStop);
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- Task Awaiter ---//
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable, typename promise_type>
|
||||||
|
struct TaskAwaiterBase
|
||||||
|
{
|
||||||
|
TaskAwaiterBase(const Task<tRet, RefType, Resumable>& in_task)
|
||||||
|
{
|
||||||
|
// This constructor exists to minimize downstream compile-error spam when co_awaiting a non-copyable Task by copy
|
||||||
|
}
|
||||||
|
TaskAwaiterBase(Task<tRet, RefType, Resumable>&& in_task)
|
||||||
|
: m_task(MoveTemp(in_task))
|
||||||
|
{
|
||||||
|
SQUID_RUNTIME_CHECK(m_task.IsValid(), "Tried to await an invalid task");
|
||||||
|
}
|
||||||
|
TaskAwaiterBase(TaskAwaiterBase&& in_taskAwaiter) noexcept
|
||||||
|
{
|
||||||
|
m_task = MoveTemp(in_taskAwaiter.m_task);
|
||||||
|
}
|
||||||
|
bool await_ready() noexcept
|
||||||
|
{
|
||||||
|
if(m_task.IsDone())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
template <eTaskResumable UResumable = Resumable, typename std::enable_if_t<UResumable == eTaskResumable::Yes>* = nullptr>
|
||||||
|
bool await_suspend(std::coroutine_handle<promise_type> in_coroHandle) noexcept
|
||||||
|
{
|
||||||
|
// Set the sub-task on the suspending task
|
||||||
|
auto& promise = in_coroHandle.promise();
|
||||||
|
auto taskInternal = promise.GetInternalTask();
|
||||||
|
auto subTaskInternal = m_task.GetInternalTask();
|
||||||
|
if(taskInternal->IsStopRequested())
|
||||||
|
{
|
||||||
|
subTaskInternal->RequestStop(); // Propagate any stop request to new sub-tasks
|
||||||
|
}
|
||||||
|
taskInternal->SetSubTask(StaticCastSharedPtr<TaskInternalBase>(subTaskInternal));
|
||||||
|
|
||||||
|
// Resume the task
|
||||||
|
if(m_task.Resume() == eTaskStatus::Done)
|
||||||
|
{
|
||||||
|
taskInternal->SetSubTask(nullptr);
|
||||||
|
return false; // Do not suspend, because the task is done
|
||||||
|
}
|
||||||
|
return true; // Suspend, because the task is not done
|
||||||
|
}
|
||||||
|
template <eTaskResumable UResumable = Resumable, typename std::enable_if_t<UResumable == eTaskResumable::No>* = nullptr>
|
||||||
|
bool await_suspend(std::coroutine_handle<promise_type> in_coroHandle) noexcept
|
||||||
|
{
|
||||||
|
auto& promise = in_coroHandle.promise();
|
||||||
|
if(!m_task.IsDone())
|
||||||
|
{
|
||||||
|
promise.SetReadyFunction([this] { return m_task.IsDone(); });
|
||||||
|
return true; // Suspend, because the task is not done
|
||||||
|
}
|
||||||
|
return false; // Do not suspend, because the task is done
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
auto GetInternalTask() const
|
||||||
|
{
|
||||||
|
return m_task.GetInternalTask();
|
||||||
|
}
|
||||||
|
Task<tRet, RefType, Resumable> m_task;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable, typename promise_type>
|
||||||
|
struct TaskAwaiter : public TaskAwaiterBase<tRet, RefType, Resumable, promise_type>
|
||||||
|
{
|
||||||
|
using TaskAwaiterBase<tRet, RefType, Resumable, promise_type>::TaskAwaiterBase;
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
auto await_resume()
|
||||||
|
{
|
||||||
|
this->m_task.RethrowUnhandledException(); // Re-throw any exceptions
|
||||||
|
auto retVal = this->m_task.TakeReturnValue();
|
||||||
|
SQUID_RUNTIME_CHECK(retVal, "Awaited task return value is unset");
|
||||||
|
return MoveTemp(retVal.GetValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
|
||||||
|
void await_resume()
|
||||||
|
{
|
||||||
|
this->m_task.RethrowUnhandledException(); // Re-throw any exceptions
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- Future Awaiter ---//
|
||||||
|
template <typename tRet, typename promise_type>
|
||||||
|
struct FutureAwaiter
|
||||||
|
{
|
||||||
|
FutureAwaiter(TFuture<tRet>&& in_future)
|
||||||
|
: m_future(MoveTemp(in_future))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~FutureAwaiter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FutureAwaiter(FutureAwaiter&& in_futureAwaiter) noexcept
|
||||||
|
{
|
||||||
|
m_future = MoveTemp(in_futureAwaiter.m_future);
|
||||||
|
}
|
||||||
|
bool await_ready() noexcept
|
||||||
|
{
|
||||||
|
bool isReady = m_future.IsReady();
|
||||||
|
return isReady;
|
||||||
|
}
|
||||||
|
bool await_suspend(std::coroutine_handle<promise_type> in_coroHandle) noexcept
|
||||||
|
{
|
||||||
|
// Set the ready function
|
||||||
|
auto& promise = in_coroHandle.promise();
|
||||||
|
|
||||||
|
// Suspend if future is not ready
|
||||||
|
bool shouldSuspend = !m_future.IsReady();
|
||||||
|
if(shouldSuspend)
|
||||||
|
{
|
||||||
|
promise.SetReadyFunction([this] { return m_future.IsReady(); });
|
||||||
|
}
|
||||||
|
return shouldSuspend;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
auto await_resume()
|
||||||
|
{
|
||||||
|
return m_future.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
|
||||||
|
void await_resume()
|
||||||
|
{
|
||||||
|
m_future.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TFuture<tRet> m_future;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- Shared Future Awaiter ---//
|
||||||
|
template <typename tRet, typename promise_type>
|
||||||
|
struct SharedFutureAwaiter
|
||||||
|
{
|
||||||
|
SharedFutureAwaiter(const TSharedFuture<tRet>& in_sharedFuture)
|
||||||
|
: m_sharedFuture(in_sharedFuture)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
bool await_ready() noexcept
|
||||||
|
{
|
||||||
|
bool isReady = m_sharedFuture.IsReady();
|
||||||
|
return isReady;
|
||||||
|
}
|
||||||
|
bool await_suspend(std::coroutine_handle<promise_type> in_coroHandle) noexcept
|
||||||
|
{
|
||||||
|
// Set the ready function
|
||||||
|
auto& promise = in_coroHandle.promise();
|
||||||
|
|
||||||
|
// Suspend if future is not ready
|
||||||
|
bool shouldSuspend = !m_sharedFuture.IsReady();
|
||||||
|
if(shouldSuspend)
|
||||||
|
{
|
||||||
|
promise.SetReadyFunction([this] { return m_sharedFuture.IsReady(); });
|
||||||
|
}
|
||||||
|
return shouldSuspend;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
auto await_resume()
|
||||||
|
{
|
||||||
|
return m_sharedFuture.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U = tRet, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
|
||||||
|
void await_resume()
|
||||||
|
{
|
||||||
|
m_sharedFuture.Get(); // Trigger any pending errors
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TSharedFuture<tRet> m_sharedFuture;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- TaskPromiseBase ---//
|
||||||
|
template <typename tRet>
|
||||||
|
class alignas(16) TaskPromiseBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Type aliases
|
||||||
|
using promise_type = TaskPromise<tRet>;
|
||||||
|
using tTaskInternal = TaskInternal<tRet>;
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~TaskPromiseBase()
|
||||||
|
{
|
||||||
|
// NOTE: Destructor is non-virtual, because it is always handled + destroyed as its concrete type
|
||||||
|
m_taskInternal->OnTaskPromiseDestroyed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coroutine interface functions
|
||||||
|
auto initial_suspend() noexcept
|
||||||
|
{
|
||||||
|
return std::suspend_always();
|
||||||
|
}
|
||||||
|
auto final_suspend() noexcept
|
||||||
|
{
|
||||||
|
return std::suspend_always();
|
||||||
|
}
|
||||||
|
auto get_return_object()
|
||||||
|
{
|
||||||
|
return std::coroutine_handle<promise_type>::from_promise(*static_cast<promise_type*>(this));
|
||||||
|
}
|
||||||
|
static TSharedPtr<tTaskInternal> get_return_object_on_allocation_failure()
|
||||||
|
{
|
||||||
|
SQUID_THROW(std::bad_alloc(), "Failed to allocate memory for Task");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// HACK: Coroutines in UE5 under MSVC is currently causing a memory underrun
|
||||||
|
// These allocators are a workaround for the issue (as is alignas(16))
|
||||||
|
void* operator new(size_t Size) noexcept
|
||||||
|
{
|
||||||
|
const size_t WorkaroundAlign = std::alignment_of<TaskPromiseBase>();
|
||||||
|
Size += WorkaroundAlign;
|
||||||
|
return (void*)((uint8_t*)FMemory::Malloc(Size, WorkaroundAlign) + WorkaroundAlign);
|
||||||
|
}
|
||||||
|
void operator delete(void* Ptr) noexcept
|
||||||
|
{
|
||||||
|
const size_t WorkaroundAlign = std::alignment_of<TaskPromiseBase>();
|
||||||
|
auto OffsetPtr = (uint8_t*)Ptr - WorkaroundAlign;
|
||||||
|
FMemory::Free(OffsetPtr);
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if SQUID_NEEDS_UNHANDLED_EXCEPTION
|
||||||
|
void unhandled_exception() noexcept
|
||||||
|
{
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
// Propagate exceptions for handling
|
||||||
|
m_taskInternal->SetUnhandledException(std::current_exception());
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
}
|
||||||
|
#endif // SQUID_NEEDS_UNHANDLED_EXCEPTION
|
||||||
|
|
||||||
|
// Internal Task
|
||||||
|
void SetInternalTask(tTaskInternal* in_taskInternal)
|
||||||
|
{
|
||||||
|
m_taskInternal = in_taskInternal;
|
||||||
|
}
|
||||||
|
tTaskInternal* GetInternalTask()
|
||||||
|
{
|
||||||
|
return m_taskInternal;
|
||||||
|
}
|
||||||
|
const tTaskInternal* GetInternalTask() const
|
||||||
|
{
|
||||||
|
return m_taskInternal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ready Function
|
||||||
|
void SetReadyFunction(const tTaskReadyFn& in_taskReadyFn)
|
||||||
|
{
|
||||||
|
m_taskInternal->SetReadyFunction(in_taskReadyFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Await-Transforms
|
||||||
|
auto await_transform(Suspend in_awaiter)
|
||||||
|
{
|
||||||
|
return in_awaiter;
|
||||||
|
}
|
||||||
|
auto await_transform(std::suspend_never in_awaiter)
|
||||||
|
{
|
||||||
|
return in_awaiter;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SQUID_ENABLE_TASK_DEBUG
|
||||||
|
auto await_transform(SetDebugName in_awaiter)
|
||||||
|
{
|
||||||
|
m_taskInternal->SetDebugName(in_awaiter.m_name);
|
||||||
|
m_taskInternal->SetDebugDataFn(in_awaiter.m_dataFn);
|
||||||
|
return std::suspend_never();
|
||||||
|
}
|
||||||
|
#endif //SQUID_ENABLE_TASK_DEBUG
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto await_transform(AddStopTaskAwaiter<tRet, RefType, Resumable> in_awaiter)
|
||||||
|
{
|
||||||
|
m_taskInternal->AddStopTask(*in_awaiter.m_taskToStop);
|
||||||
|
return std::suspend_never();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
auto await_transform(RemoveStopTaskAwaiter<tRet, RefType, Resumable> in_awaiter)
|
||||||
|
{
|
||||||
|
m_taskInternal->RemoveStopTask(*in_awaiter.m_taskToStop);
|
||||||
|
return std::suspend_never();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto await_transform(GetStopContext in_awaiter)
|
||||||
|
{
|
||||||
|
struct GetStopContextAwaiter : public std::suspend_never
|
||||||
|
{
|
||||||
|
GetStopContextAwaiter(StopContext in_stopCtx)
|
||||||
|
: stopCtx(in_stopCtx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
auto await_resume() noexcept
|
||||||
|
{
|
||||||
|
return stopCtx;
|
||||||
|
}
|
||||||
|
StopContext stopCtx;
|
||||||
|
};
|
||||||
|
GetStopContextAwaiter stopCtxAwaiter{ m_taskInternal->GetStopContext() };
|
||||||
|
return stopCtxAwaiter;
|
||||||
|
}
|
||||||
|
auto await_transform(const tTaskReadyFn& in_taskReadyFn)
|
||||||
|
{
|
||||||
|
// Check if we are already ready, and suspend if we are not
|
||||||
|
bool isReady = in_taskReadyFn();
|
||||||
|
if(!isReady)
|
||||||
|
{
|
||||||
|
m_taskInternal->SetReadyFunction(in_taskReadyFn);
|
||||||
|
}
|
||||||
|
return SuspendIf(!isReady); // Suspend if the function isn't already ready
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename tFutureRet>
|
||||||
|
auto await_transform(TFuture<tFutureRet>&& in_future)
|
||||||
|
{
|
||||||
|
return FutureAwaiter<tFutureRet, promise_type>(MoveTemp(in_future));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename tFutureRet>
|
||||||
|
auto await_transform(const TSharedFuture<tFutureRet>& in_sharedFuture)
|
||||||
|
{
|
||||||
|
return SharedFutureAwaiter<tFutureRet, promise_type>(in_sharedFuture);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task Await-Transforms
|
||||||
|
template <typename tTaskRet, eTaskRef RefType, eTaskResumable Resumable,
|
||||||
|
typename std::enable_if_t<Resumable == eTaskResumable::Yes>* = nullptr>
|
||||||
|
auto await_transform(Task<tTaskRet, RefType, Resumable>&& in_task) // Move version
|
||||||
|
{
|
||||||
|
return TaskAwaiter<tTaskRet, RefType, Resumable, promise_type>(MoveTemp(in_task));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename tTaskRet, eTaskRef RefType, eTaskResumable Resumable,
|
||||||
|
typename std::enable_if_t<Resumable == eTaskResumable::No>* = nullptr>
|
||||||
|
auto await_transform(Task<tTaskRet, RefType, Resumable> in_task) // Copy version (Non-Resumable)
|
||||||
|
{
|
||||||
|
return TaskAwaiter<tTaskRet, RefType, Resumable, promise_type>(MoveTemp(in_task));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename tTaskRet, eTaskRef RefType, eTaskResumable Resumable,
|
||||||
|
typename std::enable_if_t<Resumable == eTaskResumable::Yes>* = nullptr>
|
||||||
|
auto await_transform(const Task<tTaskRet, RefType, Resumable>& in_task) // Invalid copy version (Resumable)
|
||||||
|
{
|
||||||
|
static_assert(static_false<tTaskRet>::value, "Cannot await a non-copyable (resumable) Task by copy (try co_await MoveTemp(task), co_await WeakTaskHandle(task), or co_await task.WaitUntilDone()");
|
||||||
|
return TaskAwaiter<tTaskRet, RefType, Resumable, promise_type>(MoveTemp(in_task));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
tTaskInternal* m_taskInternal = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- TaskPromise ---//
|
||||||
|
template <typename tRet>
|
||||||
|
class TaskPromise : public TaskPromiseBase<tRet>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Return value access
|
||||||
|
void return_value(const tRet& in_retVal) // Copy return value
|
||||||
|
{
|
||||||
|
this->m_taskInternal->SetReturnValue(in_retVal);
|
||||||
|
}
|
||||||
|
void return_value(tRet&& in_retVal) // Move return value
|
||||||
|
{
|
||||||
|
this->m_taskInternal->SetReturnValue(MoveTemp(in_retVal));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class TaskPromise<void> : public TaskPromiseBase<void>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void return_void()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- TaskInternalBase ---//
|
||||||
|
class TaskInternalBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TaskInternalBase(std::coroutine_handle<> in_coroHandle)
|
||||||
|
: m_coroHandle(in_coroHandle)
|
||||||
|
{
|
||||||
|
SQUID_RUNTIME_CHECK(m_coroHandle, "Invalid coroutine handle passed into Task");
|
||||||
|
}
|
||||||
|
~TaskInternalBase() // NOTE: Destructor is intentionally non-virtual (shared_ptr preserves concrete type via deleter)
|
||||||
|
{
|
||||||
|
Kill(); // Used for killing subtasks
|
||||||
|
}
|
||||||
|
StopContext GetStopContext() const
|
||||||
|
{
|
||||||
|
return { &m_isStopRequested };
|
||||||
|
}
|
||||||
|
bool IsStopRequested() const
|
||||||
|
{
|
||||||
|
return m_isStopRequested;
|
||||||
|
}
|
||||||
|
void RequestStop() // Propagates a request for the task to come to a 'graceful' stop
|
||||||
|
{
|
||||||
|
m_isStopRequested = true;
|
||||||
|
for(auto& stopTask : m_stopTasks)
|
||||||
|
{
|
||||||
|
if(auto locked = stopTask.Pin())
|
||||||
|
{
|
||||||
|
locked->RequestStop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_stopTasks.SetNum(0);
|
||||||
|
}
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
void AddStopTask(Task<tRet, RefType, Resumable>& in_taskToStop) // Adds a task to the list of tasks to which we propagate stop requests
|
||||||
|
{
|
||||||
|
if(m_isStopRequested)
|
||||||
|
{
|
||||||
|
in_taskToStop.RequestStop();
|
||||||
|
}
|
||||||
|
else if(in_taskToStop.IsValid())
|
||||||
|
{
|
||||||
|
m_stopTasks.Add(in_taskToStop.GetInternalTask());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable>
|
||||||
|
void RemoveStopTask(Task<tRet, RefType, Resumable>& in_taskToStop) // Removes a task to the list of tasks to which we propagate stop requests
|
||||||
|
{
|
||||||
|
if(in_taskToStop.IsValid())
|
||||||
|
{
|
||||||
|
for(int32_t i = 0; i < m_stopTasks.Num(); ++i)
|
||||||
|
{
|
||||||
|
if(m_stopTasks[i].Pin() == in_taskToStop.GetInternalTask())
|
||||||
|
{
|
||||||
|
m_stopTasks[i] = m_stopTasks.Last();
|
||||||
|
m_stopTasks.Pop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eTaskStatus Resume() // Returns whether the task is still running
|
||||||
|
{
|
||||||
|
// Make sure this task is not already mid-resume
|
||||||
|
SQUID_RUNTIME_CHECK(m_internalState != eInternalState::Resuming, "Attempted to resume Task while already resumed");
|
||||||
|
|
||||||
|
// Task is destroyed, therefore task is done
|
||||||
|
if(m_internalState == eInternalState::Destroyed)
|
||||||
|
{
|
||||||
|
return eTaskStatus::Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark task as resuming
|
||||||
|
m_internalState = eInternalState::Resuming;
|
||||||
|
|
||||||
|
// Resume any active sub-task
|
||||||
|
if(m_subTaskInternal)
|
||||||
|
{
|
||||||
|
// Propagate any stop requests to sub-task prior to resuming
|
||||||
|
if(m_isStopRequested)
|
||||||
|
{
|
||||||
|
m_subTaskInternal->m_isStopRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resume the sub-task
|
||||||
|
if(m_subTaskInternal->Resume() != eTaskStatus::Done)
|
||||||
|
{
|
||||||
|
m_internalState = eInternalState::Idle;
|
||||||
|
return eTaskStatus::Suspended; // Sub-task not done, therefore task is not done
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the sub-task
|
||||||
|
m_subTaskInternal = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resume task, if necessary
|
||||||
|
if(CanResume())
|
||||||
|
{
|
||||||
|
m_taskReadyFn = nullptr; // Clear any ready function we were waiting on
|
||||||
|
m_coroHandle.resume(); // Resume the underlying std::coroutine_handle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return to idle state and return current task status
|
||||||
|
auto taskStatus = m_coroHandle.done() ? eTaskStatus::Done : eTaskStatus::Suspended;
|
||||||
|
if(taskStatus == eTaskStatus::Done)
|
||||||
|
{
|
||||||
|
m_isDone = true; // Mark task done
|
||||||
|
}
|
||||||
|
m_internalState = eInternalState::Idle;
|
||||||
|
return taskStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub-task
|
||||||
|
void SetSubTask(TSharedPtr<TaskInternalBase> in_subTaskInternal)
|
||||||
|
{
|
||||||
|
m_subTaskInternal = in_subTaskInternal;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SQUID_ENABLE_TASK_DEBUG
|
||||||
|
// Debug task name + stack
|
||||||
|
FString GetDebugName() const
|
||||||
|
{
|
||||||
|
return (!IsDone() && m_debugDataFn) ? (FString(m_debugName) + " [" + m_debugDataFn() + "]") : m_debugName;
|
||||||
|
}
|
||||||
|
FString GetDebugStack() const
|
||||||
|
{
|
||||||
|
FString result = m_subTaskInternal ? (GetDebugName() + " -> " + m_subTaskInternal->GetDebugStack()) : GetDebugName();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
void SetDebugName(const char* in_debugName)
|
||||||
|
{
|
||||||
|
if(in_debugName)
|
||||||
|
{
|
||||||
|
m_debugName = in_debugName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SetDebugDataFn(TFunction<FString()> in_debugDataFn)
|
||||||
|
{
|
||||||
|
m_debugDataFn = in_debugDataFn;
|
||||||
|
}
|
||||||
|
#endif //SQUID_ENABLE_TASK_DEBUG
|
||||||
|
|
||||||
|
// Exceptions
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
std::exception_ptr GetUnhandledException() const
|
||||||
|
{
|
||||||
|
if(m_isExceptionSet)
|
||||||
|
{
|
||||||
|
return m_exception;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
|
||||||
|
protected:
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
// Internal implementation of exception-setting (called by TaskInternal<> child classes)
|
||||||
|
void InternalSetUnhandledException(std::exception_ptr in_exception)
|
||||||
|
{
|
||||||
|
// NOTE: This must never be called more than once in the lifetime of an internal task
|
||||||
|
SQUID_RUNTIME_CHECK(!m_isExceptionSet, "Exception was set for a task after it had already been set");
|
||||||
|
if(!m_isExceptionSet)
|
||||||
|
{
|
||||||
|
m_exception = in_exception;
|
||||||
|
m_isExceptionSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename tRet> friend class TaskPromiseBase;
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable, typename promise_type> friend struct TaskAwaiterBase;
|
||||||
|
template <typename tRet, eTaskRef RefType, eTaskResumable Resumable> friend class Task;
|
||||||
|
|
||||||
|
// Kill this task
|
||||||
|
void Kill() // Kill() can safely be called multiple times
|
||||||
|
{
|
||||||
|
SQUID_RUNTIME_CHECK(m_internalState != eInternalState::Resuming, "Attempted to kill Task while resumed");
|
||||||
|
if(m_internalState == eInternalState::Idle)
|
||||||
|
{
|
||||||
|
// Mark task done
|
||||||
|
m_isDone = true;
|
||||||
|
|
||||||
|
// First destroy any sub-tasks
|
||||||
|
if(m_subTaskInternal)
|
||||||
|
{
|
||||||
|
m_subTaskInternal->Kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the underlying std::coroutine_handle
|
||||||
|
m_coroHandle.destroy(); // This should only ever be called directly from this one place
|
||||||
|
m_coroHandle = nullptr;
|
||||||
|
m_taskReadyFn = nullptr; // Clear out the ready function
|
||||||
|
m_internalState = eInternalState::Destroyed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done + can-resume status
|
||||||
|
void SetReadyFunction(const tTaskReadyFn& in_taskReadyFn)
|
||||||
|
{
|
||||||
|
m_taskReadyFn = in_taskReadyFn;
|
||||||
|
}
|
||||||
|
bool CanResume() const
|
||||||
|
{
|
||||||
|
if(IsDone())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(m_subTaskInternal)
|
||||||
|
{
|
||||||
|
bool canResume = m_subTaskInternal->CanResume();
|
||||||
|
return canResume;
|
||||||
|
}
|
||||||
|
bool isReady = !m_taskReadyFn || m_taskReadyFn();
|
||||||
|
return isReady;
|
||||||
|
}
|
||||||
|
bool IsDone() const
|
||||||
|
{
|
||||||
|
return m_isDone;
|
||||||
|
}
|
||||||
|
bool m_isDone = false;
|
||||||
|
|
||||||
|
// Internal state
|
||||||
|
enum class eInternalState
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
Resuming,
|
||||||
|
Destroyed,
|
||||||
|
};
|
||||||
|
eInternalState m_internalState = eInternalState::Idle;
|
||||||
|
|
||||||
|
// Task ready condition (when awaiting a TFunction<bool>)
|
||||||
|
tTaskReadyFn m_taskReadyFn;
|
||||||
|
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
// Exceptions
|
||||||
|
std::exception_ptr m_exception = nullptr;
|
||||||
|
bool m_isExceptionSet = false;
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
|
||||||
|
// Sub-task
|
||||||
|
TSharedPtr<TaskInternalBase> m_subTaskInternal;
|
||||||
|
|
||||||
|
// Reference-counting (determines underlying std::coroutine_handle lifetime, not lifetime of this internal task)
|
||||||
|
void AddLogicalRef()
|
||||||
|
{
|
||||||
|
++m_refCount;
|
||||||
|
}
|
||||||
|
void RemoveLogicalRef()
|
||||||
|
{
|
||||||
|
--m_refCount;
|
||||||
|
if(m_refCount == 0)
|
||||||
|
{
|
||||||
|
Kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int32_t m_refCount = 0; // Number of (strong) non-weak tasks referencing the internal task
|
||||||
|
|
||||||
|
// C++ std::coroutine_handle
|
||||||
|
std::coroutine_handle<> m_coroHandle;
|
||||||
|
|
||||||
|
// Stop request
|
||||||
|
bool m_isStopRequested = false;
|
||||||
|
TArray<TWeakPtr<TaskInternalBase>> m_stopTasks;
|
||||||
|
|
||||||
|
#if SQUID_ENABLE_TASK_DEBUG
|
||||||
|
// Debug Data
|
||||||
|
const char* m_debugName = "[unnamed task]";
|
||||||
|
TFunction<FString()> m_debugDataFn;
|
||||||
|
#endif //SQUID_ENABLE_TASK_DEBUG
|
||||||
|
};
|
||||||
|
|
||||||
|
//--- TaskInternal ---//
|
||||||
|
template <typename tRet>
|
||||||
|
class TaskInternal : public TaskInternalBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using promise_type = TaskPromise<tRet>;
|
||||||
|
|
||||||
|
TaskInternal(std::coroutine_handle<promise_type> in_handle)
|
||||||
|
: TaskInternalBase(in_handle)
|
||||||
|
{
|
||||||
|
auto& promisePtr = in_handle.promise();
|
||||||
|
promisePtr.SetInternalTask(this);
|
||||||
|
}
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
void SetUnhandledException(std::exception_ptr in_exception)
|
||||||
|
{
|
||||||
|
m_retValState = eTaskRetValState::Orphaned; // Return value can never be set if there was an unhandled exception
|
||||||
|
InternalSetUnhandledException(in_exception);
|
||||||
|
}
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
void SetReturnValue(const tRet& in_retVal)
|
||||||
|
{
|
||||||
|
tRet retVal = in_retVal;
|
||||||
|
SetReturnValue(MoveTemp(retVal));
|
||||||
|
}
|
||||||
|
void SetReturnValue(tRet&& in_retVal)
|
||||||
|
{
|
||||||
|
if(m_retValState == eTaskRetValState::Unset)
|
||||||
|
{
|
||||||
|
m_retVal = MoveTemp(in_retVal);
|
||||||
|
m_retValState = eTaskRetValState::Set;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These conditions should (logically) never be met, but they are included in case future changes violate that constraint
|
||||||
|
SQUID_RUNTIME_CHECK(m_retValState != eTaskRetValState::Set, "Attempted to set a task's return value when it was already set");
|
||||||
|
SQUID_RUNTIME_CHECK(m_retValState != eTaskRetValState::Taken, "Attempted to set a task's return value after it was already taken");
|
||||||
|
SQUID_RUNTIME_CHECK(m_retValState != eTaskRetValState::Orphaned, "Attempted to set a task's return value after it was orphaned");
|
||||||
|
}
|
||||||
|
TOptional<tRet> TakeReturnValue()
|
||||||
|
{
|
||||||
|
// If the value has been set, mark it as taken and move-return the value
|
||||||
|
if(m_retValState == eTaskRetValState::Set)
|
||||||
|
{
|
||||||
|
m_retValState = eTaskRetValState::Taken;
|
||||||
|
return MoveTemp(m_retVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the value was not set, return an unset optional (checking that it was neither taken nor orphaned)
|
||||||
|
SQUID_RUNTIME_CHECK(m_retValState != eTaskRetValState::Taken, "Attempted to take a task's return value after it was already successfully taken");
|
||||||
|
SQUID_RUNTIME_CHECK(m_retValState != eTaskRetValState::Orphaned, "Attempted to take a task's return value that will never be set (task ended prematurely)");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
void OnTaskPromiseDestroyed()
|
||||||
|
{
|
||||||
|
// Mark the return value as orphaned if it was never set
|
||||||
|
m_retValState = eTaskRetValState::Orphaned;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Internal state
|
||||||
|
enum class eTaskRetValState
|
||||||
|
{
|
||||||
|
Unset, // Has not yet been set
|
||||||
|
Set, // Has been set and can be taken
|
||||||
|
Taken, // Has been taken and can no longer be taken
|
||||||
|
Orphaned, // Will never be set because the TaskPromise has been destroyed
|
||||||
|
};
|
||||||
|
|
||||||
|
eTaskRetValState m_retValState = eTaskRetValState::Unset; // Initially unset
|
||||||
|
TOptional<tRet> m_retVal;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class TaskInternal<void> : public TaskInternalBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using promise_type = TaskPromise<void>;
|
||||||
|
|
||||||
|
TaskInternal(std::coroutine_handle<promise_type> in_handle)
|
||||||
|
: TaskInternalBase(in_handle)
|
||||||
|
{
|
||||||
|
auto& promisePtr = in_handle.promise();
|
||||||
|
promisePtr.SetInternalTask(this);
|
||||||
|
}
|
||||||
|
#if SQUID_USE_EXCEPTIONS
|
||||||
|
void SetUnhandledException(std::exception_ptr in_exception)
|
||||||
|
{
|
||||||
|
InternalSetUnhandledException(in_exception);
|
||||||
|
}
|
||||||
|
#endif //SQUID_USE_EXCEPTIONS
|
||||||
|
void TakeReturnValue() // This function is an intentional no-op, to simplify certain templated function implementations
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void OnTaskPromiseDestroyed()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,236 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
//--- User configuration header ---//
|
||||||
|
#include "../TasksConfig.h"
|
||||||
|
|
||||||
|
// Namespace macros (enabled/disabled via SQUID_ENABLE_NAMESPACE)
|
||||||
|
#if SQUID_ENABLE_NAMESPACE
|
||||||
|
#define NAMESPACE_SQUID_BEGIN namespace Squid {
|
||||||
|
#define NAMESPACE_SQUID_END }
|
||||||
|
#define NAMESPACE_SQUID Squid
|
||||||
|
#else
|
||||||
|
#define NAMESPACE_SQUID_BEGIN
|
||||||
|
#define NAMESPACE_SQUID_END
|
||||||
|
#define NAMESPACE_SQUID
|
||||||
|
namespace Squid {} // Convenience to allow 'using namespace Squid' even when namespace is disabled
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Exception macros (to support environments with exceptions disabled)
|
||||||
|
#if SQUID_USE_EXCEPTIONS && (defined(__cpp_exceptions) || defined(__EXCEPTIONS))
|
||||||
|
#include <stdexcept>
|
||||||
|
#define SQUID_THROW(exception, errStr) throw exception;
|
||||||
|
#define SQUID_RUNTIME_ERROR(errStr) throw std::runtime_error(errStr);
|
||||||
|
#define SQUID_RUNTIME_CHECK(condition, errStr) if(!(condition)) throw std::runtime_error(errStr);
|
||||||
|
#else
|
||||||
|
#include <cassert>
|
||||||
|
#define SQUID_THROW(exception, errStr) assert(false && errStr);
|
||||||
|
#define SQUID_RUNTIME_ERROR(errStr) assert(false && errStr);
|
||||||
|
#define SQUID_RUNTIME_CHECK(condition, errStr) assert((condition) && errStr);
|
||||||
|
#endif //__cpp_exceptions
|
||||||
|
|
||||||
|
// Time Interface
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
#if SQUID_ENABLE_DOUBLE_PRECISION_TIME
|
||||||
|
using tTaskTime = double;
|
||||||
|
#else
|
||||||
|
using tTaskTime = float; // Defines time units for use with the Task system
|
||||||
|
#endif //SQUID_ENABLE_DOUBLE_PRECISION_TIME
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
|
||||||
|
// Coroutine de-optimization macros [DEPRECATED]
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if _MSC_VER >= 1920
|
||||||
|
// Newer versions of Visual Studio (>= VS2019) compile coroutines correctly
|
||||||
|
#define COROUTINE_OPTIMIZE_OFF
|
||||||
|
#define COROUTINE_OPTIMIZE_ON
|
||||||
|
#else
|
||||||
|
// Older versions of Visual Studio had code generation bugs when optimizing coroutines (they would compile, but have incorrect runtime results)
|
||||||
|
#define COROUTINE_OPTIMIZE_OFF __pragma(optimize("", off))
|
||||||
|
#define COROUTINE_OPTIMIZE_ON __pragma(optimize("", on))
|
||||||
|
#endif // _MSC_VER >= 1920
|
||||||
|
#else
|
||||||
|
// The Clang compiler has sometimes crashed when optimizing/inlining certain coroutines, so this macro can be used to disable inlining
|
||||||
|
#define COROUTINE_OPTIMIZE_OFF _Pragma("clang optimize off")
|
||||||
|
#define COROUTINE_OPTIMIZE_ON _Pragma("clang optimize on")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// False type for use in static_assert() [static_assert(false, ...) -> static_assert(static_false<T>, ...)]
|
||||||
|
template<typename T>
|
||||||
|
struct static_false : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine C++ Language Version
|
||||||
|
#if defined(_MSVC_LANG)
|
||||||
|
#define CPP_LANGUAGE_VERSION _MSVC_LANG
|
||||||
|
#elif defined(__cplusplus)
|
||||||
|
#define CPP_LANGUAGE_VERSION __cplusplus
|
||||||
|
#else
|
||||||
|
#define CPP_LANGUAGE_VERSION 0L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CPP_LANGUAGE_VERSION > 201703L // C++20 or higher
|
||||||
|
#define HAS_CXX17 1
|
||||||
|
#define HAS_CXX20 1
|
||||||
|
#elif CPP_LANGUAGE_VERSION > 201402L // C++17 or higher
|
||||||
|
#define HAS_CXX17 1
|
||||||
|
#define HAS_CXX20 0
|
||||||
|
#elif CPP_LANGUAGE_VERSION > 201103L // C++14 or higher
|
||||||
|
#define HAS_CXX17 0
|
||||||
|
#define HAS_CXX20 0
|
||||||
|
#else // C++11 or lower
|
||||||
|
#error Squid::Tasks requires C++14 or higher
|
||||||
|
#define HAS_CXX17 0
|
||||||
|
#define HAS_CXX20 0
|
||||||
|
#endif
|
||||||
|
#undef CPP_LANGUAGE_VERSION
|
||||||
|
|
||||||
|
// C++20 Compatibility (std::coroutine)
|
||||||
|
#if HAS_CXX20 || (defined(_MSVC_LANG) && defined(__cpp_lib_coroutine)) // Standard coroutines
|
||||||
|
#include <coroutine>
|
||||||
|
#define SQUID_EXPERIMENTAL_COROUTINES 0
|
||||||
|
#else // Experimental coroutines
|
||||||
|
#if defined(__clang__) && defined(_STL_COMPILER_PREPROCESSOR)
|
||||||
|
// HACK: Some distributions of clang don't have a <experimental/coroutine> header. We only need a few symbols, so just define them ourselves
|
||||||
|
namespace std {
|
||||||
|
namespace experimental {
|
||||||
|
inline namespace coroutines_v1 {
|
||||||
|
|
||||||
|
template <typename R, typename...> struct coroutine_traits {
|
||||||
|
using promise_type = typename R::promise_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Promise = void> struct coroutine_handle;
|
||||||
|
|
||||||
|
template <> struct coroutine_handle<void> {
|
||||||
|
static coroutine_handle from_address(void* addr) noexcept {
|
||||||
|
coroutine_handle me;
|
||||||
|
me.ptr = addr;
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
void operator()() { resume(); }
|
||||||
|
void* address() const { return ptr; }
|
||||||
|
void resume() const { __builtin_coro_resume(ptr); }
|
||||||
|
void destroy() const { __builtin_coro_destroy(ptr); }
|
||||||
|
bool done() const { return __builtin_coro_done(ptr); }
|
||||||
|
coroutine_handle& operator=(decltype(nullptr)) {
|
||||||
|
ptr = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
coroutine_handle(decltype(nullptr)) : ptr(nullptr) {}
|
||||||
|
coroutine_handle() : ptr(nullptr) {}
|
||||||
|
// void reset() { ptr = nullptr; } // add to P0057?
|
||||||
|
explicit operator bool() const { return ptr; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void* ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Promise> struct coroutine_handle : coroutine_handle<> {
|
||||||
|
using coroutine_handle<>::operator=;
|
||||||
|
|
||||||
|
static coroutine_handle from_address(void* addr) noexcept {
|
||||||
|
coroutine_handle me;
|
||||||
|
me.ptr = addr;
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise& promise() const {
|
||||||
|
return *reinterpret_cast<Promise*>(
|
||||||
|
__builtin_coro_promise(ptr, alignof(Promise), false));
|
||||||
|
}
|
||||||
|
static coroutine_handle from_promise(Promise& promise) {
|
||||||
|
coroutine_handle p;
|
||||||
|
p.ptr = __builtin_coro_promise(&promise, alignof(Promise), true);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _PromiseT>
|
||||||
|
bool operator==(coroutine_handle<_PromiseT> const& _Left,
|
||||||
|
coroutine_handle<_PromiseT> const& _Right) noexcept
|
||||||
|
{
|
||||||
|
return _Left.address() == _Right.address();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename _PromiseT>
|
||||||
|
bool operator!=(coroutine_handle<_PromiseT> const& _Left,
|
||||||
|
coroutine_handle<_PromiseT> const& _Right) noexcept
|
||||||
|
{
|
||||||
|
return !(_Left == _Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct suspend_always {
|
||||||
|
bool await_ready() noexcept { return false; }
|
||||||
|
void await_suspend(coroutine_handle<>) noexcept {}
|
||||||
|
void await_resume() noexcept {}
|
||||||
|
};
|
||||||
|
struct suspend_never {
|
||||||
|
bool await_ready() noexcept { return true; }
|
||||||
|
void await_suspend(coroutine_handle<>) noexcept {}
|
||||||
|
void await_resume() noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <experimental/coroutine>
|
||||||
|
#endif
|
||||||
|
namespace std // Alias experimental coroutine symbols into std namespace
|
||||||
|
{
|
||||||
|
template <class _Promise = void>
|
||||||
|
using coroutine_handle = experimental::coroutine_handle<_Promise>;
|
||||||
|
using suspend_never = experimental::suspend_never;
|
||||||
|
using suspend_always = experimental::suspend_always;
|
||||||
|
};
|
||||||
|
#define SQUID_EXPERIMENTAL_COROUTINES 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Determine whether our tasks need the member function "unhandled_exception()" defined or not
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
// MSVC's rules for exceptions differ between standard + experimental coroutines
|
||||||
|
#if SQUID_EXPERIMENTAL_COROUTINES
|
||||||
|
// If exceptions are enabled, we must define unhandled_exception()
|
||||||
|
#if defined(__cpp_exceptions) && __cpp_exceptions == 199711
|
||||||
|
#define SQUID_NEEDS_UNHANDLED_EXCEPTION 1
|
||||||
|
#else
|
||||||
|
#define SQUID_NEEDS_UNHANDLED_EXCEPTION 0
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// If we're using VS16.11 or newer -- or older than 16.10, we have one set of rules for standard coroutines
|
||||||
|
#if _MSC_FULL_VER >= 192930133L || _MSC_VER < 1429L
|
||||||
|
#define SQUID_NEEDS_UNHANDLED_EXCEPTION 1
|
||||||
|
#else
|
||||||
|
#if defined(__cpp_exceptions) && __cpp_exceptions == 199711
|
||||||
|
#define SQUID_NEEDS_UNHANDLED_EXCEPTION 1
|
||||||
|
#else
|
||||||
|
// 16.10 has a bug with their standard coroutine implementation that creates a set of contradicting requirements
|
||||||
|
// https://developercommunity.visualstudio.com/t/coroutine-uses-promise_type::unhandled_e/1374530
|
||||||
|
#error Visual Studio 16.10 has a compiler bug that prevents all coroutines from compiling when exceptions are disabled and using standard C++20 coroutines or /await:strict. Please either upgrade your version of Visual Studio, or use the experimental /await flag, or enable exceptions.
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Clang always requires unhandled_exception() to be defined
|
||||||
|
#define SQUID_NEEDS_UNHANDLED_EXCEPTION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// C++17 Compatibility ([[nodiscard]])
|
||||||
|
#if !defined(SQUID_NODISCARD) && defined(__has_cpp_attribute)
|
||||||
|
#if __has_cpp_attribute(nodiscard)
|
||||||
|
#define SQUID_NODISCARD [[nodiscard]]
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifndef SQUID_NODISCARD
|
||||||
|
#define SQUID_NODISCARD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef HAS_CXX17
|
||||||
|
#undef HAS_CXX20
|
||||||
|
|
||||||
|
// Include UE core headers
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Engine/World.h"
|
||||||
|
#include "Engine/Engine.h"
|
||||||
|
#include "Async/Future.h"
|
1153
unreal/Plugins/SquidTasks/Source/SquidTasks/Public/SquidTasks/Task.h
Normal file
1153
unreal/Plugins/SquidTasks/Source/SquidTasks/Public/SquidTasks/Task.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,331 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @defgroup TaskFSM Task FSM
|
||||||
|
/// @brief Finite state machine that implements states using task factories
|
||||||
|
/// @{
|
||||||
|
///
|
||||||
|
/// Full documentation of the TaskFSM system coming soon!
|
||||||
|
|
||||||
|
#include "Task.h"
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
|
||||||
|
class TaskFSM;
|
||||||
|
|
||||||
|
namespace FSM
|
||||||
|
{
|
||||||
|
// State ID wrapper
|
||||||
|
struct StateId
|
||||||
|
{
|
||||||
|
StateId() = default;
|
||||||
|
StateId(int32_t in_idx) : idx(in_idx) {}
|
||||||
|
StateId(size_t in_idx) : idx((int32_t)in_idx) {}
|
||||||
|
bool operator==(const StateId& other) const { return (other.idx == idx); }
|
||||||
|
bool operator!=(const StateId& other) const { return (other.idx != idx); }
|
||||||
|
bool IsValid() const { return idx != INT32_MAX; }
|
||||||
|
|
||||||
|
int32_t idx = INT32_MAX; // Default to invalid idx
|
||||||
|
};
|
||||||
|
|
||||||
|
// State transition debug data
|
||||||
|
struct TransitionDebugData
|
||||||
|
{
|
||||||
|
FSM::StateId oldStateId;
|
||||||
|
FString oldStateName;
|
||||||
|
FSM::StateId newStateId;
|
||||||
|
FString newStateName;
|
||||||
|
};
|
||||||
|
|
||||||
|
// State transition callback function
|
||||||
|
using tOnStateTransitionFn = TFunction<void()>;
|
||||||
|
|
||||||
|
#include "Private/TaskFSMPrivate.h" // Internal use only! Do not include elsewhere!
|
||||||
|
|
||||||
|
//--- State Handle ---//
|
||||||
|
template<class tStateInput, class tStateConstructorFn>
|
||||||
|
class StateHandle
|
||||||
|
{
|
||||||
|
using tPredicateRet = typename std::conditional<!std::is_void<tStateInput>::value, TOptional<tStateInput>, bool>::type;
|
||||||
|
using tPredicateFn = TFunction<tPredicateRet()>;
|
||||||
|
public:
|
||||||
|
StateHandle(StateHandle&& in_other) = default;
|
||||||
|
StateHandle& operator=(StateHandle&& in_other) = default;
|
||||||
|
|
||||||
|
StateId GetId() const //< Get the ID of this state
|
||||||
|
{
|
||||||
|
return m_state ? m_state->idx : StateId{};
|
||||||
|
}
|
||||||
|
|
||||||
|
// SFINAE Template Declaration Macros (#defines)
|
||||||
|
/// @cond
|
||||||
|
#define NONVOID_ONLY_WITH_PREDICATE template <class tPredicateFn, typename tPayload = tStateInput, typename std::enable_if_t<!std::is_void<tPayload>::value>* = nullptr>
|
||||||
|
#define VOID_ONLY_WITH_PREDICATE template <class tPredicateFn, typename tPayload = tStateInput, typename std::enable_if_t<std::is_void<tPayload>::value>* = nullptr>
|
||||||
|
#define NONVOID_ONLY template <typename tPayload = tStateInput, typename std::enable_if_t<!std::is_void<tPayload>::value && !std::is_convertible<tPayload, tPredicateFn>::value>* = nullptr>
|
||||||
|
#define VOID_ONLY template <typename tPayload = tStateInput, typename std::enable_if_t<std::is_void<tPayload>::value>* = nullptr>
|
||||||
|
#define PREDICATE_ONLY template <typename tPredicateFn, typename std::enable_if_t<!std::is_convertible<tStateInput, tPredicateFn>::value>* = nullptr>
|
||||||
|
/// @endcond
|
||||||
|
|
||||||
|
// Link methods
|
||||||
|
VOID_ONLY LinkHandle Link() //< Empty predicate link (always follow link)
|
||||||
|
{
|
||||||
|
return _InternalLink([] { return true; }, LinkHandle::eType::Normal);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY LinkHandle Link(tPayload in_payload) //< Empty predicate link w/ payload (always follow link, using provided payload)
|
||||||
|
{
|
||||||
|
return _InternalLink([payload = MoveTemp(in_payload)]() -> tPredicateRet { return payload; }, LinkHandle::eType::Normal);
|
||||||
|
}
|
||||||
|
PREDICATE_ONLY LinkHandle Link(tPredicateFn in_predicate) //< Predicate link w/ implicit payload (follow link when predicate returns a value; use return value as payload)
|
||||||
|
{
|
||||||
|
return _InternalLink(in_predicate, LinkHandle::eType::Normal);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY_WITH_PREDICATE LinkHandle Link(tPredicateFn in_predicate, tPayload in_payload) //< Predicate link w/ explicit payload (follow link when predicate returns true; use provided payload)
|
||||||
|
{
|
||||||
|
return _InternalLink(in_predicate, MoveTemp(in_payload), LinkHandle::eType::Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnCompleteLink methods
|
||||||
|
VOID_ONLY LinkHandle OnCompleteLink() //< Empty predicate link (always follow link)
|
||||||
|
{
|
||||||
|
return _InternalLink([] { return true; }, LinkHandle::eType::OnComplete);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY LinkHandle OnCompleteLink(tPayload in_payload) //< Empty predicate link w/ payload (always follow link, using provided payload)
|
||||||
|
{
|
||||||
|
return _InternalLink([payload = MoveTemp(in_payload)]() -> tPredicateRet { return payload; }, LinkHandle::eType::OnComplete);
|
||||||
|
}
|
||||||
|
PREDICATE_ONLY LinkHandle OnCompleteLink(tPredicateFn in_predicate) //< Predicate link w/ implicit payload (follow link when predicate returns a value; use return value as payload)
|
||||||
|
{
|
||||||
|
return _InternalLink(in_predicate, LinkHandle::eType::OnComplete, true);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY_WITH_PREDICATE LinkHandle OnCompleteLink(tPredicateFn in_predicate, tPayload in_payload) //< Predicate link w/ explicit payload (follow link when predicate returns true; use provided payload)
|
||||||
|
{
|
||||||
|
return _InternalLink(in_predicate, MoveTemp(in_payload), LinkHandle::eType::OnComplete, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ::TaskFSM;
|
||||||
|
|
||||||
|
StateHandle() = delete;
|
||||||
|
StateHandle(TSharedPtr<State<tStateInput, tStateConstructorFn>> InStatePtr)
|
||||||
|
: m_state(InStatePtr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
StateHandle(const StateHandle& Other) = delete;
|
||||||
|
StateHandle& operator=(const StateHandle& Other) = delete;
|
||||||
|
|
||||||
|
// Internal link function implementations
|
||||||
|
VOID_ONLY_WITH_PREDICATE LinkHandle _InternalLink(tPredicateFn in_predicate, LinkHandle::eType in_linkType, bool in_isConditional = false) // bool-returning predicate
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<bool, decltype(in_predicate())>::value, "This link requires a predicate function returning bool");
|
||||||
|
TSharedPtr<LinkBase> link = MakeShared<FSM::Link<tStateInput, tStateConstructorFn, tPredicateFn>>(m_state, in_predicate);
|
||||||
|
return LinkHandle(link, in_linkType, in_isConditional);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY_WITH_PREDICATE LinkHandle _InternalLink(tPredicateFn in_predicate, LinkHandle::eType in_linkType, bool in_isConditional = false) // optional-returning predicate
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<TOptional<tStateInput>, decltype(in_predicate())>::value, "This link requires a predicate function returning TOptional<tStateInput>");
|
||||||
|
TSharedPtr<LinkBase> link = MakeShared<FSM::Link<tStateInput, tStateConstructorFn, tPredicateFn>>(m_state, in_predicate);
|
||||||
|
return LinkHandle(link, in_linkType, in_isConditional);
|
||||||
|
}
|
||||||
|
NONVOID_ONLY_WITH_PREDICATE LinkHandle _InternalLink(tPredicateFn in_predicate, tPayload in_payload, LinkHandle::eType in_linkType, bool in_isConditional = false) // bool-returning predicate w/ fixed payload
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<bool, decltype(in_predicate())>::value, "This link requires a predicate function returning bool");
|
||||||
|
auto predicate = [in_predicate, in_payload]() -> TOptional<tStateInput>
|
||||||
|
{
|
||||||
|
return in_predicate() ? TOptional<tStateInput>(in_payload) : TOptional<tStateInput>{};
|
||||||
|
};
|
||||||
|
return _InternalLink(predicate, in_linkType, in_isConditional);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SFINAE Template Declaration Macros (#undefs)
|
||||||
|
#undef NONVOID_ONLY_WITH_PREDICATE
|
||||||
|
#undef VOID_ONLY_WITH_PREDICATE
|
||||||
|
#undef NONVOID_ONLY
|
||||||
|
#undef VOID_ONLY
|
||||||
|
#undef PREDICATE_ONLY
|
||||||
|
|
||||||
|
TSharedPtr<State<tStateInput, tStateConstructorFn>> m_state; // Internal state object
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace FSM
|
||||||
|
|
||||||
|
using StateId = FSM::StateId;
|
||||||
|
template<class tStateInput, class tStateConstructorFn>
|
||||||
|
using StateHandle = FSM::StateHandle<tStateInput, tStateConstructorFn>;
|
||||||
|
using TransitionDebugData = FSM::TransitionDebugData;
|
||||||
|
using tOnStateTransitionFn = FSM::tOnStateTransitionFn;
|
||||||
|
|
||||||
|
//--- TaskFSM ---//
|
||||||
|
class TaskFSM
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using tOnStateTransitionFn = TFunction<void()>;
|
||||||
|
using tDebugStateTransitionFn = TFunction<void(TransitionDebugData)>;
|
||||||
|
|
||||||
|
// Create a new FSM state [fancy param-deducing version (hopefully) coming soon!]
|
||||||
|
template<typename tStateConstructorFn>
|
||||||
|
auto State(FString in_name, tStateConstructorFn in_stateCtorFn)
|
||||||
|
{
|
||||||
|
typedef FSM::function_traits<tStateConstructorFn> tFnTraits;
|
||||||
|
using tStateInput = typename tFnTraits::tArg;
|
||||||
|
const FSM::StateId newStateId = m_states.Num();
|
||||||
|
m_states.Add(InternalStateData(in_name));
|
||||||
|
auto state = MakeShared<FSM::State<tStateInput, tStateConstructorFn>>(MoveTemp(in_stateCtorFn), newStateId, in_name);
|
||||||
|
return FSM::StateHandle<tStateInput, tStateConstructorFn>{ state };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new FSM exit state (immediately terminates the FSM when executed)
|
||||||
|
FSM::StateHandle<void, void> State(FString in_name)
|
||||||
|
{
|
||||||
|
const FSM::StateId newStateId = m_states.Num();
|
||||||
|
m_states.Add(InternalStateData(in_name));
|
||||||
|
m_exitStates.Add(newStateId);
|
||||||
|
auto state = MakeShared<FSM::State<void, void>>(newStateId, in_name);
|
||||||
|
return FSM::StateHandle<void, void>{ state };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the initial entry links into the state machine
|
||||||
|
void EntryLinks(TArray<FSM::LinkHandle> in_entryLinks);
|
||||||
|
|
||||||
|
// Define all outgoing links from a given state (may only be called once per state)
|
||||||
|
template<class tStateInput, class tStateConstructorFn>
|
||||||
|
void StateLinks(const FSM::StateHandle<tStateInput, tStateConstructorFn>& in_originState, TArray<FSM::LinkHandle> in_outgoingLinks);
|
||||||
|
|
||||||
|
// Begins execution of the state machine (returns id of final exit state)
|
||||||
|
Task<FSM::StateId> Run(tOnStateTransitionFn in_onTransitionFn = {}, tDebugStateTransitionFn in_debugStateTransitionFn = {}) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Evaluates all possible outgoing links from the current state, returning the first valid transition (if any transitions are valid)
|
||||||
|
TOptional<FSM::TransitionEvent> EvaluateLinks(FSM::StateId in_curStateId, bool in_isCurrentStateComplete, const tOnStateTransitionFn& in_onTransitionFn) const;
|
||||||
|
|
||||||
|
// Internal state
|
||||||
|
struct InternalStateData
|
||||||
|
{
|
||||||
|
InternalStateData(FString in_debugName)
|
||||||
|
: debugName(in_debugName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
TArray<FSM::LinkHandle> outgoingLinks;
|
||||||
|
FString debugName;
|
||||||
|
};
|
||||||
|
TArray<InternalStateData> m_states;
|
||||||
|
TArray<FSM::LinkHandle> m_entryLinks;
|
||||||
|
TArray<FSM::StateId> m_exitStates;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @} end of group TaskFSM
|
||||||
|
|
||||||
|
//--- TaskFSM Methods ---//
|
||||||
|
template<class tStateInput, class tStateConstructorFn>
|
||||||
|
void TaskFSM::StateLinks(const FSM::StateHandle<tStateInput, tStateConstructorFn>& in_originState, TArray<FSM::LinkHandle> in_outgoingLinks)
|
||||||
|
{
|
||||||
|
const int32_t stateIdx = in_originState.m_state->stateId.idx;
|
||||||
|
SQUID_RUNTIME_CHECK(m_states[stateIdx].outgoingLinks.Num() == 0, "Cannot set outgoing links more than once for each state");
|
||||||
|
|
||||||
|
// Validate that there are exactly 0 or 1 unconditional OnComplete links (there may be any number of other OnComplete links, but only one with no condition)
|
||||||
|
int32_t numOnCompleteLinks = 0;
|
||||||
|
int32_t numOnCompleteLinks_Unconditional = 0;
|
||||||
|
for(const FSM::LinkHandle& link : in_outgoingLinks)
|
||||||
|
{
|
||||||
|
if(link.IsOnCompleteLink())
|
||||||
|
{
|
||||||
|
SQUID_RUNTIME_CHECK(numOnCompleteLinks_Unconditional == 0, "Cannot call OnCompleteLink() after calling OnCompleteLink() with no conditions (unreachable link)");
|
||||||
|
++numOnCompleteLinks;
|
||||||
|
if(!link.HasCondition())
|
||||||
|
{
|
||||||
|
numOnCompleteLinks_Unconditional++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SQUID_RUNTIME_CHECK(numOnCompleteLinks == 0 || numOnCompleteLinks_Unconditional > 0, "More than one unconditional OnCompleteLink() was set");
|
||||||
|
|
||||||
|
// Set the outgoing links for the origin state
|
||||||
|
m_states[stateIdx].outgoingLinks = MoveTemp(in_outgoingLinks);
|
||||||
|
}
|
||||||
|
inline void TaskFSM::EntryLinks(TArray<FSM::LinkHandle> in_entryLinks)
|
||||||
|
{
|
||||||
|
// Validate to ensure there are no OnComplete links set as entry links
|
||||||
|
int32_t numOnCompleteLinks = 0;
|
||||||
|
for(const FSM::LinkHandle& link : in_entryLinks)
|
||||||
|
{
|
||||||
|
if(link.IsOnCompleteLink())
|
||||||
|
{
|
||||||
|
++numOnCompleteLinks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SQUID_RUNTIME_CHECK(numOnCompleteLinks == 0, "EntryLinks() list may not contain any OnCompleteLink() links");
|
||||||
|
|
||||||
|
// Set the entry links list for this FSM
|
||||||
|
m_entryLinks = MoveTemp(in_entryLinks);
|
||||||
|
}
|
||||||
|
inline TOptional<FSM::TransitionEvent> TaskFSM::EvaluateLinks(FSM::StateId in_curStateId, bool in_isCurrentStateComplete, const tOnStateTransitionFn& in_onTransitionFn) const
|
||||||
|
{
|
||||||
|
// Determine whether to use entry links or state-specific outgoing links
|
||||||
|
const TArray<FSM::LinkHandle>& links = (in_curStateId.idx < m_states.Num()) ? m_states[in_curStateId.idx].outgoingLinks : m_entryLinks;
|
||||||
|
|
||||||
|
// Find the first valid transition from the current state
|
||||||
|
for(const FSM::LinkHandle& link : links)
|
||||||
|
{
|
||||||
|
if(!link.IsOnCompleteLink() || in_isCurrentStateComplete) // Skip link evaluation check for OnComplete links unless current state is complete
|
||||||
|
{
|
||||||
|
if(auto result = link.EvaluateLink(in_onTransitionFn)) // Check if the transition to this state is valid
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}; // No valid transition was found
|
||||||
|
}
|
||||||
|
inline Task<FSM::StateId> TaskFSM::Run(tOnStateTransitionFn in_onTransitionFn, tDebugStateTransitionFn in_debugStateTransitionFn) const
|
||||||
|
{
|
||||||
|
// Task-local variables
|
||||||
|
FSM::StateId curStateId; // The current state's ID
|
||||||
|
Task<> task; // The current state's task
|
||||||
|
|
||||||
|
// Custom debug task name logic
|
||||||
|
TASK_NAME(__FUNCTION__, [this, &curStateId, &task]
|
||||||
|
{
|
||||||
|
const auto stateName = m_states.IsValidIndex(curStateId.idx) ? m_states[curStateId.idx].debugName : "";
|
||||||
|
return FString::Printf(TEXT("%s -- %s"), *stateName, *task.GetDebugStack());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Debug state transition lambda
|
||||||
|
auto DebugStateTransition = [this, in_debugStateTransitionFn](FSM::StateId in_oldStateId, FSM::StateId in_newStateId) {
|
||||||
|
if(in_debugStateTransitionFn)
|
||||||
|
{
|
||||||
|
FString oldStateName = in_oldStateId.IsValid() ? m_states[in_oldStateId.idx].debugName : FString("<ENTRY>");
|
||||||
|
FString newStateName = m_states[in_newStateId.idx].debugName;
|
||||||
|
in_debugStateTransitionFn({ in_oldStateId, MoveTemp(oldStateName), in_newStateId, MoveTemp(newStateName) });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Main FSM loop
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// Evaluate links, checking for a valid transition
|
||||||
|
if(TOptional<FSM::TransitionEvent> transition = EvaluateLinks(curStateId, task.IsDone(), in_onTransitionFn))
|
||||||
|
{
|
||||||
|
auto newStateId = transition->newStateId;
|
||||||
|
DebugStateTransition(curStateId, newStateId); // Call state-transition debug function
|
||||||
|
|
||||||
|
// If the transition is to an exit state, return that state ID (terminating the FSM)
|
||||||
|
if(m_exitStates.Contains(newStateId.idx))
|
||||||
|
{
|
||||||
|
co_return newStateId;
|
||||||
|
}
|
||||||
|
SQUID_RUNTIME_CHECK(newStateId.idx < m_states.Num(), "It should be logically impossible to get an invalid state to this point");
|
||||||
|
|
||||||
|
// Begin running new state (implicitly killing old state)
|
||||||
|
curStateId = newStateId;
|
||||||
|
co_await RemoveStopTask(task);
|
||||||
|
task = MoveTemp(transition->newTask); // NOTE: Initial call to Resume() happens below
|
||||||
|
co_await AddStopTask(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resume current state
|
||||||
|
task.Resume();
|
||||||
|
|
||||||
|
// Suspend until next frame
|
||||||
|
co_await Suspend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_END
|
@ -0,0 +1,215 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @defgroup TaskManager Task Manager
|
||||||
|
/// @brief Manager that runs and resumes a collection of tasks.
|
||||||
|
/// @{
|
||||||
|
///
|
||||||
|
/// A TaskManager is a simple manager class that holds an ordered list of tasks and resumes them whenever it is updated.
|
||||||
|
///
|
||||||
|
/// Running Tasks
|
||||||
|
/// -------------
|
||||||
|
/// There are two primary ways to run tasks on a task manager.
|
||||||
|
///
|
||||||
|
/// The first method (running an "unmanaged task") is to pass a task into @ref TaskManager::Run(). This will move the task
|
||||||
|
/// into the task manager and return a @ref TaskHandle that can be used to observe and manage the lifetime of the task (as well
|
||||||
|
/// as potentially take a return value after the task finishes). With unmanaged tasks, the task manager only holds a weak
|
||||||
|
/// reference to the task, meaning that the @ref TaskHandle returned by @ref TaskManager::Run() is the only remaining strong
|
||||||
|
/// reference to the task. Because of this, the caller is entirely responsible for managing the lifetime of the task.
|
||||||
|
///
|
||||||
|
/// The second method (running a "managed task") is to pass a task into @ref TaskManager::RunManaged(). Like
|
||||||
|
/// @ref TaskManager::Run(), this will move the task into the task manager and return a @ref WeakTaskHandle that can be used to
|
||||||
|
/// observe the lifetime of the task (as well as manually kill it, if desired). Unlike unmanaged tasks, the task manager
|
||||||
|
/// stores a strong reference to the task. Because of this, that caller is not responsible for managing the lifetime of
|
||||||
|
/// the task. This difference in task ownership means that (unlike an unmanaged task) a managed task can be thought of as
|
||||||
|
/// a "fire-and-forget" task that will run until either it finishes or until something else explicitly kills it.
|
||||||
|
///
|
||||||
|
/// Order of Execution
|
||||||
|
/// ------------------
|
||||||
|
/// The ordering of task updates within a call to @ref TaskManager::Update() is stable, meaning that the first task that
|
||||||
|
/// is run on a task manager will remain the first to resume, no matter how many other tasks are run on the task manager
|
||||||
|
/// (or terminate) in the meantime.
|
||||||
|
///
|
||||||
|
/// Integration into Actor Classes
|
||||||
|
/// ------------------------------
|
||||||
|
/// Consider the following example of a TaskManager that has been integrated into a TaskActor base class:
|
||||||
|
///
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||||
|
///
|
||||||
|
/// class TaskActor : public Actor
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
/// virtual void OnInitialize() override // Automatically called when this enemy enters the scene
|
||||||
|
/// {
|
||||||
|
/// Actor::OnInitialize(); // Call the base Actor function
|
||||||
|
/// m_taskMgr.RunManaged(ManageActor()); // Run main actor task as a fire-and-forget "managed task"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// virtual void Tick(float in_dt) override // Automatically called every frame
|
||||||
|
/// {
|
||||||
|
/// Actor::Tick(in_dt); // Call the base Actor function
|
||||||
|
/// m_taskMgr.Update(); // Resume all active tasks once per tick
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// virtual void OnDestroy() override // Automatically called when this enemy leaves the scene
|
||||||
|
/// {
|
||||||
|
/// m_taskMgr.KillAllTasks(); // Kill all active tasks when we leave the scene
|
||||||
|
/// Actor::OnDestroy(); // Call the base Actor function
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// protected:
|
||||||
|
/// virtual Task<> ManageActor() // Overridden (in its entirety) by child classes
|
||||||
|
/// {
|
||||||
|
/// co_await WaitForever(); // Waits forever (doing nothing)
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// TaskManager m_taskMgr;
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
///
|
||||||
|
/// In the above example, TaskManager is instantiated once per high-level actor. It is updated once per frame within
|
||||||
|
/// the Tick() method, and all its tasks are killed when it leaves the scene in OnDestroy(). Lastly, a single entry-point
|
||||||
|
/// coroutine is run as a managed task when the actor enters the scene. (The above is the conventional method of integration
|
||||||
|
/// into this style of game engine.)
|
||||||
|
///
|
||||||
|
/// Note that it is sometimes necessary to have multiple TaskManagers within a single actor. For example, if there are
|
||||||
|
/// multiple tick functions (such as one for pre-physics updates and one for post-physics updates), then instantiating
|
||||||
|
/// a second "post-physics" task manager may be desirable.
|
||||||
|
|
||||||
|
#include "Task.h"
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
|
||||||
|
//--- TaskManager ---//
|
||||||
|
/// Manager that runs and resumes a collection of tasks.
|
||||||
|
class TaskManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~TaskManager() {} /// Destructor (disables copy/move construction + assignment)
|
||||||
|
|
||||||
|
/// @brief Run an unmanaged task
|
||||||
|
/// @details Run() return a @ref TaskHandle<> that holds a strong reference to the task. If there are ever no
|
||||||
|
/// strong references remaining to an unmanaged task, it will immediately be killed and removed from the manager.
|
||||||
|
template <typename tRet>
|
||||||
|
SQUID_NODISCARD TaskHandle<tRet> Run(Task<tRet>&& in_task)
|
||||||
|
{
|
||||||
|
// Run unmanaged task
|
||||||
|
TaskHandle<tRet> taskHandle = in_task;
|
||||||
|
WeakTask weakTask = MoveTemp(in_task);
|
||||||
|
RunWeakTask(MoveTemp(weakTask));
|
||||||
|
return taskHandle;
|
||||||
|
}
|
||||||
|
template <typename tRet>
|
||||||
|
SQUID_NODISCARD TaskHandle<tRet> Run(const Task<tRet>& in_task) /// @private Illegal copy implementation
|
||||||
|
{
|
||||||
|
static_assert(static_false<tRet>::value, "Cannot run an unmanaged task by copy (try Run(MoveTemp(task)))");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Run a managed task
|
||||||
|
/// @details RunManaged() return a @ref WeakTaskHandle, meaning it can be used to run a "fire-and-forget" background
|
||||||
|
/// task in situations where it is not necessary to observe or control task lifetime.
|
||||||
|
template <typename tRet>
|
||||||
|
WeakTaskHandle RunManaged(Task<tRet>&& in_task)
|
||||||
|
{
|
||||||
|
// Run managed task
|
||||||
|
WeakTaskHandle weakTaskHandle = in_task;
|
||||||
|
m_strongRefs.Add(Run(MoveTemp(in_task)));
|
||||||
|
return weakTaskHandle;
|
||||||
|
}
|
||||||
|
template <typename tRet>
|
||||||
|
WeakTaskHandle RunManaged(const Task<tRet>& in_task) /// @private Illegal copy implementation
|
||||||
|
{
|
||||||
|
static_assert(static_false<tRet>::value, "Cannot run a managed task by copy (try RunManaged(MoveTemp(task)))");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Run a weak task
|
||||||
|
/// @details RunWeakTask() runs a WeakTask. The caller is assumed to have already created a strong TaskHandle<> that
|
||||||
|
/// references the WeakTask, thus keeping it from being killed. When the last strong reference to the WeakTask is
|
||||||
|
/// destroyed, the task will immediately be killed and removed from the manager.
|
||||||
|
void RunWeakTask(WeakTask&& in_task)
|
||||||
|
{
|
||||||
|
// Run unmanaged task
|
||||||
|
m_tasks.Add(MoveTemp(in_task));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call Task::Kill() on all tasks (managed + unmanaged)
|
||||||
|
void KillAllTasks()
|
||||||
|
{
|
||||||
|
m_tasks.Reset(); // Destroying all the weak tasks implicitly destroys all internal tasks
|
||||||
|
|
||||||
|
// No need to call Kill() on each TaskHandle in m_strongRefs
|
||||||
|
m_strongRefs.Reset(); // Handles in the strong refs array only ever point to tasks in the now-cleared m_tasks array
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Issue a stop request using @ref Task::RequestStop() on all active tasks (managed and unmanaged)
|
||||||
|
/// @details Returns a new awaiter task that will wait until all those tasks have all terminated.
|
||||||
|
Task<> StopAllTasks()
|
||||||
|
{
|
||||||
|
// Request stop on all tasks
|
||||||
|
TArray<WeakTaskHandle> weakHandles;
|
||||||
|
for(auto& task : m_tasks)
|
||||||
|
{
|
||||||
|
task.RequestStop();
|
||||||
|
weakHandles.Add(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a fence task that waits until all stopped tasks are complete
|
||||||
|
return [](TArray<WeakTaskHandle> in_weakHandles) -> Task<> {
|
||||||
|
TASK_NAME("StopAllTasks() Fence Task");
|
||||||
|
for(const auto& weakHandle : in_weakHandles)
|
||||||
|
{
|
||||||
|
co_await weakHandle; // Wait until task is complete
|
||||||
|
}
|
||||||
|
}(MoveTemp(weakHandles));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call @ref Task::Resume() on all active tasks exactly once (managed + unmanaged)
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
// Resume all tasks
|
||||||
|
int32 writeIdx = 0;
|
||||||
|
for(int32 readIdx = 0; readIdx < m_tasks.Num(); ++readIdx)
|
||||||
|
{
|
||||||
|
if(m_tasks[readIdx].Resume() != eTaskStatus::Done)
|
||||||
|
{
|
||||||
|
if(writeIdx != readIdx)
|
||||||
|
{
|
||||||
|
m_tasks[writeIdx] = MoveTemp(m_tasks[readIdx]);
|
||||||
|
}
|
||||||
|
++writeIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_tasks.SetNum(writeIdx);
|
||||||
|
|
||||||
|
// Prune strong tasks that are done
|
||||||
|
m_strongRefs.RemoveAllSwap([](const auto& in_taskHandle) { return in_taskHandle.IsDone(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a debug string containing a list of all active tasks
|
||||||
|
FString GetDebugString(TOptional<TaskDebugStackFormatter> in_formatter = {}) const
|
||||||
|
{
|
||||||
|
FString debugStr;
|
||||||
|
for(const auto& task : m_tasks)
|
||||||
|
{
|
||||||
|
if(!task.IsDone())
|
||||||
|
{
|
||||||
|
if(debugStr.Len())
|
||||||
|
{
|
||||||
|
debugStr += '\n';
|
||||||
|
}
|
||||||
|
debugStr += task.GetDebugStack(in_formatter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return debugStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TArray<WeakTask> m_tasks;
|
||||||
|
TArray<TaskHandle<>> m_strongRefs;
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
|
||||||
|
///@} end of TaskManager group
|
@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Squid::Tasks version (major.minor.patch)
|
||||||
|
#define SQUID_TASKS_VERSION_MAJOR 0
|
||||||
|
#define SQUID_TASKS_VERSION_MINOR 2
|
||||||
|
#define SQUID_TASKS_VERSION_PATCH 0
|
||||||
|
|
||||||
|
/// @defgroup Config Configuration
|
||||||
|
/// @brief Configuration settings for the Squid::Tasks library
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Enables Task debug names and callstack tracking via Task::GetDebugStack() and Task::GetDebugName()
|
||||||
|
#ifndef SQUID_ENABLE_TASK_DEBUG
|
||||||
|
#define SQUID_ENABLE_TASK_DEBUG 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Switches time type (tTaskTime) from 32-bit single-precision floats to 64-bit double-precision floats
|
||||||
|
#ifndef SQUID_ENABLE_DOUBLE_PRECISION_TIME
|
||||||
|
#define SQUID_ENABLE_DOUBLE_PRECISION_TIME 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Wraps a Squid:: namespace around all classes in the Squid::Tasks library
|
||||||
|
#ifndef SQUID_ENABLE_NAMESPACE
|
||||||
|
#define SQUID_ENABLE_NAMESPACE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Enables experimental (largely-untested) exception handling, and replaces all asserts with runtime_error exceptions
|
||||||
|
#ifndef SQUID_USE_EXCEPTIONS
|
||||||
|
#define SQUID_USE_EXCEPTIONS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Enables global time support(alleviating the need to specify a time stream for time - sensitive awaiters) [see @ref GetGlobalTime()]
|
||||||
|
#ifndef SQUID_ENABLE_GLOBAL_TIME
|
||||||
|
// ***************
|
||||||
|
// *** WARNING ***
|
||||||
|
// ***************
|
||||||
|
// It is generally inadvisable for game projects to define a global task time, as it assumes there is only a single time-stream.
|
||||||
|
// Within game projects, there is usually a "game time" and "real time", as well as others (such as "audio time", "unpaused time").
|
||||||
|
// Furthermore, in engines such as Unreal, a non-static world context object must be provided.
|
||||||
|
|
||||||
|
// To enable global task time, user must *also* define a GetGlobalTime() implementation (otherwise there will be a linker error)
|
||||||
|
#define SQUID_ENABLE_GLOBAL_TIME 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// @} end of addtogroup Config
|
||||||
|
|
||||||
|
//--- C++17/C++20 Compatibility ---//
|
||||||
|
#include "Private/TasksCommonPrivate.h"
|
@ -0,0 +1,320 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @defgroup Tokens Token List
|
||||||
|
/// @brief Data structure for tracking decentralized state across multiple tasks.
|
||||||
|
/// @{
|
||||||
|
///
|
||||||
|
/// Token objects can be created using @ref TokenList::MakeToken(), returning a shared pointer to a new Token. This
|
||||||
|
/// new Token can then be added to the TokenList using @ref TokenList::AddToken(). @ref TokenList::TakeToken()
|
||||||
|
/// can be used to make + add a new token with a single function call.
|
||||||
|
///
|
||||||
|
/// Because TokenList uses weak pointers to track its elements, Token objects are logically removed from the list once
|
||||||
|
/// they are destroyed. As such, it is usually unnecessary to explicitly call @ref TokenList::RemoveToken() to remove a
|
||||||
|
/// Token from the list. Instead, it is idiomatic to consider the Token to be a sort of "scope guard" that will remove
|
||||||
|
/// itself from all TokenList objects when it leaves scope.
|
||||||
|
///
|
||||||
|
/// The TokenList class is included as part of Squid::Tasks to provide a simple mechanism for robustly sharing aribtrary
|
||||||
|
/// state between multiple tasks. Consider this example of a poison damage-over-time system:
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||||
|
///
|
||||||
|
/// class Character : public Actor
|
||||||
|
/// {
|
||||||
|
/// public:
|
||||||
|
/// bool IsPoisoned() const
|
||||||
|
/// {
|
||||||
|
/// return m_poisonTokens; // Whether there are any live poison tokens
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// void OnPoisoned(float in_dps, float in_duration)
|
||||||
|
/// {
|
||||||
|
/// m_taskMgr.RunManaged(ManagePoisonInstance(in_dps, in_duration));
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// private:
|
||||||
|
/// TokenList<float> m_poisonTokens; // Token list indicating live poison damage
|
||||||
|
///
|
||||||
|
/// Task<> ManagePoisonInstance(float in_dps, float in_duration)
|
||||||
|
/// {
|
||||||
|
/// // Take a poison token and hold it for N seconds
|
||||||
|
/// auto poisonToken = m_poisonTokens.TakeToken(__FUNCTION__, in_dps);
|
||||||
|
/// co_await WaitSeconds(in_duration);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Task<> ManageCharacter() // Called once per frame
|
||||||
|
/// {
|
||||||
|
/// while(true)
|
||||||
|
/// {
|
||||||
|
/// float poisonDps = m_poisonTokens.GetMax(); // Get highest DPS poison instance
|
||||||
|
/// DealDamage(poisonDps * GetDT()); // Deal the actual poison damage
|
||||||
|
/// co_await Suspend();
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
///
|
||||||
|
/// As the above example shows, this mechanism is well-suited for coroutines, as they can hold a Token across
|
||||||
|
/// multiple frames. Also note that Token objects can optionally hold data. The TokenList class has query functions
|
||||||
|
/// (e.g. GetMin()/GetMax()) that can be used to aggregate the data from the set of live tokens. This is used above
|
||||||
|
/// to quickly find the highest DPS poison instance.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
//--- User configuration header ---//
|
||||||
|
#include "TasksConfig.h"
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_BEGIN
|
||||||
|
|
||||||
|
template <typename T = void>
|
||||||
|
class TokenList;
|
||||||
|
|
||||||
|
/// @brief Handle to a TokenList element that stores a debug name
|
||||||
|
/// @details In most circumstances, name should be set to \ref __FUNCTION__ at the point of creation.
|
||||||
|
struct Token
|
||||||
|
{
|
||||||
|
Token(FString in_name)
|
||||||
|
: name(MoveTemp(in_name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FString name; // Used for debug only
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Handle to a TokenList element that stores both a debug name and associated data
|
||||||
|
/// @details In most circumstances, name should be set to \c __FUNCTION__ at the point of creation.
|
||||||
|
template <typename tData>
|
||||||
|
struct DataToken
|
||||||
|
{
|
||||||
|
DataToken(FString in_name, tData in_data)
|
||||||
|
: name(MoveTemp(in_name))
|
||||||
|
, data(MoveTemp(in_data))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FString name; // Used for debug only
|
||||||
|
tData data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create a token with the specified debug name
|
||||||
|
inline TSharedPtr<Token> MakeToken(FString in_name)
|
||||||
|
{
|
||||||
|
return MakeShared<Token>(MoveTemp(in_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a token with the specified debug name and associated data
|
||||||
|
template <typename tData>
|
||||||
|
TSharedPtr<DataToken<tData>> MakeToken(FString in_name, tData in_data)
|
||||||
|
{
|
||||||
|
return MakeShared<DataToken<tData>>(MoveTemp(in_name), MoveTemp(in_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Container for tracking decentralized state across multiple tasks. (See \ref Tokens for more info...)
|
||||||
|
/// @tparam T Type of data to associate with each Token in this container
|
||||||
|
template <typename T>
|
||||||
|
class TokenList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Type of Token tracked by this container
|
||||||
|
using Token = typename std::conditional_t<std::is_void<T>::value, Token, DataToken<T>>;
|
||||||
|
|
||||||
|
/// Create a token with the specified debug name
|
||||||
|
template <typename U = T, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
|
||||||
|
static TSharedPtr<Token> MakeToken(FString in_name)
|
||||||
|
{
|
||||||
|
return MakeShared<Token>(MoveTemp(in_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a token with the specified debug name and associated data
|
||||||
|
template <typename U = T, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
static TSharedPtr<Token> MakeToken(FString in_name, U in_data)
|
||||||
|
{
|
||||||
|
return MakeShared<Token>(MoveTemp(in_name), MoveTemp(in_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create and add a token with the specified debug name
|
||||||
|
template <typename U = T, typename std::enable_if_t<std::is_void<U>::value>* = nullptr>
|
||||||
|
SQUID_NODISCARD TSharedPtr<Token> TakeToken(FString in_name)
|
||||||
|
{
|
||||||
|
return AddToken(MakeToken(MoveTemp(in_name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create and add a token with the specified debug name and associated data
|
||||||
|
template <typename U = T, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
SQUID_NODISCARD TSharedPtr<Token> TakeToken(FString in_name, U in_data)
|
||||||
|
{
|
||||||
|
return AddToken(MakeToken(MoveTemp(in_name), MoveTemp(in_data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an existing token to this container
|
||||||
|
TSharedPtr<Token> AddToken(TSharedPtr<Token> in_token)
|
||||||
|
{
|
||||||
|
SQUID_RUNTIME_CHECK(in_token, "Cannot add null token");
|
||||||
|
Sanitize();
|
||||||
|
m_tokens.AddUnique(in_token);
|
||||||
|
return in_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Explicitly remove a token from this container
|
||||||
|
void RemoveToken(TSharedPtr<Token> in_token)
|
||||||
|
{
|
||||||
|
// Find and remove the token
|
||||||
|
m_tokens.Remove(in_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience conversion operator that calls HasTokens()
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return HasTokens();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this container holds any live tokens
|
||||||
|
bool HasTokens() const
|
||||||
|
{
|
||||||
|
// Return true when holding any unexpired tokens
|
||||||
|
for(auto i = (int32_t)(m_tokens.Num() - 1); i >= 0; --i)
|
||||||
|
{
|
||||||
|
const auto& token = m_tokens[i];
|
||||||
|
if(token.IsValid())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
m_tokens.Pop(); // Because the token is expired, we can safely remove it from the back
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an array of all live token data
|
||||||
|
TArray<T> GetTokenData() const
|
||||||
|
{
|
||||||
|
TArray<T> tokenData;
|
||||||
|
for(const auto& tokenWeak : m_tokens)
|
||||||
|
{
|
||||||
|
if(auto token = tokenWeak.Pin())
|
||||||
|
{
|
||||||
|
tokenData.Add(token->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tokenData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @name Data Queries
|
||||||
|
/// Methods for querying and aggregating the data from the set of live tokens.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// Returns associated data from the least-recently-added live token
|
||||||
|
TOptional<T> GetLeastRecent() const
|
||||||
|
{
|
||||||
|
Sanitize();
|
||||||
|
return m_tokens.Num() ? m_tokens[0].Pin()->data : TOptional<T>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns associated data from the most-recently-added live token
|
||||||
|
TOptional<T> GetMostRecent() const
|
||||||
|
{
|
||||||
|
Sanitize();
|
||||||
|
return m_tokens.Num() ? m_tokens.Last().Pin()->data : TOptional<T>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns smallest associated data from the set of live tokens
|
||||||
|
TOptional<T> GetMin() const
|
||||||
|
{
|
||||||
|
TOptional<T> ret;
|
||||||
|
SanitizeAndProcessData([&ret](const T& in_data) {
|
||||||
|
if(!ret || in_data < ret.GetValue())
|
||||||
|
{
|
||||||
|
ret = in_data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns largest associated data from the set of live tokens
|
||||||
|
TOptional<T> GetMax() const
|
||||||
|
{
|
||||||
|
TOptional<T> ret;
|
||||||
|
SanitizeAndProcessData([&ret](const T& in_data) {
|
||||||
|
if(!ret || in_data > ret.GetValue())
|
||||||
|
{
|
||||||
|
ret = in_data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns arithmetic mean of all associated data from the set of live tokens
|
||||||
|
TOptional<double> GetMean() const
|
||||||
|
{
|
||||||
|
TOptional<double> ret;
|
||||||
|
TOptional<double> total;
|
||||||
|
SanitizeAndProcessData([&total](const T& in_data) {
|
||||||
|
total = total.Get(0.0) + (double)in_data;
|
||||||
|
});
|
||||||
|
if(total)
|
||||||
|
{
|
||||||
|
ret = total.GetValue() / m_tokens.Num();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the set of live tokens contains at least one token associated with the specified data
|
||||||
|
template <typename U = T, typename std::enable_if_t<!std::is_void<U>::value>* = nullptr>
|
||||||
|
bool Contains(const U& in_searchData) const
|
||||||
|
{
|
||||||
|
bool containsData = false;
|
||||||
|
SanitizeAndProcessData([&in_searchData, &containsData](const T& in_data) {
|
||||||
|
if(in_searchData == in_data)
|
||||||
|
{
|
||||||
|
containsData = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return containsData;
|
||||||
|
}
|
||||||
|
///@} end of Data Queries
|
||||||
|
|
||||||
|
/// Returns a debug string containing a list of the debug names of all live tokens
|
||||||
|
FString GetDebugString() const
|
||||||
|
{
|
||||||
|
TArray<FString> tokenStrings;
|
||||||
|
for(auto token : m_tokens)
|
||||||
|
{
|
||||||
|
if(token.IsValid())
|
||||||
|
{
|
||||||
|
tokenStrings.Add(token.Pin()->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(tokenStrings.Num())
|
||||||
|
{
|
||||||
|
return FString::Join(tokenStrings, TEXT("\n"));
|
||||||
|
}
|
||||||
|
return TEXT("[no tokens]");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Sanitation
|
||||||
|
void Sanitize() const
|
||||||
|
{
|
||||||
|
// Remove all invalid tokens
|
||||||
|
m_tokens.RemoveAll([](const Wp<Token>& in_token) { return !in_token.IsValid(); });
|
||||||
|
}
|
||||||
|
template <typename tFn>
|
||||||
|
void SanitizeAndProcessData(tFn in_dataFn) const
|
||||||
|
{
|
||||||
|
// Remove all invalid tokens while applying a processing function on each valid token
|
||||||
|
m_tokens.RemoveAll([&in_dataFn](const TWeakPtr<Token>& in_token) {
|
||||||
|
if(auto pinnedToken = in_token.Pin())
|
||||||
|
{
|
||||||
|
in_dataFn(pinnedToken->data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token data
|
||||||
|
mutable TArray<TWeakPtr<Token>> m_tokens; // Mutable so we can remove expired tokens while converting bool
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_SQUID_END
|
||||||
|
|
||||||
|
///@} end of Tokens group
|
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SquidTasks/Task.h"
|
||||||
|
#include "SquidTasks/TaskManager.h"
|
||||||
|
#include "SquidTasks/TokenList.h"
|
||||||
|
#include "SquidTasks/FunctionGuard.h"
|
||||||
|
#include "SquidTasks/TaskFSM.h"
|
@ -0,0 +1,17 @@
|
|||||||
|
using UnrealBuildTool;
|
||||||
|
|
||||||
|
public class SquidTasks : ModuleRules
|
||||||
|
{
|
||||||
|
public SquidTasks(ReadOnlyTargetRules Target) : base(Target)
|
||||||
|
{
|
||||||
|
DefaultBuildSettings = BuildSettingsVersion.V2;
|
||||||
|
|
||||||
|
PublicDependencyModuleNames.AddRange(new string[] {
|
||||||
|
"Core",
|
||||||
|
"CoreUObject",
|
||||||
|
"Engine",
|
||||||
|
});
|
||||||
|
|
||||||
|
SharedPCHHeaderFile = "Public/SquidTasksSharedPCH.h";
|
||||||
|
}
|
||||||
|
}
|
25
unreal/Plugins/SquidTasks/SquidTasks.uplugin
Normal file
25
unreal/Plugins/SquidTasks/SquidTasks.uplugin
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"FileVersion": 1,
|
||||||
|
"Version": 1,
|
||||||
|
"VersionName": "1.0",
|
||||||
|
"FriendlyName": "SquidTasks",
|
||||||
|
"Description": "Giant Squid's Task Plugin",
|
||||||
|
"Category": "Other",
|
||||||
|
"CreatedBy": "Giant Squid",
|
||||||
|
"CreatedByURL": "",
|
||||||
|
"DocsURL": "",
|
||||||
|
"MarketplaceURL": "",
|
||||||
|
"SupportURL": "",
|
||||||
|
"EnabledByDefault": true,
|
||||||
|
"CanContainContent": true,
|
||||||
|
"IsBetaVersion": false,
|
||||||
|
"IsExperimentalVersion": false,
|
||||||
|
"Installed": false,
|
||||||
|
"Modules": [
|
||||||
|
{
|
||||||
|
"Name": "SquidTasks",
|
||||||
|
"Type": "Runtime",
|
||||||
|
"LoadingPhase": "Default"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user