Major clean up and reorganization

- Upgraded to Godot 4
- Just remembered the basic principles are based on a tile editor, and dramatically simplified from there. Derp.
- New state machine and license display add-ons.
- Re-licensed under the GPL because Micropolis' assets aren't under a separate one.
This commit is contained in:
Tony Bark 2023-03-14 06:17:27 -04:00
parent 55ed76c914
commit c980445340
337 changed files with 5129 additions and 7661 deletions

65
.gitattributes vendored
View file

@ -1,63 +1,2 @@
############################################################################### # Normalize EOL for all files that Git considers text files.
# Set default behavior to automatically normalize line endings. * text=auto eol=lf
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

View file

@ -1,32 +1,27 @@
name: Build Godot Project # name: Build Godot Project
on: # on:
push: # push:
branches: [main, develop, "releases/**"] # branches: [main, develop, "releases/**"]
pull_request: # pull_request:
branches: [main, develop, "releases/**"] # branches: [main, develop, "releases/**"]
jobs: # jobs:
Godot: # Godot:
timeout-minutes: 15 # timeout-minutes: 15
continue-on-error: true # continue-on-error: true
runs-on: ubuntu-latest # runs-on: ubuntu-latest
strategy: # strategy:
matrix: # matrix:
platform: [linux, windows] # platform: [linux, windows]
steps: # steps:
- uses: actions/checkout@v2 # - uses: actions/checkout@v2
with: # with:
lfs: true # lfs: true
- name: Build # - name: Build
id: build # id: build
uses: manleydev/build-godot-action@v1.4.1 # uses: manleydev/build-godot-action@v1.4.1
with: # with:
name: My Simulation # name: My Simulation
preset: ${{ matrix.platform }} # preset: ${{ matrix.platform }}
debugMode: "true" # debugMode: "true"
# - name: Upload Artifact
# uses: actions/upload-artifact@v2
# with:
# name: Client - ${{ matrix.platform }}
# path: ${{ github.workspace }}/${{ steps.build.outputs.build }}

33
.gitignore vendored
View file

@ -1,27 +1,11 @@
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
# Created by https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,macos,linux,godot,executable,backup # Created by https://www.toptal.com/developers/gitignore/api/godot,linux,macos,visualstudiocode,windows
# Edit at https://www.toptal.com/developers/gitignore?templates=windows,visualstudiocode,macos,linux,godot,executable,backup # Edit at https://www.toptal.com/developers/gitignore?templates=godot,linux,macos,visualstudiocode,windows
### Backup ###
*.bak
*.gho
*.ori
*.orig
*.tmp
### Executable ###
*.app
*.bat
*.cgi
*.com
*.exe
*.gadget
*.jar
*.pif
*.vb
*.wsf
### Godot ### ### Godot ###
# Godot 4+ specific ignores
.godot/
# Godot-specific ignores # Godot-specific ignores
.import/ .import/
export.cfg export.cfg
@ -33,6 +17,7 @@ export_presets.cfg
# Mono-specific ignores # Mono-specific ignores
.mono/ .mono/
data_*/ data_*/
mono_crash.*.json
### Linux ### ### Linux ###
*~ *~
@ -56,8 +41,7 @@ data_*/
.LSOverride .LSOverride
# Icon must end with two \r # Icon must end with two \r
Icon Icon
# Thumbnails # Thumbnails
._* ._*
@ -127,8 +111,7 @@ $RECYCLE.BIN/
# Windows shortcuts # Windows shortcuts
*.lnk *.lnk
# End of https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,macos,linux,godot,executable,backup # End of https://www.toptal.com/developers/gitignore/api/godot,linux,macos,visualstudiocode,windows
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
!export_presets.cfg

457
LICENSE
View file

@ -1,201 +1,320 @@
Apache License GNU GENERAL PUBLIC LICENSE
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION Version 2, June 1991
1. Definitions. Copyright (C) 1989, 1991 Free Software Foundation, Inc.
"License" shall mean the terms and conditions for use, reproduction, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by Everyone is permitted to copy and distribute verbatim copies of this license
the copyright owner that is granting the License. document, but changing it is not allowed.
"Legal Entity" shall mean the union of the acting entity and all Preamble
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity The licenses for most software are designed to take away your freedom to share
exercising permissions granted by this License. and change it. By contrast, the GNU General Public License is intended to
guarantee your freedom to share and change free software--to make sure the
software is free for all its users. This General Public License applies to
most of the Free Software Foundation's software and to any other program whose
authors commit to using it. (Some other Free Software Foundation software
is covered by the GNU Lesser General Public License instead.) You can apply
it to your programs, too.
"Source" form shall mean the preferred form for making modifications, When we speak of free software, we are referring to freedom, not price. Our
including but not limited to software source code, documentation General Public Licenses are designed to make sure that you have the freedom
source, and configuration files. to distribute copies of free software (and charge for this service if you
wish), that you receive source code or can get it if you want it, that you
can change the software or use pieces of it in new free programs; and that
you know you can do these things.
"Object" form shall mean any form resulting from mechanical To protect your rights, we need to make restrictions that forbid anyone to
transformation or translation of a Source form, including but deny you these rights or to ask you to surrender the rights. These restrictions
not limited to compiled object code, generated documentation, translate to certain responsibilities for you if you distribute copies of
and conversions to other media types. the software, or if you modify it.
"Work" shall mean the work of authorship, whether in Source or For example, if you distribute copies of such a program, whether gratis or
Object form, made available under the License, as indicated by a for a fee, you must give the recipients all the rights that you have. You
copyright notice that is included in or attached to the work must make sure that they, too, receive or can get the source code. And you
(an example is provided in the Appendix below). must show them these terms so they know their rights.
"Derivative Works" shall mean any work, whether in Source or Object We protect your rights with two steps: (1) copyright the software, and (2)
form, that is based on (or derived from) the Work and for which the offer you this license which gives you legal permission to copy, distribute
editorial revisions, annotations, elaborations, or other modifications and/or modify the software.
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including Also, for each author's protection and ours, we want to make certain that
the original version of the Work and any modifications or additions everyone understands that there is no warranty for this free software. If
to that Work or Derivative Works thereof, that is intentionally the software is modified by someone else and passed on, we want its recipients
submitted to Licensor for inclusion in the Work by the copyright owner to know that what they have is not the original, so that any problems introduced
or by an individual or Legal Entity authorized to submit on behalf of by others will not reflect on the original authors' reputations.
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity Finally, any free program is threatened constantly by software patents. We
on behalf of whom a Contribution has been received by Licensor and wish to avoid the danger that redistributors of a free program will individually
subsequently incorporated within the Work. obtain patent licenses, in effect making the program proprietary. To prevent
this, we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
2. Grant of Copyright License. Subject to the terms and conditions of The precise terms and conditions for copying, distribution and modification
this License, each Contributor hereby grants to You a perpetual, follow.
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the 0. This License applies to any program or other work which contains a notice
Work or Derivative Works thereof in any medium, with or without placed by the copyright holder saying it may be distributed under the terms
modifications, and in Source or Object form, provided that You of this General Public License. The "Program", below, refers to any such program
meet the following conditions: or work, and a "work based on the Program" means either the Program or any
derivative work under copyright law: that is to say, a work containing the
Program or a portion of it, either verbatim or with modifications and/or translated
into another language. (Hereinafter, translation is included without limitation
in the term "modification".) Each licensee is addressed as "you".
(a) You must give any other recipients of the Work or Activities other than copying, distribution and modification are not covered
Derivative Works a copy of this License; and by this License; they are outside its scope. The act of running the Program
is not restricted, and the output from the Program is covered only if its
contents constitute a work based on the Program (independent of having been
made by running the Program). Whether that is true depends on what the Program
does.
(b) You must cause any modified files to carry prominent notices 1. You may copy and distribute verbatim copies of the Program's source code
stating that You changed the files; and as you receive it, in any medium, provided that you conspicuously and appropriately
publish on each copy an appropriate copyright notice and disclaimer of warranty;
keep intact all the notices that refer to this License and to the absence
of any warranty; and give any other recipients of the Program a copy of this
License along with the Program.
(c) You must retain, in the Source form of any Derivative Works You may charge a fee for the physical act of transferring a copy, and you
that You distribute, all copyright, patent, trademark, and may at your option offer warranty protection in exchange for a fee.
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its 2. You may modify your copy or copies of the Program or any portion of it,
distribution, then any Derivative Works that You distribute must thus forming a work based on the Program, and copy and distribute such modifications
include a readable copy of the attribution notices contained or work under the terms of Section 1 above, provided that you also meet all
within such NOTICE file, excluding those notices that do not of these conditions:
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and a) You must cause the modified files to carry prominent notices stating that
may provide additional or different license terms and conditions you changed the files and the date of any change.
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, b) You must cause any work that you distribute or publish, that in whole or
any Contribution intentionally submitted for inclusion in the Work in part contains or is derived from the Program or any part thereof, to be
by You to the Licensor shall be under the terms and conditions of licensed as a whole at no charge to all third parties under the terms of this
this License, without any additional terms or conditions. License.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade c) If the modified program normally reads commands interactively when run,
names, trademarks, service marks, or product names of the Licensor, you must cause it, when started running for such interactive use in the most
except as required for reasonable and customary use in describing the ordinary way, to print or display an announcement including an appropriate
origin of the Work and reproducing the content of the NOTICE file. copyright notice and a notice that there is no warranty (or else, saying that
you provide a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this License.
(Exception: if the Program itself is interactive but does not normally print
such an announcement, your work based on the Program is not required to print
an announcement.)
7. Disclaimer of Warranty. Unless required by applicable law or These requirements apply to the modified work as a whole. If identifiable
agreed to in writing, Licensor provides the Work (and each sections of that work are not derived from the Program, and can be reasonably
Contributor provides its Contributions) on an "AS IS" BASIS, considered independent and separate works in themselves, then this License,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or and its terms, do not apply to those sections when you distribute them as
implied, including, without limitation, any warranties or conditions separate works. But when you distribute the same sections as part of a whole
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A which is a work based on the Program, the distribution of the whole must be
PARTICULAR PURPOSE. You are solely responsible for determining the on the terms of this License, whose permissions for other licensees extend
appropriateness of using or redistributing the Work and assume any to the entire whole, and thus to each and every part regardless of who wrote
risks associated with Your exercise of permissions under this License. it.
8. Limitation of Liability. In no event and under no legal theory, Thus, it is not the intent of this section to claim rights or contest your
whether in tort (including negligence), contract, or otherwise, rights to work written entirely by you; rather, the intent is to exercise
unless required by applicable law (such as deliberate and grossly the right to control the distribution of derivative or collective works based
negligent acts) or agreed to in writing, shall any Contributor be on the Program.
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing In addition, mere aggregation of another work not based on the Program with
the Work or Derivative Works thereof, You may choose to offer, the Program (or with a work based on the Program) on a volume of a storage
and charge a fee for, acceptance of support, warranty, indemnity, or distribution medium does not bring the other work under the scope of this
or other liability obligations and/or rights consistent with this License.
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS 3. You may copy and distribute the Program (or a work based on it, under Section
APPENDIX: How to apply the Apache License to your work. 2) in object code or executable form under the terms of Sections 1 and 2 above
provided that you also do one of the following:
To apply the Apache License to your work, attach the following a) Accompany it with the complete corresponding machine-readable source code,
boilerplate notice, with the fields enclosed by brackets "[]" which must be distributed under the terms of Sections 1 and 2 above on a medium
replaced with your own identifying information. (Don't include customarily used for software interchange; or,
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2022 Tony Bark b) Accompany it with a written offer, valid for at least three years, to give
any third party, for a charge no more than your cost of physically performing
source distribution, a complete machine-readable copy of the corresponding
source code, to be distributed under the terms of Sections 1 and 2 above on
a medium customarily used for software interchange; or,
Licensed under the Apache License, Version 2.0 (the "License"); c) Accompany it with the information you received as to the offer to distribute
you may not use this file except in compliance with the License. corresponding source code. (This alternative is allowed only for noncommercial
You may obtain a copy of the License at distribution and only if you received the program in object code or executable
form with such an offer, in accord with Subsection b above.)
http://www.apache.org/licenses/LICENSE-2.0 The source code for a work means the preferred form of the work for making
modifications to it. For an executable work, complete source code means all
the source code for all modules it contains, plus any associated interface
definition files, plus the scripts used to control compilation and installation
of the executable. However, as a special exception, the source code distributed
need not include anything that is normally distributed (in either source or
binary form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component itself
accompanies the executable.
Unless required by applicable law or agreed to in writing, software If distribution of executable or object code is made by offering access to
distributed under the License is distributed on an "AS IS" BASIS, copy from a designated place, then offering equivalent access to copy the
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. source code from the same place counts as distribution of the source code,
See the License for the specific language governing permissions and even though third parties are not compelled to copy the source along with
limitations under the License. the object code.
4. You may not copy, modify, sublicense, or distribute the Program except
as expressly provided under this License. Any attempt otherwise to copy, modify,
sublicense or distribute the Program is void, and will automatically terminate
your rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses terminated
so long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed
it. However, nothing else grants you permission to modify or distribute the
Program or its derivative works. These actions are prohibited by law if you
do not accept this License. Therefore, by modifying or distributing the Program
(or any work based on the Program), you indicate your acceptance of this License
to do so, and all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program),
the recipient automatically receives a license from the original licensor
to copy, distribute or modify the Program subject to these terms and conditions.
You may not impose any further restrictions on the recipients' exercise of
the rights granted herein. You are not responsible for enforcing compliance
by third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent infringement
or for any other reason (not limited to patent issues), conditions are imposed
on you (whether by court order, agreement or otherwise) that contradict the
conditions of this License, they do not excuse you from the conditions of
this License. If you cannot distribute so as to satisfy simultaneously your
obligations under this License and any other pertinent obligations, then as
a consequence you may not distribute the Program at all. For example, if a
patent license would not permit royalty-free redistribution of the Program
by all those who receive copies directly or indirectly through you, then the
only way you could satisfy both it and this License would be to refrain entirely
from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply and
the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents
or other property right claims or to contest validity of any such claims;
this section has the sole purpose of protecting the integrity of the free
software distribution system, which is implemented by public license practices.
Many people have made generous contributions to the wide range of software
distributed through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing to
distribute software through any other system and a licensee cannot impose
that choice.
This section is intended to make thoroughly clear what is believed to be a
consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain
countries either by patents or by copyrighted interfaces, the original copyright
holder who places the Program under this License may add an explicit geographical
distribution limitation excluding those countries, so that distribution is
permitted only in or among countries not thus excluded. In such case, this
License incorporates the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions of
the General Public License from time to time. Such new versions will be similar
in spirit to the present version, but may differ in detail to address new
problems or concerns.
Each version is given a distinguishing version number. If the Program specifies
a version number of this License which applies to it and "any later version",
you have the option of following the terms and conditions either of that version
or of any later version published by the Free Software Foundation. If the
Program does not specify a version number of this License, you may choose
any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs
whose distribution conditions are different, write to the author to ask for
permission. For software which is copyrighted by the Free Software Foundation,
write to the Free Software Foundation; we sometimes make exceptions for this.
Our decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing and reuse
of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE
OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES
OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH
HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible
use to the public, the best way to achieve this is to make it free software
which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach
them to the start of each source file to most effectively convey the exclusion
of warranty; and each file should have at least the "copyright" line and a
pointer to where the full notice is found.
<one line to give the program's name and an idea of what it does.>
Copyright (C) < yyyy> <name of author>
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
Street, Fifth Floor, Boston, MA 02110-1301, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when
it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software,
and you are welcome to redistribute it under certain conditions; type `show
c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may be
called something other than `show w' and `show c'; they could even be mouse-clicks
or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your school,
if any, to sign a "copyright disclaimer" for the program, if necessary. Here
is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision'
(which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General
Public License does not permit incorporating your program into proprietary
programs. If your program is a subroutine library, you may consider it more
useful to permit linking proprietary applications with the library. If this
is what you want to do, use the GNU Lesser General Public License instead
of this License.

View file

@ -7,22 +7,22 @@
<hr> <hr>
</p> </p>
City Limits is a re-imagining of SimCity Classic that brings modern city building concepts to the classic game. Based on Godot, CityLimits is an open source reimagining of SimCity Classic based on Godot. In the long run, I plan on adding on gameplay mechanics used in later iterations. Like it's cousin, everything learned in the making of CityLimits will go towards the building and customization that I've been itching to create.
## Getting Started ## Getting Started
### Prerequisites ### Prerequisites
- Godot Engine 3.x - Godot Engine 4.x
## Authors ## Authors
- **Tony Bark** - _Initial work_ - [tonytins](https://github.com/tonytins) - **Tony Bark** - _Initial work_ - [tonytins](https://github.com/tonytins)
- **Maxis** - _Assets_ - [SimHacker](https://github.com/SimHacker/) - **Maxis** - _Assets_ - [SimHacker](https://github.com/SimHacker/)
- **Font Awesome** - *Icons* - [FortAwesome](https://github.com/FortAwesome) - **Font Awesome** - _Icons_ - [FortAwesome](https://github.com/FortAwesome)
See also the list of [contributors](https://github.com/tonytins/citylimits/contributors) who participated in this project. See also the list of [contributors](https://github.com/tonytins/citylimits/contributors) who participated in this project.
## License ## License
In jurisdictions that recognize copyright waivers, I've [waived all copyright](UNLICENSE) and related or neighboring rights for to this project. In areas where these waivers are not recognized, [Apache-2.0](LICENSE) is enforced. I license this project under the GPL-2.0-or-later license - see [LICENSE](LICENSE) for details.

View file

@ -1,6 +0,0 @@
# To-do
- Make zones upgradeable, similar to SimCity BuildIt
- Add Casey Universe buildings
- Central Tower
- Pawprint Press

View file

@ -1,22 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute
this software, either in source code form or as a compiled binary, for any
purpose, commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and
to the detriment of our heirs and
successors. We intend this dedication to be an overt act of relinquishment
in perpetuity of all present and future rights to this software under copyright
law.
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
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. For more information,
please refer to <https://unlicense.org/>

View file

@ -1,24 +0,0 @@
extends Reference
var blackboard = {}
func set(key, value, blackboard_name = 'default'):
if not blackboard.has(blackboard_name):
blackboard[blackboard_name] = {}
blackboard[blackboard_name][key] = value
func get(key, default_value = null, blackboard_name = 'default'):
if has(key, blackboard_name):
return blackboard[blackboard_name].get(key, default_value)
return default_value
func has(key, blackboard_name = 'default'):
return blackboard.has(blackboard_name) and blackboard[blackboard_name].has(key) and blackboard[blackboard_name][key] != null
func erase(key, blackboard_name = 'default'):
if blackboard.has(blackboard_name):
blackboard[blackboard_name][key] = null

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg14360"
sodipodi:docname="action.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata14366">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs14364" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview14362"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg14360" />
<path
d="M 8,4 C 5.792,4 4,5.792 4,8 c 0,2.208 1.792,4 4,4 2.208,0 4,-1.792 4,-4 C 12,5.792 10.208,4 8,4 Z M 8,0 C 3.584,0 0,3.584 0,8 c 0,4.416 3.584,8 8,8 4.416,0 8,-3.584 8,-8 C 16,3.584 12.416,0 8,0 Z M 8,14.4 C 4.464,14.4 1.6,11.536 1.6,8 1.6,4.464 4.464,1.6 8,1.6 c 3.536,0 6.4,2.864 6.4,6.4 0,3.536 -2.864,6.4 -6.4,6.4 z"
id="path14356"
style="fill:#efd7a5;fill-opacity:1;stroke-width:0.80000001"
inkscape:connector-curvature="0" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path14358"
inkscape:connector-curvature="0"
style="fill:none" />
</svg>

Before

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/action.svg-e8a91246d0ba9ba3cf84290d65648f06.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/action.svg"
dest_files=[ "res://.import/action.svg-e8a91246d0ba9ba3cf84290d65648f06.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg893"
sodipodi:docname="blackboard.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata899">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs897" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview895"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg893" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path889"
inkscape:connector-curvature="0"
style="fill:none" />
<path
d="M 0,8.888889 H 7.111111 V 0 H 0 Z M 0,16 H 7.111111 V 10.666667 H 0 Z m 8.888889,0 H 16 V 7.111111 H 8.888889 Z m 0,-16 V 5.333333 H 16 V 0 Z"
id="path891"
style="fill:#b2a5ef;fill-opacity:1;stroke-width:0.8888889"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/blackboard.svg-18d4dfd4f6de558de250b67251ff1e69.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/blackboard.svg"
dest_files=[ "res://.import/blackboard.svg-18d4dfd4f6de558de250b67251ff1e69.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg14360"
sodipodi:docname="category_bt.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<metadata
id="metadata14366">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs14364" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1051"
id="namedview14362"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="-6.0508475"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="29"
inkscape:window-maximized="1"
inkscape:current-layer="svg14360" />
<path
d="M 8,4 C 5.792,4 4,5.792 4,8 c 0,2.208 1.792,4 4,4 2.208,0 4,-1.792 4,-4 C 12,5.792 10.208,4 8,4 Z M 8,0 C 3.584,0 0,3.584 0,8 c 0,4.416 3.584,8 8,8 4.416,0 8,-3.584 8,-8 C 16,3.584 12.416,0 8,0 Z M 8,14.4 C 4.464,14.4 1.6,11.536 1.6,8 1.6,4.464 4.464,1.6 8,1.6 c 3.536,0 6.4,2.864 6.4,6.4 0,3.536 -2.864,6.4 -6.4,6.4 z"
id="path14356"
style="fill:#b2a5ef;fill-opacity:1;stroke-width:0.80000001"
inkscape:connector-curvature="0" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path14358"
inkscape:connector-curvature="0"
style="fill:none" />
</svg>

Before

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/category_bt.svg-8537bebd1c5f62dca3d7ee7f17efeed4.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/category_bt.svg"
dest_files=[ "res://.import/category_bt.svg-8537bebd1c5f62dca3d7ee7f17efeed4.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg14360"
sodipodi:docname="category_composite.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<metadata
id="metadata14366">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs14364" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1051"
id="namedview14362"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="-6.0508475"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="29"
inkscape:window-maximized="1"
inkscape:current-layer="svg14360" />
<path
d="M 8,4 C 5.792,4 4,5.792 4,8 c 0,2.208 1.792,4 4,4 2.208,0 4,-1.792 4,-4 C 12,5.792 10.208,4 8,4 Z M 8,0 C 3.584,0 0,3.584 0,8 c 0,4.416 3.584,8 8,8 4.416,0 8,-3.584 8,-8 C 16,3.584 12.416,0 8,0 Z M 8,14.4 C 4.464,14.4 1.6,11.536 1.6,8 1.6,4.464 4.464,1.6 8,1.6 c 3.536,0 6.4,2.864 6.4,6.4 0,3.536 -2.864,6.4 -6.4,6.4 z"
id="path14356"
style="fill:#a5efac;fill-opacity:1;stroke-width:0.80000001"
inkscape:connector-curvature="0" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path14358"
inkscape:connector-curvature="0"
style="fill:none" />
</svg>

Before

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/category_composite.svg-43f66e63a7ccfa5ac8ec6da0583b3246.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/category_composite.svg"
dest_files=[ "res://.import/category_composite.svg-43f66e63a7ccfa5ac8ec6da0583b3246.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg14360"
sodipodi:docname="category_decorator.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<metadata
id="metadata14366">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs14364" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1051"
id="namedview14362"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="-6.0508475"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="29"
inkscape:window-maximized="1"
inkscape:current-layer="svg14360" />
<path
d="M 8,4 C 5.792,4 4,5.792 4,8 c 0,2.208 1.792,4 4,4 2.208,0 4,-1.792 4,-4 C 12,5.792 10.208,4 8,4 Z M 8,0 C 3.584,0 0,3.584 0,8 c 0,4.416 3.584,8 8,8 4.416,0 8,-3.584 8,-8 C 16,3.584 12.416,0 8,0 Z M 8,14.4 C 4.464,14.4 1.6,11.536 1.6,8 1.6,4.464 4.464,1.6 8,1.6 c 3.536,0 6.4,2.864 6.4,6.4 0,3.536 -2.864,6.4 -6.4,6.4 z"
id="path14356"
style="fill:#fc9c9c;fill-opacity:1;stroke-width:0.80000001"
inkscape:connector-curvature="0" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path14358"
inkscape:connector-curvature="0"
style="fill:none" />
</svg>

Before

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/category_decorator.svg-79d598d6456f32724156248e09d6eaf3.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/category_decorator.svg"
dest_files=[ "res://.import/category_decorator.svg-79d598d6456f32724156248e09d6eaf3.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg13771"
sodipodi:docname="condition.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata13777">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs13775" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview13773"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg13771" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path13767"
inkscape:connector-curvature="0"
style="fill:none" />
<path
d="M 14.222222,0 H 1.7777778 C 0.7911111,0 0,0.8 0,1.7777778 V 14.222222 C 0,15.2 0.7911111,16 1.7777778,16 H 14.222222 C 15.208889,16 16,15.2 16,14.222222 V 1.7777778 C 16,0.8 15.208889,0 14.222222,0 Z M 6.2222222,12.444444 1.7777778,8 3.0311111,6.7466667 6.2222222,9.9288889 12.968889,3.1822222 14.222222,4.4444444 Z"
id="path13769"
style="fill:#efd7a5;fill-opacity:1;stroke-width:0.8888889"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/condition.svg-57892684b10a64086f68c09c388b17e5.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/condition.svg"
dest_files=[ "res://.import/condition.svg-57892684b10a64086f68c09c388b17e5.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg5952"
sodipodi:docname="fail.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata5958">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs5956" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview5954"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="-23.186441"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg5952"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
scale-x="1" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path5948"
inkscape:connector-curvature="0"
style="fill:none" />
<path
d="m 8.1694915,0.0338983 c -4.416,0 -7.99999997,3.584 -7.99999997,8 0,4.4159997 3.58399997,7.9999997 7.99999997,7.9999997 4.4160005,0 8.0000005,-3.584 8.0000005,-7.9999997 0,-4.416 -3.584,-8 -8.0000005,-8 z m 0.8,11.9999997 h -1.6 v -1.6 h 1.6 z m 0,-3.1999997 h -1.6 v -4.8 h 1.6 z"
id="path5950"
style="fill:#fc9c9c;fill-opacity:1;stroke-width:0.80000001"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/fail.svg-85247bd8065819a11b971d222d3d43bb.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/fail.svg"
dest_files=[ "res://.import/fail.svg-85247bd8065819a11b971d222d3d43bb.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg6553"
sodipodi:docname="inverter.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata6559">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6557" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview6555"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="-22.881356"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg6553" />
<path
d="M 0,-8 H 24 V 16 H 0 Z m 0,0 H 24 V 16 H 0 Z m 0,0 H 24 V 16 H 0 Z"
id="path6549"
inkscape:connector-curvature="0"
style="fill:none" />
<path
d="M 14.222222,0 H 1.7777778 C 0.8,0 0,0.8 0,1.7777778 V 14.222222 C 0,15.2 0.8,16 1.7777778,16 H 14.222222 C 15.2,16 16,15.2 16,14.222222 V 1.7777778 C 16,0.8 15.2,0 14.222222,0 Z M 2.6666667,3.5555556 H 7.111111 V 4.8888889 H 2.6666667 Z M 14.222222,14.222222 H 1.7777778 L 14.222222,1.7777778 Z m -4,-2.666666 v 1.777777 h 1.333334 v -1.777777 h 1.777777 V 10.222222 H 11.555556 V 8.444444 h -1.333334 v 1.777778 H 8.444444 v 1.333334 z"
id="path6551"
style="fill:#fc9c9c;fill-opacity:1;stroke-width:0.8888889"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/inverter.svg-1f1b976d95de42c4ad99a92fa9a6c5d0.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/inverter.svg"
dest_files=[ "res://.import/inverter.svg-1f1b976d95de42c4ad99a92fa9a6c5d0.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg7154"
sodipodi:docname="limiter.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata7160">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs7158" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview7156"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg7154" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path7150"
inkscape:connector-curvature="0"
style="fill:none" />
<path
d="M 8.0685714,4.541598 10.79619,7.2768364 H 0 v 1.523809 H 10.79619 L 8.0609524,11.535884 9.142857,12.61017 13.714286,8.0387404 9.142857,3.4673123 Z M 14.47619,3.4673123 V 12.61017 H 16 V 3.4673123 Z"
id="path7152"
style="fill:#fc9c9c;fill-opacity:1;stroke-width:0.76190478"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/limiter.svg-b4c7646605c46f53c5e403fe21d8f584.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/limiter.svg"
dest_files=[ "res://.import/limiter.svg-b4c7646605c46f53c5e403fe21d8f584.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg12569"
sodipodi:docname="selector.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata12575">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs12573" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview12571"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg12569" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path12565"
inkscape:connector-curvature="0"
style="fill:none" />
<path
d="M 3.8101694,4 H 11.81017 v 2.4 l 3.2,-3.2 -3.2,-3.2 V 2.4 H 2.2101694 v 4.8 h 1.6 z M 11.81017,12 H 3.8101694 V 9.6 L 0.61016952,12.8 3.8101694,16 V 13.6 H 13.41017 V 8.8 h -1.6 z"
id="path12567"
style="fill:#a5efac;fill-opacity:1;stroke-width:0.80000001"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/selector.svg-78bccfc448bd1676b5a29bfde4b08e5b.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/selector.svg"
dest_files=[ "res://.import/selector.svg-78bccfc448bd1676b5a29bfde4b08e5b.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<rect id="path12565" x="0" y="-8" width="24" height="24" style="fill:none;fill-rule:nonzero;"/>
<g transform="matrix(0.571429,0,0,0.571429,7.42857,-585.2)">
<path d="M8,1038.1L5.626,1042.2L1,1043.3L4.236,1046.7L3.877,1051.38L8.016,1049.4L12.174,1051.34L11.778,1046.69L15,1043.3L10.374,1042.2L8,1038.1Z" style="fill:rgb(165,239,172);fill-rule:nonzero;"/>
</g>
<path id="path12567" d="M8.76,13.6L8.784,13.315L7.405,12L3.81,12L3.81,9.6L0.61,12.8L3.81,16L3.81,13.6L8.76,13.6ZM13.41,8.855L13.375,8.8L13.41,8.8L13.41,8.855ZM3.81,4L11.81,4L11.81,6.4L15.01,3.2L11.81,0L11.81,2.4L2.21,2.4L2.21,7.2L3.81,7.2L3.81,4Z" style="fill:rgb(165,239,172);fill-rule:nonzero;"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/selector_star.svg-368af7abfb9842c3f4258786871d1f03.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/selector_star.svg"
dest_files=[ "res://.import/selector_star.svg-368af7abfb9842c3f4258786871d1f03.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=false
svg/scale=1.0

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg13170"
sodipodi:docname="sequence.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata13176">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs13174" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview13172"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12"
inkscape:cy="17.186441"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg13170" />
<path
d="M 0,9.0376644 H 1.7777778 V 7.2598874 H 0 Z M 0,12.59322 H 1.7777778 V 10.815442 H 0 Z M 0,5.4821093 H 1.7777778 V 3.7043315 H 0 Z M 3.5555556,9.0376644 H 16 V 7.2598874 H 3.5555556 Z m 0,3.5555556 H 16 V 10.815442 H 3.5555556 Z m 0,-8.8888885 V 5.4821093 H 16 V 3.7043315 Z"
id="path13166"
style="fill:#a5efac;fill-opacity:1;stroke-width:0.8888889"
inkscape:connector-curvature="0" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path13168"
inkscape:connector-curvature="0"
style="fill:none" />
</svg>

Before

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/sequencer.svg-a7b0e1cc6b00c0067836f9a81d0b2f9b.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/sequencer.svg"
dest_files=[ "res://.import/sequencer.svg-a7b0e1cc6b00c0067836f9a81d0b2f9b.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<rect id="path13168" x="0" y="-8" width="24" height="24" style="fill:none;fill-rule:nonzero;"/>
<g transform="matrix(0.571429,0,0,0.571429,7.42857,-585.2)">
<path d="M8,1038.1L5.626,1042.2L1,1043.3L4.236,1046.7L3.877,1051.38L8.016,1049.4L12.174,1051.34L11.778,1046.69L15,1043.3L10.374,1042.2L8,1038.1Z" style="fill:rgb(165,239,172);fill-rule:nonzero;"/>
</g>
<path id="path13166" d="M0,12.593L1.778,12.593L1.778,10.815L0,10.815L0,12.593ZM5.728,10.815L3.556,10.815L3.556,12.593L7.416,12.593L5.728,10.815ZM0,9.038L1.778,9.038L1.778,7.26L0,7.26L0,9.038ZM10.976,7.26L3.556,7.26L3.556,9.038L9.946,9.038L10.976,7.26ZM13.024,7.26L14.054,9.038L16,9.038L16,7.26L13.024,7.26ZM0,5.482L1.778,5.482L1.778,3.704L0,3.704L0,5.482ZM3.556,3.704L3.556,5.482L16,5.482L16,3.704L3.556,3.704Z" style="fill:rgb(165,239,172);fill-rule:nonzero;"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/sequencer_star.svg-2385cbba0c38b4d4ec43e0996f8a3493.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/sequencer_star.svg"
dest_files=[ "res://.import/sequencer_star.svg-2385cbba0c38b4d4ec43e0996f8a3493.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=false
svg/scale=1.0

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg5317"
sodipodi:docname="succeed.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata5323">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs5321" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview5319"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="-40.576272"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg5317" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path5313"
inkscape:connector-curvature="0"
style="fill:none" />
<path
d="M 8,0 C 3.584,0 0,3.584 0,8 c 0,4.416 3.584,8 8,8 4.416,0 8,-3.584 8,-8 C 16,3.584 12.416,0 8,0 Z M 6.4,12 2.4,8 3.528,6.872 6.4,9.736 12.472,3.664 13.6,4.8 Z"
id="path5315"
style="fill:#fc9c9c;fill-opacity:1;stroke-width:0.80000001"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/succeed.svg-c70f0a6f3d9b2864e4771942f0762307.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/succeed.svg"
dest_files=[ "res://.import/succeed.svg-c70f0a6f3d9b2864e4771942f0762307.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg61"
sodipodi:docname="tree.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata67">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs65" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview63"
showgrid="false"
inkscape:zoom="36.041667"
inkscape:cx="-2.3445086"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg61" />
<path
d="M 0,-8 H 24 V 16 H 0 Z"
id="path57"
inkscape:connector-curvature="0"
style="fill:none" />
<path
d="m 16,8.0000002 v -6.4 h -5.6 v 2.4 H 5.6 v -2.4 H 0 v 6.4 h 5.6 v -2.4 H 7.2 V 13.6 h 3.2 V 16 H 16 V 9.6000002 H 10.4 V 12 H 8.7999998 V 5.6000002 H 10.4 v 2.4 z"
id="path59"
style="fill:#b2a5ef;fill-opacity:1;stroke-width:0.80000001"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -1,35 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/tree.svg-c0b20ed88b2fe300c0296f7236049076.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/beehave/icons/tree.svg"
dest_files=[ "res://.import/tree.svg-c0b20ed88b2fe300c0296f7236049076.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -1,8 +0,0 @@
extends BeehaveTree
class_name BeehaveNode, "../icons/action.svg"
enum { SUCCESS, FAILURE, RUNNING }
func tick(actor, blackboard):
pass

View file

@ -1,84 +0,0 @@
extends BeehaveTree
class_name BeehaveRoot, "../icons/tree.svg"
const Blackboard = preload("../blackboard.gd")
const SUCCESS = 0
const FAILURE = 1
const RUNNING = 2
enum ProcessMode {
PHYSICS_PROCESS,
IDLE,
MANUAL
}
export (ProcessMode) var process_mode = ProcessMode.PHYSICS_PROCESS setget set_process_mode
export (bool) var enabled = true
export (NodePath) var actor_node_path
var actor : Node
onready var blackboard = Blackboard.new()
func _ready():
if self.get_child_count() != 1:
push_error("Beehave error: Root %s should have one child (NodePath: %s)" % [self.name, self.get_path()])
disable()
return
actor = get_parent()
if actor_node_path:
actor = get_node(actor_node_path)
set_process_mode(self.process_mode)
func _process(delta):
tick(delta)
func _physics_process(delta):
tick(delta)
func tick(delta):
blackboard.set("delta", delta)
var status = self.get_child(0).tick(actor, blackboard)
if status != RUNNING:
blackboard.set("running_action", null)
func get_running_action():
if blackboard.has("running_action"):
return blackboard.get("running_action")
return null
func get_last_condition():
if blackboard.has("last_condition"):
return blackboard.get("last_condition")
return null
func get_last_condition_status():
if blackboard.has("last_condition_status"):
var status = blackboard.get("last_condition_status")
if status == SUCCESS:
return "SUCCESS"
elif status == FAILURE:
return "FAILURE"
else:
return "RUNNING"
return ""
func enable():
self.enabled = true
set_process_mode(self.process_mode)
func disable():
self.enabled = false
set_process(self.enabled)
set_physics_process(self.enabled)
func set_process_mode(value):
process_mode = value
set_process(process_mode == ProcessMode.IDLE)
set_physics_process(process_mode == ProcessMode.PHYSICS_PROCESS)

View file

@ -1,3 +0,0 @@
extends Node
class_name BeehaveTree

View file

@ -1,8 +0,0 @@
extends BeehaveNode
class_name Composite, "../../icons/category_composite.svg"
func _ready():
if self.get_child_count() < 1:
push_error("BehaviorTree Error: Composite %s should have at least one child (NodePath: %s)" % [self.name, self.get_path()])

View file

@ -1,18 +0,0 @@
extends Composite
class_name SelectorComposite, "../../icons/selector.svg"
func tick(actor, blackboard):
for c in get_children():
var response = c.tick(actor, blackboard)
if c is ConditionLeaf:
blackboard.set("last_condition", c)
blackboard.set("last_condition_status", response)
if response != FAILURE:
if c is ActionLeaf and response == RUNNING:
blackboard.set("running_action", c)
return response
return FAILURE

View file

@ -1,33 +0,0 @@
# Special implementation of a selector that will
# "wait" for running nodes and will not re-attempt
# to execute previous nodes until that node is either
# FAILED or SUCCEEDED
extends Composite
class_name SelectorStarComposite, "../../icons/selector_star.svg"
var last_execution_index = 0
func tick(actor, blackboard):
for c in get_children():
if c.get_index() < last_execution_index:
continue
var response = c.tick(actor, blackboard)
if c is ConditionLeaf:
blackboard.set("last_condition", c)
blackboard.set("last_condition_status", response)
if response != FAILURE:
if c is ActionLeaf and response == RUNNING:
blackboard.set("running_action", c)
if response == SUCCESS:
last_execution_index = 0
return response
else:
last_execution_index += 1
last_execution_index = 0
return FAILURE

View file

@ -1,18 +0,0 @@
extends Composite
class_name SequenceComposite, "../../icons/sequencer.svg"
func tick(actor, blackboard):
for c in get_children():
var response = c.tick(actor, blackboard)
if c is ConditionLeaf:
blackboard.set("last_condition", c)
blackboard.set("last_condition_status", response)
if response != SUCCESS:
if c is ActionLeaf and response == RUNNING:
blackboard.set("running_action", c)
return response
return SUCCESS

View file

@ -1,35 +0,0 @@
# Special implementation of sequencer who will execute
# successful nodes only once until all nodes were successful
extends Composite
class_name SequenceStarComposite, "../../icons/sequencer_star.svg"
var successful_index = 0
func tick(actor, blackboard):
for c in get_children():
if c.get_index() < successful_index:
continue
var response = c.tick(actor, blackboard)
if c is ConditionLeaf:
blackboard.set("last_condition", c)
blackboard.set("last_condition_status", response)
if response != SUCCESS:
if response == FAILURE:
successful_index = 0
if c is ActionLeaf and response == RUNNING:
blackboard.set("running_action", c)
return response
else:
successful_index += 1
if successful_index == get_child_count():
successful_index = 0
return SUCCESS
else:
successful_index = 0
return FAILURE

View file

@ -1,8 +0,0 @@
extends BeehaveNode
class_name Decorator, "../../icons/category_decorator.svg"
func _ready():
if self.get_child_count() != 1:
push_error("Beehave Error: Decorator %s should have only one child (NodePath: %s)" % [self.name, self.get_path()])

View file

@ -1,11 +0,0 @@
extends Decorator
class_name AlwaysFailDecorator, "../../icons/fail.svg"
func tick(action, blackboard):
for c in get_children():
var response = c.tick(action, blackboard)
if response == RUNNING:
return RUNNING
return FAILURE

View file

@ -1,17 +0,0 @@
extends Decorator
class_name InverterDecorator, "../../icons/inverter.svg"
func tick(action, blackboard):
for c in get_children():
var response = c.tick(action, blackboard)
if response == SUCCESS:
return FAILURE
if response == FAILURE:
return SUCCESS
if c is Leaf and response == RUNNING:
blackboard.set("running_action", c)
return RUNNING

View file

@ -1,19 +0,0 @@
extends Decorator
class_name LimiterDecorator, "../../icons/limiter.svg"
onready var cache_key = 'limiter_%s' % self.get_instance_id()
export (float) var max_count = 0
func tick(actor, blackboard):
var current_count = blackboard.get(cache_key)
if current_count == null:
current_count = 0
if current_count <= max_count:
blackboard.set(cache_key, current_count + 1)
return self.get_child(0).tick(actor, blackboard)
else:
return FAILED

View file

@ -1,11 +0,0 @@
extends Decorator
class_name AlwaysSucceedDecorator, "../../icons/succeed.svg"
func tick(action, blackboard):
for c in get_children():
var response = c.tick(action, blackboard)
if response == RUNNING:
return RUNNING
return SUCCESS

View file

@ -1,3 +0,0 @@
extends Leaf
class_name ActionLeaf, "../../icons/action.svg"

View file

@ -1,3 +0,0 @@
extends Leaf
class_name ConditionLeaf, "../../icons/condition.svg"

View file

@ -1,3 +0,0 @@
extends BeehaveNode
class_name Leaf, "../../icons/action.svg"

View file

@ -1,7 +0,0 @@
[plugin]
name="Beehave"
description="🐝 Behaviour Tree addon for Godot Engine"
author="bitbrain"
version="1.2.0"
script="plugin.gd"

View file

@ -1,5 +0,0 @@
tool
extends EditorPlugin
func _init():
print("Beehave initialized!")

View file

@ -1,70 +0,0 @@
# Godot Version Manager
<img src="https://raw.githubusercontent.com/fcazalet/godot-version-management/main/icon.png" width="64" height="64">
This addon is for developpers that want a centralized place for version naming / build number and then display it in game.
It allow you to configure version and build in project settings.
These configurations are synchronized to all existing export of your project.
Moreover configurations can be loaded for in game display.
## How to install it
You can find this addon in Godot AssetLibrary
See the Godot Addon install section : https://docs.godotengine.org/en/stable/tutorials/plugins/editor/installing_plugins.html
## How to use it for exports
Once the addon activated it add two entry in your project configuration:
- Application / Config / Version as String (application/config/version default to 0.0.1)
- Application / Config / Build as Integer (application/config/build default to 1)
You can change the version and the build numbers.
It will update all your exports versions value to the project config value.
Then you need to reload the project (Project / Reload current project).
See below section to know why you need to reload project.
For Android exports:
* version is version/name
* build is version/code
For iOS and MacOS exports:
* version is application/short_version
* build is application/version
For Windows Desktop exports:
* version is application/file_version and application/product_version
For HTML5 and UWP exports no versions specified.
## How to use it for in game display
The version and build numbers can be accessed for in game use like that:
```GDScript
# To get version string
var version = ProjectSettings.get_setting("application/config/version")
# To get build number
var build = ProjectSettings.get_setting("application/config/build")
```
## Why I need to reload project ?
The GodotVersionManager addon update the export-presets.cfg file.
Because of Godot keep in memory ExportsSettings and do not reload it from export-presets.cfg file you will need to reload your project.
When project is loaded Godot load in memory the export-presets.cfg .
## Support Me
You to buy me a coffee ?
<a href='https://ko-fi.com/J3J2COV54' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi3.png?v=3' border='0' alt='Buy Me a Coffee' /></a>

View file

@ -1,78 +0,0 @@
# By Erasor
tool
extends EditorPlugin
const PLUGIN_NAME = "Godot-Version-Manager"
const DEBUG = true
# Use same name as https://github.com/godotengine/godot/pull/35555
const PROJECT_VERSION_SETTING = "application/config/version"
const PROJECT_BUILD_SETTING = "application/config/build"
const EXPORT_PRESETS_FILE = "res://export_presets.cfg"
var current_version
var current_build
func _enter_tree():
if not ProjectSettings.has_setting(PROJECT_VERSION_SETTING):
ProjectSettings.set_setting(PROJECT_VERSION_SETTING, "0.0.1")
if not ProjectSettings.has_setting(PROJECT_BUILD_SETTING):
ProjectSettings.set_setting(PROJECT_BUILD_SETTING, 1)
current_version = ProjectSettings.get_setting(PROJECT_VERSION_SETTING)
current_build = ProjectSettings.get_setting(PROJECT_BUILD_SETTING)
func _exit_tree():
# Do not remove the verson config, may conflict with https://github.com/godotengine/godot/pull/35555
pass
func apply_changes():
_update_export_presets()
func save_external_data():
_update_export_presets()
func _update_export_presets():
# If config version changed, update all exports
if ProjectSettings.get_setting(PROJECT_VERSION_SETTING) != current_version:
var export_config: ConfigFile = ConfigFile.new()
var err = export_config.load(EXPORT_PRESETS_FILE)
if err == OK:
# Loop limited to 100 exports
for i in range(0, 100):
var section = "preset." + str(i)
if export_config.has_section(section):
plugin_log("Update Export " + export_config.get_value(section, "platform"))
# Update Android exports configs
if export_config.get_value(section, "platform") == "Android":
export_config.set_value(section + ".options", 'version/name', ProjectSettings.get_setting(PROJECT_VERSION_SETTING))
export_config.set_value(section + ".options", 'version/code', ProjectSettings.get_setting(PROJECT_BUILD_SETTING))
if export_config.get_value(section, "platform") == "iOS" or export_config.get_value(section, "platform") == "Mac OSX":
export_config.set_value(section + ".options", 'application/short_version', ProjectSettings.get_setting(PROJECT_VERSION_SETTING))
export_config.set_value(section + ".options", 'application/version', ProjectSettings.get_setting(PROJECT_BUILD_SETTING))
if export_config.get_value(section, "platform") == "UWP":
# TODO parsing of version to minor/major
pass
if export_config.get_value(section, "platform") == "Windows Desktop":
export_config.set_value(section + ".options", 'application/file_version', ProjectSettings.get_setting(PROJECT_VERSION_SETTING))
export_config.set_value(section + ".options", 'application/product_version', ProjectSettings.get_setting(PROJECT_VERSION_SETTING))
else:
break
err = export_config.save(EXPORT_PRESETS_FILE)
ProjectSettings.save()
if err == OK:
plugin_log("All exports updated")
else:
plugin_log("Error saving " + EXPORT_PRESETS_FILE + ", exports not updated")
else:
plugin_log('Error open ' + EXPORT_PRESETS_FILE)
func plugin_log(message):
if (DEBUG):
var time : Dictionary = OS.get_datetime()
var date_string : String = "%02d:%02d" % [time.hour, time.minute]
print(date_string, " - ", PLUGIN_NAME, " - ", message)

View file

@ -1,8 +0,0 @@
[plugin]
name="Godot-Version-Manager"
description="Godot plugin to manage versions for exports.
It centralize the version number in project."
author="Erasor"
version="1.0.0"
script="godot_version_manager.gd"

View file

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2019 Tomek Copyright (c) 2022 Addons By Aura
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

View file

@ -0,0 +1,47 @@
@icon("../icons/animation_state.png")
class_name AnimationState
extends State
## Plays an animation from the linked [member animation_player].
## The name of the animation to be played comes from the name of the node.
## Emitted when the animation started by this state has finished playing.
signal animation_finished
@export_range(0, 20, 1, "or_greater")
## How many times to play before emitting [signal State.choose_new_substate_requested].
## [b]If set to zero, it will go forever.[/b]
var loops := 0
var _loops_left := 0
func _init() -> void:
set_meta(&"description", "Plays the named animation from the linked AnimationPlayer.")
func _on_animation_finished(animation_name: StringName) -> void:
if animation_name != name: return
if loops == 0:
animation_player.play(name)
elif _loops_left <= 0:
choose_new_substate_requested.emit()
else:
_loops_left -= 1
animation_player.play(name)
func enter(set_target: Node, set_animation_player: AnimationPlayer, set_debug_mode := false) -> void:
super(set_target, set_animation_player, set_debug_mode)
assert(animation_player != null, "AnimationPlayer must be set, either directly or by an ancestor.")
animation_player.animation_finished.connect(_on_animation_finished)
_loops_left = loops - 1
animation_player.play(name)
func exit() -> void:
super()
animation_player.animation_finished.disconnect(_on_animation_finished)
animation_player.stop()

View file

@ -0,0 +1,139 @@
@icon("../icons/state_machine_debugger.png")
class_name StateMachineDebugger
extends Tree
## Displays an interactive state tree.
# This source code is a mess, I'm trying to make it less so.
@export
## Root state machine to reference.
var state_machine_root : State:
set(value):
state_machine_root = value
_setup_tree()
@export
## What color to make the item when a state is active.
var active_color := Color.FOREST_GREEN
@export
## Forcefully switch states by double-clicking them.
## Due to its nature, it has the potential to be destructive
## and/ or not behave completely how one might expect.
var allow_state_switching := false:
set(value):
allow_state_switching = value
if allow_state_switching:
item_activated.connect(_on_item_activated)
else:
item_activated.disconnect(_on_item_activated)
@export_group("Signals", "signal_")
@export
## Show when a state emits a relevant signal.
var signal_show := false:
set(value):
signal_show = value
if state_machine_root == null:
return
if signal_show:
connect_signals()
else:
disconnect_signals()
@export
## Which signals to connect to on each state, as long as they exist.
var signal_connections : Array[StringName] = [
&"entered",
&"exited",
&"choose_new_substate_requested",
&"animation_finished",
]
@export
## Delay before hiding signal.
var signal_hide_delay := 1.0
func _init() -> void:
columns = 2
func change_state_by_path(path: NodePath) -> void:
if not state_machine_root.has_node(path):
return
var state := state_machine_root
for i in path.get_name_count():
var part := path.get_name(i)
state = await state.change_state_name(part)
func connect_signals(state := state_machine_root) -> void:
if not state.has_meta(&"tree_item"):
return
for signal_name in signal_connections:
if state.has_signal(signal_name) and not \
state.is_connected(signal_name, _on_state_signal):
state.connect(signal_name, _on_state_signal.bind(signal_name, state.get_meta(&"tree_item")))
for child in(state.get_children() as Array[State]):
connect_signals(child)
func disconnect_signals(state := state_machine_root) -> void:
for signal_name in signal_connections:
if state.has_signal(signal_name) and \
state.is_connected(signal_name, _on_state_signal):
state.disconnect(signal_name, _on_state_signal)
for child in (state.get_children() as Array[State]):
disconnect_signals(child)
func _setup_tree(state := state_machine_root, parent_item: TreeItem = null) -> void:
if state == state_machine_root:
if get_root() != null:
disconnect_signals()
clear()
if state_machine_root == null:
return
# state.print_tree_pretty()
# TODO: add icons
var item := create_item(parent_item)
item.set_text(0, state.name)
item.set_metadata(0, state)
state.set_meta(&"tree_item", item)
connect_signals(state)
for child in (state.get_children() as Array[State]):
_setup_tree(child, item)
func _on_item_activated() -> void:
change_state_by_path(state_machine_root.get_path_to(
get_selected().get_metadata(0) as State))
func _on_state_signal(signal_name: StringName, state_item: TreeItem) -> void:
match signal_name:
&"entered":
for i in columns:
state_item.set_custom_color(i, active_color)
&"exited":
for i in columns:
state_item.clear_custom_color(i)
if not signal_show:
return
state_item.set_text(1, signal_name)
var timer := state_item.get_metadata(1) as SceneTreeTimer
if timer != null:
timer.timeout.disconnect(state_item.set_text)
timer = get_tree().create_timer(signal_hide_delay)
timer.timeout.connect(state_item.set_text.bind(1, ""))
state_item.set_metadata(1, timer)

View file

@ -0,0 +1,34 @@
@icon("../icons/random_state.png")
class_name RandomState
extends State
## Activates a random one of its substates.
## Useful in conjuction with [AnimationState] for random idles.
@export
## When one of its children asks for a state change,
## instead of picking another one itself, it defers that choice to its parent.
## Allows for nested random states for finer control over flow and probability.
var defer_choice := false
func _init() -> void:
set_meta(&"description", "Pseudo-randomly picks a state to start.")
func _ready() -> void:
randomize()
super()
# You can define which state is picked automatically (like on enter).
# If you would like to call it yourself, use the public version (choose_substate).
func _choose_substate() -> State:
if get_child_count() == 0:
return null
if defer_choice and _active_substate != null:
choose_new_substate_requested.emit()
return null
return get_child(randi() % get_child_count()) as State

View file

@ -0,0 +1,43 @@
@icon("../icons/sequence_state.png")
class_name SequenceState
extends State
## Executes its children in order, one after the other. Like an [Array] in [State] form!
@export_range(0, 20, 1, "or_greater")
## How many times the sequence should be looped through before emitting [signal State.choose_new_substate_requested].
## [b]If set to zero, it will go forever.[/b]
var loops := 1
var _loops_left := 0
func _init() -> void:
set_meta(&"description", "Starts its children one after the other in order, \
waiting for each one to be done before starting the next.")
# You can define which state is picked automatically (like on [method enter]).
# If you would like to call it yourself, use the public version ([method choose_substate]).
func _choose_substate() -> State:
if _active_substate == null:
return get_child(0) as State if get_child_count() > 0 else null
if _active_substate.get_index() == get_child_count() - 1:
if loops == 0:
return get_child(0) as State
elif _loops_left == 0:
choose_new_substate_requested.emit()
return null
else:
_loops_left -= 1
return get_child(0) as State
return get_child(_active_substate.get_index() + 1) as State
func enter(set_target: Node, set_animation_player: AnimationPlayer, set_debug := false) -> void:
super(set_target, set_animation_player, set_debug)
_loops_left = loops - 1

View file

@ -0,0 +1,291 @@
@icon("../icons/state.png")
class_name State
extends Node
## The bare, basic state. Use it if you want total control over the state-flow.
##
## Properties marked as [b](inherited)[/b] are passed to substates,
## meaning you don't have to set it on each individual state, only the root.
## You can override it of course, and that will be passed to all of [i]its[/i] children.
## Emitted between [method _enter] and [method _after_enter].
signal entered
## Emitted after [method _exit].
signal exited
## Emitted between [method _update] and [method _after_update]
signal updated
## Switched active substates.
signal active_substate_changed(new: State, old: State)
## A request for the parent to pick a new substate to activate.
## Mainly used by children of [RandomState], such as an [AnimationState].
signal choose_new_substate_requested
## Active or not.
enum Status {
INACTIVE, ## Inactive
ACTIVE, ## Active
}
@export
## The node that the states will act upon. [b](inherited)[/b]
## Doesn't actually get used in the addon scripts, it's just
## included for your convenience when scripting your own behaviour.
var target: Node:
set(value):
target = value
if _active_substate != null:
_active_substate.target = target
@export
## Where to play animations from. [b](inherited)[/b]
var animation_player: AnimationPlayer
@export_range(0, 120, 1, "or_greater")
## How many seconds the state should be active before emitting [signal choose_new_substate_requested].
## [b]If set to zero, it will go forever.[/b]
var timer := 0.0
@export
## Whether to force-restart the chosen substate in the callback for [signal choose_new_substate_requested] if it was already active.
var force := true
@export
## The state will not be activated under any circumstances.
var disabled := false:
set(value):
disabled = value
var root := is_root()
if root and not disabled:
enter(target, animation_player, debug_mode)
elif status == Status.ACTIVE:
exit()
@export
## Print a message avery time there is a state change. [b](inherited)[/b]
var debug_mode := false:
set(value):
debug_mode = value
if _active_substate != null:
_active_substate.debug_mode = debug_mode
## The status of this state, ie. whether it's running or not.
var status := Status.INACTIVE
# The substate that is currently active, if any.
var _active_substate: State:
set(value):
if _active_substate != null:
_active_substate.choose_new_substate_requested.disconnect(_on_choose_new_substate_requested)
active_substate_changed.emit(value, _active_substate)
_active_substate = value
if _active_substate != null:
_active_substate.choose_new_substate_requested.connect(_on_choose_new_substate_requested)
# If a timer is set, the object will be stored here.
var _timer_object: SceneTreeTimer
#########################
### VIRTUAL METHODS ###
#########################
func _init() -> void:
set_physics_process(false)
set_meta(&"description", "A bare, basic state - will only ever automatically start its first child.")
func _ready() -> void:
for child in get_children():
assert(child is State, "A State should not have any children that are not other States.")
if is_root() and not disabled:
enter(target, animation_player, debug_mode)
func _physics_process(delta: float) -> void:
if status == Status.INACTIVE:
set_physics_process(false)
return
update(delta)
## [b][parents, then children][/b] Called when the state is activated.
func _enter() -> void:
pass
## [b][children, then parents][/b] Called after the state is activated.
func _after_enter() -> void:
pass
## [b][parents, then children][/b] Called every physics frame (only when the state is active, of course).
func _update(delta: float) -> void:
pass
## [b][children, then parents][/b] Called at the end of every physics frame.
func _after_update(delta: float) -> void:
pass
## [b][parents, then children][/b] Called before the state is deactivated.
func _before_exit() -> void:
pass
## [b][children, then parents][/b] Called when the state is deactivated.
func _exit() -> void:
pass
## You can define which state is picked automatically (like on [method enter]).
## Return `null` to not change substate at all.
## If you would like to call it yourself, use the public version ([method choose_substate]).
func _choose_substate() -> State:
return get_child(0) as State if get_child_count() > 0 else null
########################
### PUBLIC METHODS ###
########################
## Switch to the specified substate by name. It is just a shortcut to [method change_state_node].
func change_state_name(name: String, force := false) -> State:
return await change_state_node(get_node_or_null(name) as State, force)
## Switch to the specified substate by node. If it is not a direct child, nothing will happen.
## If `force`, it will start a state again even if it's already running.
## It waits for the next [signal updated] to make sure it's not
## switching all over the place in one tick.
func change_state_node(node: State, force := false) -> State:
await updated
if (
node == null
or node.disabled
or (node.status != Status.INACTIVE and not force)
or node.get_parent() != self
):
return node
var old := _active_substate
_active_substate = node
if old != null:
old.exit()
_active_substate.enter(target, animation_player, debug_mode)
if debug_mode:
print(
("FORCE " if force else "") +
"STATE: " +
str(get_root().get_parent().get_path_to(_active_substate))
)
return _active_substate
## Return the currently active substate, if any.
func get_active_substate() -> State:
return _active_substate
## Public [method _choose_substate].
func choose_substate() -> State:
return _choose_substate()
## Shortcut for `change_state_node(choose_substate())`.
func change_to_next_substate(force := false) -> void:
await change_state_node(choose_substate(), force)
## Whether this state is the root of the state tree,
## ie. it is the common ancestor of all the others.
func is_root() -> bool:
# If your parent is not a state, then you are the root.
return not get_parent() is State
## Get the root state.
func get_root() -> State:
var node: State = self
while not node.is_root():
node = node.get_parent() as State
return node
## Runs [method _enter] and [method _after_enter],
## not a good idea to call it yourself unless you really know what you're doing.
func enter(set_target: Node, set_animation_player: AnimationPlayer, set_debug_mode: bool) -> void:
for child in get_children():
assert(child is State, "A State should not have any children that are not other States.")
_enter()
entered.emit()
status = Status.ACTIVE
if timer != 0:
_timer_object = get_tree().create_timer(timer)
_timer_object.timeout.connect(_on_timer_timeout)
set_physics_process(is_root())
# Only set them if they're not being overridden
if target == null:
target = set_target
if animation_player == null:
animation_player = set_animation_player
if debug_mode == false:
debug_mode = set_debug_mode
change_to_next_substate()
_after_enter()
## Runs [method _update] and [method _after_update],
## not a good idea to call it yourself unless you really know what you're doing.
func update(delta: float) -> void:
_update(delta)
updated.emit()
if _active_substate != null:
_active_substate.update(delta)
_after_update(delta)
## Runs [method _exit] and [method _before_exit],
## not a good idea to call it yourself unless you really know what you're doing.
func exit() -> void:
_before_exit()
status = Status.INACTIVE
if _active_substate != null:
_active_substate.exit()
_active_substate = null
if is_instance_valid(_timer_object):
_timer_object.timeout.disconnect(_on_timer_timeout)
_timer_object = null
_exit()
exited.emit()
set_physics_process(false)
#########################
### PRIVATE METHODS ###
#########################
#################
### CALLBACKS ###
#################
func _on_choose_new_substate_requested() -> void:
change_to_next_substate(force)
func _on_timer_timeout() -> void:
choose_new_substate_requested.emit()

View file

@ -0,0 +1,14 @@
extends State
const NEXT_STATE_ACTION = "demo_next_state"
func _enter() -> void:
if InputMap.has_action(NEXT_STATE_ACTION):
return
var input_event := InputEventKey.new()
input_event.keycode = KEY_TAB
InputMap.add_action(NEXT_STATE_ACTION)
InputMap.action_add_event(NEXT_STATE_ACTION, input_event)

View file

@ -0,0 +1,218 @@
[gd_scene load_steps=17 format=3 uid="uid://clnliyc6fmqy6"]
[ext_resource type="Script" path="res://addons/simple-state/classes/debugger.gd" id="1_rqf1w"]
[ext_resource type="Script" path="res://addons/simple-state/demo/description_box.gd" id="2_gktik"]
[ext_resource type="Script" path="res://addons/simple-state/classes/sequence_state.gd" id="3_4afa7"]
[ext_resource type="Script" path="res://addons/simple-state/demo/demo.gd" id="3_x0hcs"]
[ext_resource type="Script" path="res://addons/simple-state/classes/random_state.gd" id="4_wxjoe"]
[ext_resource type="Script" path="res://addons/simple-state/demo/emit_next.gd" id="6_kxcgl"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ysqm7"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_wxupu"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7gdgn"]
draw_center = false
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
[sub_resource type="Animation" id="Animation_5pgem"]
resource_name = "RESET"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("ColorRect:color")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 1, 1, 1)]
}
[sub_resource type="Animation" id="Animation_mwhj1"]
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("ColorRect:color")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(0, 0, 0, 1)]
}
[sub_resource type="Animation" id="Animation_yyph0"]
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("ColorRect:color")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(0, 0, 1, 1)]
}
[sub_resource type="Animation" id="Animation_xmkhy"]
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("ColorRect:color")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(0, 1, 0, 1)]
}
[sub_resource type="Animation" id="Animation_4pwkk"]
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("ColorRect:color")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 0, 0, 1)]
}
[sub_resource type="Animation" id="Animation_gt7hj"]
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("ColorRect:color")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 1, 0, 1)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_01hf1"]
_data = {
"RESET": SubResource("Animation_5pgem"),
"black": SubResource("Animation_mwhj1"),
"blue": SubResource("Animation_yyph0"),
"green": SubResource("Animation_xmkhy"),
"red": SubResource("Animation_4pwkk"),
"yellow": SubResource("Animation_gt7hj")
}
[node name="SimpleStateDemo" type="Panel"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="MarginContainer" type="MarginContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"]
layout_mode = 2
theme_override_constants/separation = 10
[node name="StateMachineDebugger" type="Tree" parent="MarginContainer/HBoxContainer" node_paths=PackedStringArray("state_machine_root")]
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/relationship_line_width = 2
theme_override_constants/draw_guides = 0
theme_override_styles/panel = SubResource("StyleBoxEmpty_ysqm7")
theme_override_styles/focus = SubResource("StyleBoxEmpty_wxupu")
theme_override_styles/selected = SubResource("StyleBoxFlat_7gdgn")
theme_override_styles/selected_focus = SubResource("StyleBoxFlat_7gdgn")
select_mode = 1
script = ExtResource("1_rqf1w")
state_machine_root = NodePath("../../Root")
allow_state_switching = true
signal_show = true
[node name="DescriptionBox" type="Label" parent="MarginContainer/HBoxContainer" node_paths=PackedStringArray("tree")]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
autowrap_mode = 3
script = ExtResource("2_gktik")
tree = NodePath("../StateMachineDebugger")
show_descriptions = 2
[node name="InputInfo" type="Label" parent="MarginContainer/HBoxContainer/DescriptionBox"]
layout_mode = 1
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -349.0
offset_top = -78.0
grow_horizontal = 0
grow_vertical = 0
text = "MOUSE CLICK on state: select
DOUBLE MOUSE CLICK on state: start
TAB: next substate (only has effect on leaves)"
horizontal_alignment = 2
vertical_alignment = 2
[node name="ColorRect" type="ColorRect" parent="MarginContainer"]
custom_minimum_size = Vector2(50, 50)
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 8
[node name="AnimationPlayer" type="AnimationPlayer" parent="MarginContainer"]
libraries = {
"": SubResource("AnimationLibrary_01hf1")
}
[node name="Root" type="Node" parent="MarginContainer" node_paths=PackedStringArray("target", "animation_player")]
script = ExtResource("3_x0hcs")
target = NodePath("")
animation_player = NodePath("../AnimationPlayer")
[node name="SequenceState" type="Node" parent="MarginContainer/Root"]
script = ExtResource("3_4afa7")
[node name="RandomState" type="Node" parent="MarginContainer/Root/SequenceState"]
script = ExtResource("4_wxjoe")
defer_choice = true
[node name="red" type="Node" parent="MarginContainer/Root/SequenceState/RandomState"]
script = ExtResource("6_kxcgl")
[node name="yellow" type="Node" parent="MarginContainer/Root/SequenceState/RandomState"]
script = ExtResource("6_kxcgl")
[node name="green" type="Node" parent="MarginContainer/Root/SequenceState"]
script = ExtResource("6_kxcgl")
[node name="blue" type="Node" parent="MarginContainer/Root/SequenceState"]
script = ExtResource("6_kxcgl")
[node name="black" type="Node" parent="MarginContainer/Root"]
script = ExtResource("6_kxcgl")
timer = 1.0
metadata/description = "Will never start automatically, due to its parent being only a normal state."

View file

@ -0,0 +1,98 @@
extends Label
## Mode of description box rendering.
enum DisplayModes {
NONE, ## Description box completely hidden.
ACTIVE, ## Show descriptions of all active states.
SELECTION, ## Show description of last selected state (also includes manual switches).
}
@export
## [StateMachineDebugger] to reference.
var tree : StateMachineDebugger:
set(value):
tree = value
if show_descriptions == DisplayModes.SELECTION and \
not tree.item_selected.is_connected(_on_tree_item_selected):
tree.item_selected.connect(_on_tree_item_selected)
@export
## Show a description of a state.
## Looks for a string metadata value by the name of [code]description[/code] on each state.
var show_descriptions := DisplayModes.NONE:
set(value):
show_descriptions = value
match show_descriptions:
DisplayModes.NONE:
visible = false
DisplayModes.ACTIVE:
visible = true
if not is_instance_valid(tree):
return
if tree.item_selected.is_connected(_on_tree_item_selected):
tree.item_selected.disconnect(_on_tree_item_selected)
DisplayModes.SELECTION:
visible = true
if not is_instance_valid(tree):
return
if not tree.item_selected.is_connected(_on_tree_item_selected):
tree.item_selected.connect(_on_tree_item_selected)
var _active_states : Array[State] = []
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
visible = show_descriptions != DisplayModes.NONE
connect_signals()
func connect_signals(state := tree.state_machine_root) -> void:
if not state.has_meta(&"tree_item"):
return
for signal_name in tree.signal_connections:
if state.has_signal(signal_name) and not \
state.is_connected(signal_name, _on_state_signal):
state.connect(signal_name, _on_state_signal.bind(signal_name, state))
for child in(state.get_children() as Array[State]):
connect_signals(child)
func disconnect_signals(state := tree.state_machine_root) -> void:
for signal_name in tree.signal_connections:
if state.has_signal(signal_name) and \
state.is_connected(signal_name, _on_state_signal):
state.disconnect(signal_name, _on_state_signal)
for child in (state.get_children() as Array[State]):
disconnect_signals(child)
func _set_description_from_active_states() -> void:
text = ""
for state in _active_states:
text += ("" if state.is_root() else "\n\n") + \
state.name as String + \
": " + \
state.get_meta(&"description", "") as String
func _on_tree_item_selected() -> void:
text = tree.get_selected() \
.get_metadata(0).get_meta(&"description", "")
func _on_state_signal(signal_name: StringName, state: State) -> void:
match signal_name:
&"entered":
if show_descriptions == DisplayModes.ACTIVE:
_active_states.push_back(state)
_set_description_from_active_states()
&"exited":
if show_descriptions == DisplayModes.ACTIVE:
_active_states.pop_back()
_set_description_from_active_states()

View file

@ -0,0 +1,6 @@
extends AnimationState
func _update(_delta: float) -> void:
if Input.is_action_just_pressed(get_root().NEXT_STATE_ACTION):
choose_new_substate_requested.emit()

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cna1s8hi8xc58"
path="res://.godot/imported/animation_state.png-5f10255295e45d80e555d2885de83e22.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/simple-state/icons/animation_state.png"
dest_files=["res://.godot/imported/animation_state.png-5f10255295e45d80e555d2885de83e22.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View file

@ -0,0 +1,2 @@
[InternetShortcut]
URL=http://www.kenney.nl/

View file

@ -0,0 +1,2 @@
[InternetShortcut]
URL=https://www.patreon.com/kenney/

View file

@ -0,0 +1,22 @@
Board Game Icons (1.0)
Created/distributed by Kenney (www.kenney.nl)
Creation date: 10-01-2022
------------------------------
License: (Creative Commons Zero, CC0)
http://creativecommons.org/publicdomain/zero/1.0/
This content is free to use in personal, educational and commercial projects.
Support us by crediting Kenney or www.kenney.nl (this is not mandatory)
------------------------------
Donate: http://support.kenney.nl
Patreon: http://patreon.com/kenney/
Follow on Twitter for updates:
http://twitter.com/KenneyNL

View file

@ -0,0 +1,14 @@
###############################################################################
Game icon pack by Kenney Vleugels (www.kenney.nl)
------------------------------
License (CC0)
http://creativecommons.org/publicdomain/zero/1.0/
You may use these graphics in personal and commercial projects.
Credit (Kenney or www.kenney.nl) would be nice but is not mandatory.
###############################################################################

View file

@ -0,0 +1,20 @@
Pictogrammers Free License
--------------------------
This icon collection is released as free, open source, and GPL friendly by
the [Pictogrammers](http://pictogrammers.com/). You may use it
for commercial projects, open source projects, or anything really.
# Icons: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
Some of the icons are redistributed under the Apache 2.0 license. All other
icons are either redistributed under their respective licenses or are
distributed under the Apache 2.0 license.
# Fonts: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
All web and desktop fonts are distributed under the Apache 2.0 license. Web
and desktop fonts contain some icons that are redistributed under the Apache
2.0 license. All other icons are either redistributed under their respective
licenses or are distributed under the Apache 2.0 license.
# Code: MIT (https://opensource.org/licenses/MIT)
The MIT license applies to all non-font and non-icon files.

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cgoc214akn2d6"
path="res://.godot/imported/random_state.png-0878745fbdc123f3f0d51012c73a7024.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/simple-state/icons/random_state.png"
dest_files=["res://.godot/imported/random_state.png-0878745fbdc123f3f0d51012c73a7024.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bcviu3dccvvm2"
path="res://.godot/imported/sequence_state.png-4718f2c926301319d99a0ccd15ff62fb.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/simple-state/icons/sequence_state.png"
dest_files=["res://.godot/imported/sequence_state.png-4718f2c926301319d99a0ccd15ff62fb.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View file

@ -0,0 +1,12 @@
Icon Sources
-----------
[0] Board Game Icons: https://kenney.nl/assets/board-game-icons
- state.png
- random_state.png
- sequence_state.png
[1] Game Icons: https://kenney.nl/assets/game-icons
- animation_state.png
[2] Pictogrammers: <https://pictogrammers.com/library/mdi/>
- state_machine_debugger.png (tinted)

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://msu07hn5ewo5"
path="res://.godot/imported/state.png-fa3dd722682a28f890f138dcc6e162af.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/simple-state/icons/state.png"
dest_files=["res://.godot/imported/state.png-fa3dd722682a28f890f138dcc6e162af.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b32u1sa3robj0"
path="res://.godot/imported/state_fullsize.png-41a4827bc36d7745ba55c17c0bc213e9.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/simple-state/icons/state_fullsize.png"
dest_files=["res://.godot/imported/state_fullsize.png-41a4827bc36d7745ba55c17c0bc213e9.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dsglk01amsawf"
path="res://.godot/imported/state_machine_debugger.png-4af22f2c577f0756aa0b1d50ce679700.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/simple-state/icons/state_machine_debugger.png"
dest_files=["res://.godot/imported/state_machine_debugger.png-4af22f2c577f0756aa0b1d50ce679700.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View file

@ -0,0 +1,7 @@
[plugin]
name="SimpleState"
description="A super-simple state machine. Lightweight and (hopefully) reliable."
author="AuraTheEnby"
version="1.3.2"
script="plugin.gd"

View file

@ -0,0 +1,25 @@
@tool
extends EditorPlugin
## It uses the icons provided by the scripts anyway, so
## we don't really need to specify the real ones here.
## Plus, it might help with enabling it before the project
## has been reloaded for the first time.
var placeholder_texture := PlaceholderTexture2D.new()
func _enter_tree() -> void:
add_custom_type("State", "Node", State, placeholder_texture)
add_custom_type("RandomState", "Node", RandomState, placeholder_texture)
add_custom_type("AnimationState", "Node", AnimationState, placeholder_texture)
add_custom_type("SequenceState", "Node", SequenceState, placeholder_texture)
add_custom_type("StateMachineDebugger", "Tree", StateMachineDebugger, placeholder_texture)
func _exit_tree() -> void:
remove_custom_type("State")
remove_custom_type("RandomState")
remove_custom_type("AnimationState")
remove_custom_type("SequenceState")
remove_custom_type("StateMachineDebugger")

View file

@ -0,0 +1,33 @@
# meta-default: true
extends _BASE_
# Called when the state is activated. (parents, then children)
func _enter() -> void:
pass
# Called after the state is activated. (children, then parents)
func _after_enter() -> void:
pass
# Called every physics frame (only when the state is active, of course). (parents, then children)
func _update(delta: float) -> void:
pass
# Called at the end of every physics frame. (children, then parents)
func _after_update(delta: float) -> void:
pass
# Called before the state is deactivated. (parents, then children)
func _before_exit() -> void:
pass
# Called when the state is deactivated. (children, then parents)
func _exit() -> void:
pass

View file

@ -0,0 +1,111 @@
[gd_scene load_steps=3 format=3 uid="uid://bbhv8iqdbkqbt"]
[ext_resource type="Script" path="res://scripts/license_gui.gd" id="1_esldu"]
[ext_resource type="Script" path="res://addons/simplelicense/api/LicenseManager.gd" id="2_cpb2k"]
[node name="LicenseGUI" type="Control"]
custom_minimum_size = Vector2(256, 256)
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_esldu")
load_locations = Array[String](["res://licenses", "res://addons/simplelicense/mod_example/licenses/"])
export_locations = Array[String](["user://licenses/game/", "user://licenses/mods/mod_1/"])
[node name="LicenseManager" type="Node" parent="."]
script = ExtResource("2_cpb2k")
[node name="background" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Label" type="Label" parent="."]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.381076
anchor_right = 0.461806
anchor_bottom = 0.0401235
offset_left = 3.05176e-05
grow_horizontal = 2
text = "License Info"
metadata/_edit_use_anchors_ = true
[node name="Tree" type="Tree" parent="."]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.00694444
anchor_top = 0.0462963
anchor_right = 0.404514
anchor_bottom = 0.987654
grow_vertical = 2
size_flags_horizontal = 2
hide_root = true
metadata/_edit_use_anchors_ = true
[node name="Text" type="TextEdit" parent="."]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.434028
anchor_top = 0.0462963
anchor_right = 0.993056
anchor_bottom = 0.987654
offset_left = -8.0
grow_horizontal = 0
grow_vertical = 2
size_flags_horizontal = 3
editable = false
scroll_smooth = true
minimap_draw = true
metadata/_edit_use_anchors_ = true
[node name="btn_open_data_dir" type="Button" parent="."]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.585069
anchor_top = 0.00308642
anchor_right = 0.696181
anchor_bottom = 0.0416667
grow_horizontal = 2
theme_override_font_sizes/font_size = 12
text = "Open Data Directory"
metadata/_edit_use_anchors_ = true
[node name="btn_save_licenses" type="Button" parent="."]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.491319
anchor_top = 0.00308642
anchor_right = 0.56684
anchor_bottom = 0.0416667
grow_horizontal = 2
theme_override_font_sizes/font_size = 12
text = "Save Licenses"
metadata/_edit_use_anchors_ = true
[node name="op_locations" type="OptionButton" parent="."]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.00694444
anchor_top = 0.00308642
anchor_right = 0.172743
anchor_bottom = 0.0416667
theme_override_font_sizes/font_size = 12
item_count = 2
popup/item_0/text = "a"
popup/item_0/id = 0
popup/item_1/text = "b"
popup/item_1/id = 1
metadata/_edit_use_anchors_ = true
[connection signal="item_activated" from="Tree" to="." method="_on_tree_item_activated"]
[connection signal="item_selected" from="Tree" to="." method="_on_tree_item_selected"]
[connection signal="pressed" from="btn_open_data_dir" to="." method="_on_btn_open_data_dir_pressed"]
[connection signal="pressed" from="btn_save_licenses" to="." method="_on_button_pressed"]
[connection signal="item_selected" from="op_locations" to="." method="_on_op_locations_item_selected"]

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://duvmbh55cyvev"
path="res://.godot/imported/Icon.png-451064bd72ea26ed7eb00aedd926556f.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/simplelicense/Icon.png"
dest_files=["res://.godot/imported/Icon.png-451064bd72ea26ed7eb00aedd926556f.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 51 KiB

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dnr20t153it5i"
path="res://.godot/imported/Icon.svg-62b5bc5b7872f9c089f3b98f0084a03c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/simplelicense/Icon.svg"
dest_files=["res://.godot/imported/Icon.svg-62b5bc5b7872f9c089f3b98f0084a03c.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View file

@ -0,0 +1,37 @@
A simple plugin, to make dealing with licensing simple.
Files: ./addons/simplelicense/*
License: CC0-1.0
Developed in Godot version: v4.0.beta.custom_build [166df0896]
Quick Example: (A License Viewer Scene, that you can also drop into one of your game scenes)
Run the Scene at
res://addons/simplelicense/GUI/LicenseGUI.tscn
look around, then
click on the "open data directory" button
then click on the "save licenses" button
and watch the data directory populate with license files
Quick Start:
1. Create a "LicenseLink" Resource file inside the
res://licenses/license_links/
2. Click on the the new Resource file, and try it out
There are docs on how to use it, so just F1 + LicenseLink, to find out more
3. Load license information
Create an instance of "LicenseManager" either in code or by adding the node to the scene
then call "load_license_information" on the LicenseManager
4. Export License information
call "export" function on the LicenseManager
it will populate the "user://" directory with your license files
one combined "COPYRIGHT.txt" file
and individual copyright files into "user://licenses/<license_identifier>.txt".
The license text will be formatted in the SPDX standard.
It's the way the Godot Engine does it.
in the Godot Editor: Help -> About Godot -> Third-party Licenses
There is more you can do, just visit the docs!
(Like support for loading mod's license information!)

View file

@ -0,0 +1,78 @@
class_name License
extends Resource
## Holds AUTO GENERATED License information
## SPDX-License-Identifier or similar to it. CASE SENSITIVE[br]
## Like "CC0-1.0"[br]
## See [url=https://spdx.org/licenses/]SPDX Identifier List[/url]
var identifier: String = ""
## The License's Name. [br]
## Like "CC0 1.0 Universal"
var name: String = ""
## License Terms; The text of a license file
var terms: String = ""
## Returns a string containing this license's information, formatted to [url=https://spdx.dev/resources/use/]SPDX Standards[/url]
func to_formatted_string() -> String:
return "License: {identifier}\n{terms}".format({
'identifier': identifier,
'terms': _add_line_padding(terms)
})
# wouldn't recomend using this, unless you know what your doing
# but if you do, this loads and parses all licenses (.txt files) in a directory,
# plus Godot's built-in Licenses
static func _load_licenses_in(dir: String):
var dict = {}
# get game licenses
var names = DirAccess.get_files_at(dir)
if names.size() == 0:
print_verbose("\nSimple License: No License files found in dir\n", dir, "\nif you have no license files there, then this can be ignored\n")
for _name in names:
var ext = _name.rsplit('.', false, 1)
if ext.size() == 0 or ext[-1] != 'txt':
continue
var l = new()
l.identifier = _name.split('.', false, 1)[0]
l.name = l.identifier
l.terms = FileAccess.open(dir.path_join(_name), FileAccess.READ).get_as_text()
dict[l.identifier] = l
# get licenses built into the Godot Engine
var tmp = Engine.get_license_info()
for id in tmp:
if dict.has(id):
continue
var l = new()
l.identifier = id
l.terms = tmp[id]
dict[id] = l
return dict
# this is for formatting individual lines accoring to SPDX standards
static func _add_line_padding(combined_lines: String, padding: String = " ") -> String:
if combined_lines.is_empty():
return combined_lines
var lines = combined_lines.split("\n")
var s = ""
for i in len(lines):
if lines[i].is_empty() or lines[i] == "\n":
if i+1 < len(lines):
s += padding + "." + "\n"
else:
s += '\n'
else:
s += padding + lines[i] + "\n"
s = s.strip_edges(false)
s += '\n'
return s

View file

@ -0,0 +1,178 @@
class_name LicenseLink
extends Resource
## Files that are under this license [br]
## [color=red]WARNING[/color] DO NOT put in any file that Godot Cannot load, via Resource.load() [br]
## or it will prevent the game from launching. files like .txt .csg etc
@export var link_files: Array[Resource]
## Directories that are under this license [br]
## The given file's Parent Directory will be tracked [br]
## [color=red]WARNING[/color] DO NOT put in any file that Godot Cannot load, via Resource.load() [br]
## or it will prevent the game from launching. files like .txt .csg etc
@export var link_dirs: Array[Resource]
## Files that are under this license [br]
## Note: These paths are [b]NOT[/b] automatically tracked, [br]
## you will have to, manually keep these paths up to date
@export var link_paths: Array
## Example: Godot_Icon, Custom Font Name, Your Games Name, etc
@export var componet_name: String = ""
## Gets included in [method to_formatted_string] right after [member componet_name] [br]
## as part of the "Comment:" Section of the SPDX format
@export var extra: String = ""
## SPDX-License-Identifier or similar to it. CASE SENSITIVE[br]
## Like "CC0-1.0" or more complex entries like [br]
## "CC0-1.0 or MIT" [br]
## "CC0-1.0 and MIT" [br]
## See [url=https://spdx.org/licenses/]SPDX Identifier List[/url]
@export var license_identifier: String = "" : set = _set_identifier
## who and when was the copyright was created [br]
## example [br]
## 2022, John Doe [br]
## (next entry) [br]
## 2022-2023, Jim Stirling, Corp xyz [br]
@export var copyright: Array[String]
var license: License
## Unlike [member license_identifier] this contains [b]ONLY[/b] the identifiers [br]
var license_identifiers: Array[String]
## Either "Godot Engine" or "Game" [br]
## This value is AUTO GENERATED [br]
## [b]DON'T SET THIS VALUE MANUALLY[/b], IT CAN BREAK THINGS
var component_of: String = ""
func _init() -> void:
_set_identifier(license_identifier)
func _set_identifier(v: String):
license_identifier = v
var tmp = v.replace(' and ', '!break!').replace(' or ', '!break!').split('!break!', false)
for x in tmp:
license_identifiers.append(x)
func _to_string() -> String:
return self.to_formatted_string()
## Returns a string containing this link's information, formatted to [url=https://spdx.dev/resources/use/]SPDX Standards[/url]
func to_formatted_string(hide_files: bool = false):
var _files = ""
if not hide_files:
for x in link_files:
_files += x.resource_path.replace("res://", " ./").strip_edges() + "\n"
for x in link_dirs:
_files += (
x.resource_path.replace("res://", " ./").rsplit("/", false, 1)[0].strip_edges()
+ "/*\n"
)
for x in link_paths:
_files += x.replace("res://", " ./").strip_edges() + "\n"
_files = _files.strip_edges()
var _comment = ""
if not componet_name.is_empty():
_comment += componet_name
if not extra.is_empty():
_comment += "\n"
if not extra.is_empty():
_comment += extra
return "Files:{files}\nComment:{comment}\nCopyright:{copyright}\nLicense:{identifier}\n".format(
{
"files": _add_line_padding(_files, " "),
"comment": _add_line_padding(_comment, " "),
"copyright": _add_line_padding("\n".join(copyright), " "),
"identifier": _add_line_padding(license_identifier, " "),
}
)
# wouldn't recomend using this, unless you know what your doing
# but if you do, this loads and parses all links (LicenseLink Resource files) in a directory,
# plus Godot's built-in Licenses
#
# exclude engine: excludes loading Godot's built-in license information
# this is for mods, in which the main game will have already shown the Godot Engine's Licensing
static func _load_links_in(dir: String, exclude_engine: bool = false):
var dict = {
'array': [],
'by_identifier': {},
'by_parent': {},
}
if not DirAccess.dir_exists_absolute(dir):
printerr('Simple License: LicenseLinks directory is missing! ', dir)
return dict
# get Game license links
var names = DirAccess.get_files_at(dir)
if len(names) == 0:
print_verbose("\nSimple License: No LicenseLinks found in dir\n", dir, "\nif you have no LicenseLinks there, then this can be ignored\n")
for name in names:
name = name.replace('.remap', '')
var path = dir.path_join(name)
var res = ResourceLoader.load(path)
if res is Resource and res.get("copyright") != null:
if res.component_of.is_empty():
res.component_of = "Game"
dict.array.append(res)
dict.by_identifier[res.license_identifier] = res
if not dict.by_parent.has(res.component_of):
dict.by_parent[res.component_of] = {}
dict.by_parent[res.component_of][res.license_identifier] = res
# Get Engine license links
if not exclude_engine:
for a in Engine.get_copyright_info():
var l = new()
l.componet_name = a.name
l.component_of = "Godot Engine"
l.link_paths = a.parts[0].files
l.license_identifier = a.parts[0].license
l.copyright.append_array(a.parts[0].copyright)
dict.array.append(l)
dict.by_identifier[l.license_identifier] = l
if not dict.by_parent.has(l.component_of):
dict.by_parent[l.component_of] = {}
if not dict.by_parent[l.component_of].has(l.license_identifier):
dict.by_parent[l.component_of][l.license_identifier] = l
return dict
# this is for formatting individual lines accoring to SPDX standards
static func _add_line_padding(combined_lines: String, padding: String) -> String:
if combined_lines.is_empty():
return combined_lines
var lines = combined_lines.split("\n")
var s = ""
for i in len(lines):
if lines[i].is_empty() or lines[i] == "\n":
if i+1 < len(lines):
s += padding + "." + "\n"
else:
s += '\n'
else:
s += padding + lines[i] + "\n"
s = s.strip_edges(false)
return s

View file

@ -0,0 +1,121 @@
class_name LicenseManager
extends Node
## loads license information from this directory and the sub-directory "license_links"
@export var load_dir: String = "res://licenses"
## export license information to this directory and the sub-directory "licenses"
@export var export_dir: String = "user://"
## This disables loading Godot's built-in license information [br]
## this is for mods, in which the main game will have already shown the Godot's built-in Licensing
@export var exclude_engine: bool = false
## contains all loaded [License]s [br]
## key = identifier [br]
## value = [License]
var licenses := {}
## contains all loaded [LicenseLink]s [br]
## with searching in mind [br]
## "array" [] [br]
## "by_identifier" {} license identifier [br]
## "by_parent" {} parent component name [br]
var license_links := {
'array': [],
'by_identifier': {},
'by_parent': {},
}
## Loads license information from [member load_dir] [br]
func load_license_information():
licenses.clear()
license_links.array.clear()
license_links.by_identifier.clear()
license_links.by_parent.clear()
if not DirAccess.dir_exists_absolute(load_dir):
printerr("Failed to find license directory ", load_dir)
return
licenses = License._load_licenses_in(load_dir)
if licenses.has('Expat') and not licenses.has('MIT'):
var l = licenses['Expat'].duplicate() as License
l.identifier = 'MIT'
licenses['MIT'] = l
license_links = LicenseLink._load_links_in(load_dir.path_join('license_links'), exclude_engine)
## Returns a single string "file", that is formatted in the SPDX Standard [br]
## that contains all licensing information, contained in this instance, [br]
## if only_links, then the returned data will omit the licensing term files
func get_combined_copyright(only_links: bool = false) -> String:
var lines = ""
var used_licenses = {}
# Links
for link in license_links.array:
if link is LicenseLink:
lines += link.to_formatted_string(link.component_of == 'Godot Engine')
lines += '\n'
used_licenses.merge(get_all_valid_licenses(link))
lines += '\n\n'
if only_links:
return lines
# License Terms
var values = used_licenses.values()
for i in len(values):
if i+1 < len(values):
lines += values[i].to_formatted_string() + '\n'
else:
lines += values[i].to_formatted_string()
return lines
## Returns all licenses that are "valid"/exist [br]
## Sometimes license files are missing, or Identifiers are incorrectly spelled, this helps with that.
func get_all_valid_licenses(link: LicenseLink) -> Dictionary:
var d = {}
for x in link.license_identifiers:
if licenses.has(x):
d[x] = licenses[x]
return d
## export all license information to [member export_dir] and the sub-directory "licenses"
func export(directory: String = ""):
if directory.is_empty():
directory = export_dir
var licenses_path = directory.path_join('licenses')
if not DirAccess.dir_exists_absolute(licenses_path):
DirAccess.make_dir_recursive_absolute(licenses_path)
# Export the combined license file
var f = FileAccess.open(directory.path_join('COPYRIGHT.txt'), FileAccess.WRITE)
if f is FileAccess:
f.store_string(self.get_combined_copyright())
# Export the slim license file
f = FileAccess.open(directory.path_join('COPYRIGHT_SLIM.txt'), FileAccess.WRITE)
if f is FileAccess:
f.store_string(self.get_combined_copyright(true))
# Export the individual license files
var used = {}
for i in license_links.array.size():
var license = license_links.array[i] as LicenseLink
var ids = self.get_all_valid_licenses(license)
used.merge(ids)
for id in ids:
var license_path = licenses_path.path_join(id)+'.txt'
f = FileAccess.open(license_path, FileAccess.WRITE)
f.store_string(licenses[id].to_formatted_string())

Some files were not shown because too many files have changed in this diff Show more