Compare commits

...

18 Commits
0.21.1 ... main

Author SHA1 Message Date
cosmonaut 00614661ec fix broken test
continuous-integration/drone/push Build is passing Details
2021-03-23 17:50:05 -07:00
cosmonaut 36e98b0376 add dt and alpha params to renderers
continuous-integration/drone/push Build is failing Details
2021-03-23 17:37:47 -07:00
cosmonaut 6858ec1b0f Mega Refactor (#20)
continuous-integration/drone/push Build is passing Details
Co-Authored-By: cosmonaut <evan@moonside.games>
Co-Committed-By: cosmonaut <evan@moonside.games>
2021-03-12 08:25:25 +00:00
cosmonaut df0e251650 Merge pull request 'fix configuration' (#19) from fix_sln into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: #19
2021-01-30 01:09:35 +00:00
cosmonaut 5183c04632 fix configuration
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details
2021-01-29 17:04:13 -08:00
cosmonaut d5186e6011 remove some dependencies (#18)
continuous-integration/drone/push Build is passing Details
Co-Authored-By: cosmonaut <evan@moonside.games>
Co-Committed-By: cosmonaut <evan@moonside.games>
2021-01-30 00:36:42 +00:00
cosmonaut 49ea9e7a5d 0.23.0 (#16)
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2020-11-16 07:24:37 +00:00
cosmonaut 40e6d75638 Expose some enumerable iterators + some tweaks (#15)
continuous-integration/drone/push Build is passing Details
2020-11-16 07:21:51 +00:00
cosmonaut 327a458f17 Update 'encompass-cs/encompass-cs.csproj'
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2020-07-22 01:10:45 +00:00
Evan Hemsley d661ed5b17 Spawner.Spawn now requires in param
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
2020-07-21 18:05:47 -07:00
cosmonaut 1d458e3563 0.21.3
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
2020-07-20 03:18:12 +00:00
cosmonaut b4a5a4c66a Merge pull request 'fix silent failure when performing singular reads' (#11) from SingularReadFix into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: #11
2020-07-20 03:12:45 +00:00
Evan Hemsley a5fd322791 fix silent failure when performing singular reads
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details
2020-07-19 20:10:38 -07:00
cosmonaut 94e81a0258 0.21.2
continuous-integration/drone/tag Build is passing Details
continuous-integration/drone/push Build is passing Details
2020-07-16 07:15:08 +00:00
Evan Hemsley b234b9bad1 0.21.2
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details
2020-07-16 00:12:31 -07:00
cosmonaut 703e088430 fix IDrawableComponent throwing if non auto property used for Layer (#9)
continuous-integration/drone/push Build is passing Details
2020-07-16 07:10:21 +00:00
cosmonaut 59014c7a9e QueryWith and QueryWithout implicitly Read (#8)
continuous-integration/drone/push Build is passing Details
2020-07-12 22:17:38 +00:00
cosmonaut e76161c8af license (#7)
continuous-integration/drone/push Build is passing Details
2020-07-10 19:49:17 +00:00
48 changed files with 995 additions and 1220 deletions

View File

@ -7,13 +7,13 @@
steps:
- name: test
image: mcr.microsoft.com/dotnet/core/sdk:3.1
image: mcr.microsoft.com/dotnet/sdk:5.0.102-ca-patch-buster-slim
commands:
- dotnet build -c Release
- dotnet test -c Release
- name: deploy
image: mcr.microsoft.com/dotnet/core/sdk:3.1
image: mcr.microsoft.com/dotnet/sdk:5.0.102-ca-patch-buster-slim
environment:
API_KEY:
from_secret: API_KEY

424
LICENSE
View File

@ -1,415 +1,19 @@
encompass-cs
Copyright Evan Hemsley 2019
COOPERATIVE SOFTWARE LICENSE
Copyright (c) 2020 Evan Hemsley <evan@moonside.games>
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
COPYFARLEFT PUBLIC LICENSE ("LICENSE"). THE WORK IS PROTECTED BY
COPYRIGHT AND ALL OTHER APPLICABLE LAWS. ANY USE OF THE WORK OTHER THAN
AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY
EXERCISING ANY RIGHTS TO THE WORK PROVIDED IN THIS LICENSE, YOU AGREE
TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE
MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
CONTAINED HERE IN AS CONSIDERATION FOR ACCEPTING THE TERMS AND
CONDITIONS OF THIS LICENSE AND FOR AGREEING TO BE BOUND BY THE TERMS
AND CONDITIONS OF THIS LICENSE.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
1. DEFINITIONS
a. "Adaptation" means a work based upon the Work, or upon the
Work and other pre-existing works, such as a translation,
adaptation, derivative work, arrangement of music or other
alterations of a literary or artistic work, or phonogram or
performance and includes cinematographic adaptations or any
other form in which the Work may be recast, transformed, or
adapted including in any form recognizably derived from the
original, except that a work that constitutes a Collection will
not be considered an Adaptation for the purpose of this License.
For the avoidance of doubt, where the Work is a musical work,
performance or phonogram, the synchronization of the Work in
timed-relation with a moving image ("synching") will be
considered an Adaptation for the purpose of this License.
b. "Collection" means a collection of literary or artistic
works, such as encyclopedias and anthologies, or performances,
phonograms or broadcasts, or other works or subject matter other
than works listed in Section 1(f) below, which, by reason of the
selection and arrangement of their contents, constitute
intellectual creations, in which the Work is included in its
entirety in unmodified form along with one or more other
contributions, each constituting separate and independent works
in themselves, which together are assembled into a collective
whole. A work that constitutes a Collection will not be
considered an Adaptation (as defined above) for the purposes of
this License.
c. "Distribute" means to make available to the public the
original and copies of the Work or Adaptation, as appropriate,
through sale, gift or any other transfer of possession or
ownership.
d. "Licensor" means the individual, individuals, entity or
entities that offer(s) the Work under the terms of this License.
e. "Original Author" means, in the case of a literary or
artistic work, the individual, individuals, entity or entities
who created the Work or if no individual or entity can be
identified, the publisher; and in addition (i) in the case of a
performance the actors, singers, musicians, dancers, and other
persons who act, sing, deliver, declaim, play in, interpret or
otherwise perform literary or artistic works or expressions of
folklore; (ii) in the case of a phonogram the producer being the
person or legal entity who first fixes the sounds of a
performance or other sounds; and, (iii) in the case of
f. "Work" means the literary and/or artistic work offered under
the terms of this License including without limitation any
production in the literary, scientific and artistic domain,
whatever may be the mode or form of its expression including
digital form, such as a book, pamphlet and other writing; a
lecture, address, sermon or other work of the same nature; a
dramatic or dramatico-musical work; a choreographic work or
entertainment in dumb show; a musical composition with or
without words; a cinematographic work to which are assimilated
works expressed by a process analogous to cinematography; a work
of drawing, painting, architecture, sculpture, engraving or
lithography; a photographic work to which are assimilated works
expressed by a process analogous to photography; a work of
applied art; an illustration, map, plan, sketch or
three-dimensional work relative to geography, topography,
architecture or science; a performance; a broadcast; a
phonogram; a compilation of data to the extent it is protected
as a copyrightable work; or a work performed by a variety or
circus performer to the extent it is not otherwise considered a
literary or artistic work.
g. "You" means an individual or entity exercising rights under
this License who has not previously violated the terms of this
License with respect to the Work, or who has received express
permission from the Licensor to exercise rights under this
License despite a previous violation.
h. "Publicly Perform" means to perform public recitations of the
Work and to communicate to the public those public recitations,
by any means or process, including by wire or wireless means or
public digital performances; to make available to the public
Works in such a way that members of the public may access these
Works from a place and at a place individually chosen by them;
to perform the Work to the public by any means or process and
the communication to the public of the performances of the Work,
including by public digital performance; to broadcast and
rebroadcast the Work by any means including signs, sounds or
images.
i. "Reproduce" means to make copies of the Work by any means
including without limitation by sound or visual recordings and
the right of fixation and reproducing fixations of the Work,
including storage of a protected performance or phonogram in
digital form or other electronic medium.
j. "Software" means any digital Work which, through use of a
third-party piece of Software or through the direct usage of
itself on a computer system, the memory of the computer is
modified dynamically or semi-dynamically. "Software",
secondly, processes or interprets information.
k. "Source Code" means the human-readable form of Software
through which the Original Author and/or Distributor originally
created, derived, and/or modified it.
l. "Web Service" means the use of a piece of Software to
interpret or modify information that is subsequently and directly
served to users over the Internet.
2. FAIR DEALING RIGHTS
Nothing in this License is intended to reduce, limit, or restrict any
uses free from copyright or rights arising from limitations or
exceptions that are provided for in connection with the copyright
protection under copyright law or other applicable laws.
3. LICENSE GRANT
Subject to the terms and conditions of this License, Licensor hereby
grants You a worldwide, royalty-free, non-exclusive, perpetual (for the
duration of the applicable copyright) license to exercise the rights in
the Work as stated below:
a. to Reproduce the Work, to incorporate the Work into one or
more Collections, and to Reproduce the Work as incorporated in
the Collections;
b. to create and Reproduce Adaptations provided that any such
Adaptation, including any translation in any medium, takes
reasonable steps to clearly label, demarcate or otherwise
identify that changes were made to the original Work. For
example, a translation could be marked "The original work was
translated from English to Spanish," or a modification could
indicate "The original work has been modified.";
c. to Distribute and Publicly Perform the Work including as
incorporated in Collections; and,
d. to Distribute and Publicly Perform Adaptations. The above
rights may be exercised in all media and formats whether now
known or hereafter devised. The above rights include the right
to make such modifications as are technically necessary to
exercise the rights in other media and formats. Subject to
Section 8(g), all rights not expressly granted by Licensor are
hereby reserved, including but not limited to the rights set
forth in Section 4(h).
4. RESTRICTIONS
The license granted in Section 3 above is expressly made subject to and
limited by the following restrictions:
a. You may Distribute or Publicly Perform the Work only under
the terms of this License. You must include a copy of, or the
Uniform Resource Identifier (URI) for, this License with every
copy of the Work You Distribute or Publicly Perform. You may not
offer or impose any terms on the Work that restrict the terms of
this License or the ability of the recipient of the Work to
exercise the rights granted to that recipient under the terms of
the License. You may not sublicense the Work. You must keep
intact all notices that refer to this License and to the
disclaimer of warranties with every copy of the Work You
Distribute or Publicly Perform. When You Distribute or Publicly
Perform the Work, You may not impose any effective technological
measures on the Work that restrict the ability of a recipient of
the Work from You to exercise the rights granted to that
recipient under the terms of the License. This Section 4(a)
applies to the Work as incorporated in a Collection, but this
does not require the Collection apart from the Work itself to be
made subject to the terms of this License. If You create a
Collection, upon notice from any Licensor You must, to the
extent practicable, remove from the Collection any credit as
required by Section 4(f), as requested. If You create an
Adaptation, upon notice from any Licensor You must, to the
extent practicable, remove from the Adaptation any credit as
required by Section 4(f), as requested.
b. Subject to the exception in Section 4(e), you may not
exercise any of the rights granted to You in Section 3 above in
any manner that is primarily intended for or directed toward
commercial advantage or private monetary compensation. The
exchange of the Work for other copyrighted works by means of
digital file-sharing or otherwise shall not be considered to be
intended for or directed toward commercial advantage or private
monetary compensation, provided there is no payment of any
monetary compensation in connection with the exchange of
copyrighted works.
c. If the Work meets the definition of Software, You may exercise
the rights granted in Section 3 only if You provide a copy of the
corresponding Source Code from which the Work was derived in digital
form, or You provide a URI for the corresponding Source Code of
the Work, to any recipients upon request.
d. If the Work is used as or for a Web Service, You may exercise
the rights granted in Section 3 only if You provide a copy of the
corresponding Source Code from which the Work was derived in digital
form, or You provide a URI for the corresponding Source Code to the
Work, to any recipients of the data served or modified by the Web
Service.
e. You may exercise the rights granted in Section 3 for
commercial purposes only if you statisy any of the following:
i. You are a worker-owned business or worker-owned
collective; and
ii. after tax, all financial gain, surplus, profits and
benefits produced by the business or collective are
distributed among the worker-owners
iii. You are not using such rights on behalf of a business
other than those specified in 4(e.i) and elaborated upon in
4(e.ii), nor are using such rights as a proxy on behalf of a
business with the intent to circumvent the aformentioned
restrictions on such a business.
f. Any use by a business that is privately owned and managed,
and that seeks to generate profit from the labor of employees
paid by salary or other wages, is not permitted under this
license.
g. If You Distribute, or Publicly Perform the Work or any
Adaptations or Collections, You must, unless a request has been
made pursuant to Section 4(a), keep intact all copyright notices
for the Work and provide, reasonable to the medium or means You
are utilizing: (i) the name of the Original Author (or
pseudonym, if applicable) if supplied, and/or if the Original
Author and/or Licensor designate another party or parties (e.g.,
a sponsor institute, publishing entity, journal) for attribution
("Attribution Parties") in Licensor!s copyright notice, terms of
service or by other reasonable means, the name of such party or
parties; (ii) the title of the Work if supplied; (iii) to the
extent reasonably practicable, the URI, if any, that Licensor
specifies to be associated with the Work, unless such URI does
not refer to the copyright notice or licensing information for
the Work; and, (iv) consistent with Section 3(b), in the case of
an Adaptation, a credit identifying the use of the Work in the
Adaptation (e.g., "French translation of the Work by Original
Author," or "Screenplay based on original Work by Original
Author"). The credit required by this Section 4(f) may be
implemented in any reasonable manner; provided, however, that in
the case of a Adaptation or Collection, at a minimum such credit
will appear, if a credit for all contributing authors of the
Adaptation or Collection appears, then as part of these credits
and in a manner at least as prominent as the credits for the
other contributing authors. For the avoidance of doubt, You may
only use the credit required by this Section for the purpose of
attribution in the manner set out above and, by exercising Your
rights under this License, You may not implicitly or explicitly
assert or imply any connection with, sponsorship or endorsement
by the Original Author, Licensor and/or Attribution Parties, as
appropriate, of You or Your use of the Work, without the
separate, express prior written permission of the Original
Author, Licensor and/or Attribution Parties.
h. For the avoidance of doubt:
i. Non-waivable Compulsory License Schemes. In those
jurisdictions in which the right to collect royalties
through any statutory or compulsory licensing scheme
cannot be waived, the Licensor reserves the exclusive
right to collect such royalties for any exercise by You of
the rights granted under this License;
ii. Waivable Compulsory License Schemes. In those
jurisdictions in which the right to collect royalties
through any statutory or compulsory licensing scheme can
be waived, the Licensor reserves the exclusive right to
collect such royalties for any exercise by You of the
rights granted under this License if Your exercise of such
rights is for a purpose or use which is otherwise than
noncommercial as permitted under Section 4(b) and
otherwise waives the right to collect royalties through
any statutory or compulsory licensing scheme; and,
iii.Voluntary License Schemes. The Licensor reserves the
right to collect royalties, whether individually or, in
the event that the Licensor is a member of a collecting
society that administers voluntary licensing schemes, via
that society, from any exercise by You of the rights
granted under this License that is for a purpose or use
which is otherwise than noncommercial as permitted under
Section 4(b).
i. Except as otherwise agreed in writing by the Licensor or as
may be otherwise permitted by applicable law, if You Reproduce,
Distribute or Publicly Perform the Work either by itself or as
part of any Adaptations or Collections, You must not distort,
mutilate, modify or take other derogatory action in relation to
the Work which would be prejudicial to the Original Author's
honor or reputation. Licensor agrees that in those jurisdictions
(e.g. Japan), in which any exercise of the right granted in
Section 3(b) of this License (the right to make Adaptations)
would be deemed to be a distortion, mutilation, modification or
other derogatory action prejudicial to the Original Author's
honor and reputation, the Licensor will waive or not assert, as
appropriate, this Section, to the fullest extent permitted by
the applicable national law, to enable You to reasonably
exercise Your right under Section 3(b) of this License (right to
make Adaptations) but not otherwise.
5. REPRESENTATIONS, WARRANTIES AND DISCLAIMER
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
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, MERCHANTIBILITY,
FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF
ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW
THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO
YOU.
6. LIMITATION ON LIABILITY
EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL
LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF
THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED
OF THE POSSIBILITY OF SUCH DAMAGES.
7. TERMINATION
a. This License and the rights granted hereunder will terminate
automatically upon any breach by You of the terms of this
License. Individuals or entities who have received Adaptations
or Collections from You under this License, however, will not
have their licenses terminated provided such individuals or
entities remain in full compliance with those licenses. Sections
1, 2, 5, 6, 7, and 8 will survive any termination of this
License.
b. Subject to the above terms and conditions, the license
granted here is perpetual (for the duration of the applicable
copyright in the Work). Notwithstanding the above, Licensor
reserves the right to release the Work under different license
terms or to stop distributing the Work at any time; provided,
however that any such election will not serve to withdraw this
License (or any other license that has been, or is required to
be, granted under the terms of this License), and this License
will continue in full force and effect unless terminated as
stated above.
8. MISCELLANEOUS
a. Each time You Distribute or Publicly Perform the Work or a
Collection, the Licensor offers to the recipient a license to
the Work on the same terms and conditions as the license granted
to You under this License.
b. Each time You Distribute or Publicly Perform an Adaptation,
Licensor offers to the recipient a license to the original Work
on the same terms and conditions as the license granted to You
under this License.
c. If the Work is classified as Software, each time You Distribute
or Publicly Perform an Adaptation, Licensor offers to the recipient
a copy and/or URI of the corresponding Source Code on the same
terms and conditions as the license granted to You under this License.
d. If the Work is used as a Web Service, each time You Distribute
or Publicly Perform an Adaptation, or serve data derived from the
Software, the Licensor offers to any recipients of the data a copy
and/or URI of the corresponding Source Code on the same terms and
conditions as the license granted to You under this License.
e. If any provision of this License is invalid or unenforceable
under applicable law, it shall not affect the validity or
enforceability of the remainder of the terms of this License,
and without further action by the parties to this agreement,
such provision shall be reformed to the minimum extent necessary
to make such provision valid and enforceable.
f. No term or provision of this License shall be deemed waived
and no breach consented to unless such waiver or consent shall
be in writing and signed by the party to be charged with such
waiver or consent.
g. This License constitutes the entire agreement between the
parties with respect to the Work licensed here. There are no
understandings, agreements or representations with respect to
the Work not specified here. Licensor shall not be bound by any
additional provisions that may appear in any communication from
You. This License may not be modified without the mutual written
agreement of the Licensor and You.
h. The rights granted under, and the subject matter referenced,
in this License were drafted utilizing the terminology of the
Berne Convention for the Protection of Literary and Artistic
Works (as amended on September 28, 1979), the Rome Convention of
1961, the WIPO Copyright Treaty of 1996, the WIPO Performances
and Phonograms Treaty of 1996 and the Universal Copyright
Convention (as revised on July 24, 1971). These rights and
subject matter take effect in the relevant jurisdiction in which
the License terms are sought to be enforced according to the
corresponding provisions of the implementation of those treaty
provisions in the applicable national law. If the standard suite
of rights granted under applicable copyright law includes
additional rights not granted under this License, such
additional rights are deemed to be included in the License; this
License is not intended to restrict the license of any rights
under applicable law.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

7
TODO
View File

@ -1,7 +0,0 @@
- immutable component system?
- method to remove all components of a type without destroying Entities
- method to remove a component of a type without destroying entity
- look at test coverage
- docs

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
# Visual Studio Version 16
VisualStudioVersion = 16.0.30717.126
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "encompass-cs", "encompass-cs\encompass-cs.csproj", "{B862FC25-0740-4CEA-BC53-3C5F43DCD985}"
EndProject
@ -9,38 +9,28 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "test", "test\test.csproj",
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Debug|x64.ActiveCfg = Debug|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Debug|x64.Build.0 = Debug|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Debug|x86.ActiveCfg = Debug|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Debug|x86.Build.0 = Debug|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Release|Any CPU.Build.0 = Release|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Release|x64.ActiveCfg = Release|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Release|x64.Build.0 = Release|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Release|x86.ActiveCfg = Release|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Release|x86.Build.0 = Release|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Debug|x64.ActiveCfg = Debug|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Debug|x64.Build.0 = Debug|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Debug|x86.ActiveCfg = Debug|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Debug|x86.Build.0 = Debug|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Release|Any CPU.Build.0 = Release|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Release|x64.ActiveCfg = Release|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Release|x64.Build.0 = Release|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Release|x86.ActiveCfg = Release|Any CPU
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Release|x86.Build.0 = Release|Any CPU
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Debug|x64.ActiveCfg = Debug|x64
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Debug|x64.Build.0 = Debug|x64
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Debug|x86.ActiveCfg = Debug|x86
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Debug|x86.Build.0 = Debug|x86
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Release|x64.ActiveCfg = Release|x64
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Release|x64.Build.0 = Release|x64
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Release|x86.ActiveCfg = Release|x86
{B862FC25-0740-4CEA-BC53-3C5F43DCD985}.Release|x86.Build.0 = Release|x86
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Debug|x64.ActiveCfg = Debug|x64
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Debug|x64.Build.0 = Debug|x64
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Debug|x86.ActiveCfg = Debug|x86
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Debug|x86.Build.0 = Debug|x86
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Release|x64.ActiveCfg = Release|x64
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Release|x64.Build.0 = Release|x64
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Release|x86.ActiveCfg = Release|x86
{23D6C29C-A310-4D3E-8455-8D0B8CA1FC06}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
namespace Encompass
{
[AttributeUsage(AttributeTargets.Class)]
public class Adds : Attribute
{
public readonly HashSet<Type> addTypes;
public Adds(params Type[] addTypes)
{
this.addTypes = new HashSet<Type>(addTypes);
}
}
}

View File

@ -1,7 +1,6 @@
using Encompass.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Encompass
{

View File

@ -1,7 +1,5 @@
using Encompass.Exceptions;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Encompass
{

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Encompass.Exceptions;
namespace Encompass
{

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Encompass.Exceptions;
namespace Encompass
{
@ -12,15 +10,6 @@ namespace Encompass
public Receives(params Type[] receiveTypes)
{
foreach (var receiveType in receiveTypes)
{
var isMessage = receiveType.GetInterfaces().Contains(typeof(IMessage));
if (!isMessage)
{
throw new IllegalSendTypeException("{0} must be a Message", receiveType.Name);
}
}
ReceiveTypes = new HashSet<Type>(receiveTypes);
}
}

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Encompass.Exceptions;
namespace Encompass
{
@ -12,15 +10,6 @@ namespace Encompass
public Sends(params Type[] sendTypes)
{
foreach (var sendType in sendTypes)
{
var isMessage = sendType.GetInterfaces().Contains(typeof(IMessage));
if (!isMessage)
{
throw new IllegalSendTypeException("{0} must be a Message", sendType.Name);
}
}
this.SendTypes = new HashSet<Type>(sendTypes);
}
}

View File

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Encompass.Exceptions;
namespace Encompass
{

View File

@ -0,0 +1,156 @@
using System;
namespace Encompass
{
public static unsafe class MemoryHelper
{
public static void Copy(uint* src, uint* dest, int count)
{
for (; count != 0; count--) *dest++ = *src++;
}
public static void Fill(uint* p, int count, uint value)
{
for (; count != 0; count--) *p++ = value;
}
public static void And(uint* p, uint* q, uint* result, int count)
{
for (; count != 0; count--) *result++ = *p++ & *q++;
}
public static void Or(uint* p, uint* q, uint* result, int count)
{
for (; count != 0; count--) *result++ = *p++ | *q++;
}
public static void Not(uint* p, uint* result, int count)
{
for (; count != 0; count--) *result++ = ~*p++;
}
public static bool Equal(uint* p, uint* q, int count)
{
for (; count != 0; count--) if (*p++ != *q++) { return false; }
return true;
}
}
public unsafe struct BitSet512 : IEquatable<BitSet512>
{
public static BitSet512 Zero { get; } = new BitSet512(0);
public static BitSet512 Ones { get; } = new BitSet512(uint.MaxValue);
private const int _uintLength = 16;
private fixed uint _buffer[_uintLength];
public BitSet512(uint value)
{
fixed (uint* p = _buffer) MemoryHelper.Fill(p, _uintLength, value);
}
public BitSet512(uint* src)
{
fixed (uint* dest = _buffer) MemoryHelper.Copy(src, dest, _uintLength);
}
public static BitSet512 operator &(BitSet512 a, BitSet512 b)
{
var tmp = stackalloc uint[_uintLength];
MemoryHelper.And(a._buffer, b._buffer, tmp, _uintLength);
return new BitSet512(tmp);
}
public static BitSet512 operator |(BitSet512 a, BitSet512 b)
{
var tmp = stackalloc uint[_uintLength];
MemoryHelper.Or(a._buffer, b._buffer, tmp, _uintLength);
return new BitSet512(tmp);
}
public static BitSet512 operator ~(BitSet512 a)
{
var tmp = stackalloc uint[_uintLength];
MemoryHelper.Not(a._buffer, tmp, _uintLength);
return new BitSet512(tmp);
}
public static bool operator ==(BitSet512 left, BitSet512 right)
{
return left.Equals(right);
}
public static bool operator !=(BitSet512 left, BitSet512 right)
{
return !(left == right);
}
public BitSet512 Set(int index)
{
var tmp = stackalloc uint[_uintLength];
fixed (uint* p = _buffer) MemoryHelper.Copy(p, tmp, _uintLength);
tmp[index / 32] |= (uint)(1 << index % 32);
return new BitSet512(tmp);
}
public BitSet512 UnSet(int index)
{
var tmp = stackalloc uint[_uintLength];
fixed (uint* p = _buffer) MemoryHelper.Copy(p, tmp, _uintLength);
tmp[index / 32] &= ~(uint)(1 << index % 32);
return new BitSet512(tmp);
}
public bool Get(int bitIndex)
{
var bitInt = (uint)(1 << bitIndex % 32);
return (_buffer[bitIndex / 32] & bitInt) == bitInt;
}
public bool AllTrue()
{
return this == Ones;
}
public bool AllFalse()
{
return this == Zero;
}
public static BitSet512 BitwiseAnd(BitSet512 left, BitSet512 right)
{
return left & right;
}
public static BitSet512 BitwiseOr(BitSet512 left, BitSet512 right)
{
return left | right;
}
public static BitSet512 OnesComplement(BitSet512 bitSet)
{
return ~bitSet;
}
public override bool Equals(object obj)
{
return obj is BitSet512 set && Equals(set);
}
public bool Equals(BitSet512 other)
{
fixed (uint* p = _buffer) return MemoryHelper.Equal(p, other._buffer, _uintLength);
}
public override int GetHashCode()
{
var hc = 0;
for (var i = 0; i < _uintLength; i++)
{
hc ^= _buffer[i].GetHashCode();
}
return hc;
}
}
}

View File

@ -1,4 +1,3 @@
using MoonTools.FastCollections;
using System;
using System.Collections.Generic;

View File

@ -74,7 +74,7 @@ namespace Encompass
}
}
public Span<Entity> AllEntities<TComponent>() where TComponent : struct
public ReadOnlySpan<Entity> AllEntities<TComponent>() where TComponent : struct
{
return _store.AllEntities<TComponent>();
}

View File

@ -1,4 +1,4 @@
using MoonTools.FastCollections;
using Encompass.Exceptions;
using System;
using System.Collections.Generic;
@ -54,11 +54,15 @@ namespace Encompass
public ref readonly TComponent Singular<TComponent>() where TComponent : struct
{
if (!Any<TComponent>()) { throw new NoComponentOfTypeException("No component of type {0} exists", typeof(TComponent).Name); }
return ref Lookup<TComponent>().Singular();
}
public ref readonly Entity SingularEntity<TComponent>() where TComponent : struct
{
if (!Any<TComponent>()) { throw new NoComponentOfTypeException("No component of type {0} exists", typeof(TComponent).Name); }
return ref Lookup<TComponent>().SingularEntity();
}
@ -108,16 +112,26 @@ namespace Encompass
return Lookup<TComponent>().Count > 0;
}
public Span<TComponent> All<TComponent>() where TComponent : struct
public ReadOnlySpan<TComponent> All<TComponent>() where TComponent : struct
{
return Lookup<TComponent>().AllComponents();
}
public Span<Entity> AllEntities<TComponent>() where TComponent : struct
public IEnumerable<TComponent> AllAsEnumerable<TComponent>() where TComponent : struct
{
return Lookup<TComponent>().AllComponentsAsEnumerable();
}
public ReadOnlySpan<Entity> AllEntities<TComponent>() where TComponent : struct
{
return Lookup<TComponent>().AllEntities();
}
public IEnumerable<Entity> AllEntitiesAsEnumerable<TComponent>() where TComponent : struct
{
return Lookup<TComponent>().AllEntitiesAsEnumerable();
}
public void Clear<TComponent>() where TComponent : struct
{
Lookup<TComponent>().Clear();

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Encompass.Exceptions;
namespace Encompass
{
@ -7,58 +8,60 @@ namespace Encompass
{
private readonly Dictionary<Type, TypedMessageStore> _stores = new Dictionary<Type, TypedMessageStore>(512);
private void RegisterMessageType<TMessage>() where TMessage : struct, IMessage
private void RegisterMessageType<TMessage>() where TMessage : struct
{
_stores.Add(typeof(TMessage), new TypedMessageStore<TMessage>());
}
private TypedMessageStore<TMessage> Lookup<TMessage>() where TMessage : struct, IMessage
private TypedMessageStore<TMessage> Lookup<TMessage>() where TMessage : struct
{
if (!_stores.ContainsKey(typeof(TMessage))) { RegisterMessageType<TMessage>(); }
return _stores[typeof(TMessage)] as TypedMessageStore<TMessage>;
}
public void AddMessage<TMessage>(in TMessage message) where TMessage : struct, IMessage
public void AddMessage<TMessage>(in TMessage message) where TMessage : struct
{
Lookup<TMessage>().Add(message);
}
public void AddMessage<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
public void AddMessage<TMessage>(in TMessage message, double time) where TMessage : struct
{
Lookup<TMessage>().Add(message, time);
}
public void AddMessageIgnoringTimeDilation<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
public void AddMessageIgnoringTimeDilation<TMessage>(in TMessage message, double time) where TMessage : struct
{
Lookup<TMessage>().AddIgnoringTimeDilation(message, time);
}
public ref readonly TMessage First<TMessage>() where TMessage : struct, IMessage
public ref readonly TMessage First<TMessage>() where TMessage : struct
{
if (!Any<TMessage>()) { throw new NoMessageOfTypeException("No Message of type {0} exists", typeof(TMessage).Name); }
return ref Lookup<TMessage>().First();
}
public Span<TMessage> All<TMessage>() where TMessage : struct, IMessage
public ReadOnlySpan<TMessage> All<TMessage>() where TMessage : struct
{
return Lookup<TMessage>().All();
}
public bool Any<TMessage>() where TMessage : struct, IMessage
public bool Any<TMessage>() where TMessage : struct
{
return Lookup<TMessage>().Any();
}
public IEnumerable<TMessage> WithEntity<TMessage>(int entityID) where TMessage : struct, IMessage, IHasEntity
public IEnumerable<TMessage> WithEntity<TMessage>(int entityID) where TMessage : struct, IHasEntity
{
return Lookup<TMessage>().WithEntity(entityID);
}
public ref readonly TMessage FirstWithEntity<TMessage>(int entityID) where TMessage : struct, IMessage
public ref readonly TMessage FirstWithEntity<TMessage>(int entityID) where TMessage : struct
{
return ref Lookup<TMessage>().FirstWithEntity(entityID);
}
public bool SomeWithEntity<TMessage>(int entityID) where TMessage : struct, IMessage, IHasEntity
public bool SomeWithEntity<TMessage>(int entityID) where TMessage : struct, IHasEntity
{
return Lookup<TMessage>().SomeWithEntity(entityID);
}

View File

@ -78,8 +78,8 @@ namespace Encompass
{
if (!_priorities.ContainsKey(entityID) || priority <= _priorities[entityID]) // if priorities are equal that means it's the same engine
{
_priorities[entityID] = priority;
ForceRemove(entityID);
_priorities[entityID] = priority;
return true;
}
@ -92,7 +92,6 @@ namespace Encompass
{
var storageIndex = _entityIDToStorageIndex[entityID];
_entityIDToStorageIndex.Remove(entityID);
_priorities.Remove(entityID);
// move a component into the hole to maintain contiguous memory
if (_nextID > 1 && storageIndex != _nextID - 1)
@ -127,14 +126,24 @@ namespace Encompass
_priorities.Clear();
}
public Span<Entity> AllEntities()
public ReadOnlySpan<Entity> AllEntities()
{
return new Span<Entity>(_storageIndexToEntities, 0, _nextID);
return new ReadOnlySpan<Entity>(_storageIndexToEntities, 0, _nextID);
}
public Span<TComponent> AllComponents()
public IEnumerable<Entity> AllEntitiesAsEnumerable()
{
return new Span<TComponent>(_components, 0, _nextID);
return new ArraySegment<Entity>(_storageIndexToEntities, 0, _nextID);
}
public ReadOnlySpan<TComponent> AllComponents()
{
return new ReadOnlySpan<TComponent>(_components, 0, _nextID);
}
public IEnumerable<TComponent> AllComponentsAsEnumerable()
{
return new ArraySegment<TComponent>(_components, 0, _nextID);
}
}
}

View File

@ -9,7 +9,7 @@ namespace Encompass
public abstract void Clear();
}
internal class TypedMessageStore<TMessage> : TypedMessageStore where TMessage : struct, IMessage
internal class TypedMessageStore<TMessage> : TypedMessageStore where TMessage : struct
{
// messages are placed in a contiguous region
// so we can return the collection as a Span
@ -92,9 +92,9 @@ namespace Encompass
return _nextIndex != 0;
}
public Span<TMessage> All()
public ReadOnlySpan<TMessage> All()
{
return new Span<TMessage>(_store, 0, _nextIndex);
return new ReadOnlySpan<TMessage>(_store, 0, _nextIndex);
}
public IEnumerable<TMessage> WithEntity(int entityID)

View File

@ -5,8 +5,6 @@ namespace Encompass
{
internal class ComponentManager
{
private readonly DrawLayerManager _drawLayerManager;
private readonly ComponentStore _existingComponentStore;
private readonly ComponentStore _immediateComponentStore;
private readonly ComponentDeltaStore _replayStore;
@ -19,9 +17,8 @@ namespace Encompass
internal ComponentBitSet ImmediateBits { get { return _immediateComponentStore.ComponentBitSet; } }
internal ComponentBitSet ExistingBits { get { return _existingComponentStore.ComponentBitSet; } }
public ComponentManager(DrawLayerManager drawLayerManager, Dictionary<Type, int> typeToIndex)
public ComponentManager(Dictionary<Type, int> typeToIndex)
{
this._drawLayerManager = drawLayerManager;
_existingComponentStore = new ComponentStore(typeToIndex);
_immediateComponentStore = new ComponentStore(typeToIndex);
_replayStore = new ComponentDeltaStore(typeToIndex);
@ -47,11 +44,6 @@ namespace Encompass
_upToDateComponentStore.SwapWith(componentStore);
}
internal void RegisterDrawableComponent<TComponent>(int entityID, int layer) where TComponent : struct
{
_drawLayerManager.RegisterComponentWithLayer<TComponent>(entityID, layer);
}
internal void WriteComponents()
{
_existingComponentStore.UpdateUsing(_replayStore);
@ -98,7 +90,7 @@ namespace Encompass
// existing or immediate reads
internal Span<TComponent> ReadExistingAndImmediateComponentsByType<TComponent>() where TComponent : struct
internal ReadOnlySpan<TComponent> ReadExistingAndImmediateComponentsByType<TComponent>() where TComponent : struct
{
return _upToDateComponentStore.All<TComponent>();
}
@ -108,7 +100,7 @@ namespace Encompass
return ref _upToDateComponentStore.Singular<TComponent>();
}
internal Span<Entity> GetExistingAndImmediateEntities<TComponent>() where TComponent : struct
internal ReadOnlySpan<Entity> GetExistingAndImmediateEntities<TComponent>() where TComponent : struct
{
return _upToDateComponentStore.AllEntities<TComponent>();
}
@ -125,7 +117,7 @@ namespace Encompass
// existing reads
internal Span<TComponent> GetExistingComponents<TComponent>() where TComponent : struct
internal ReadOnlySpan<TComponent> GetExistingComponents<TComponent>() where TComponent : struct
{
return _existingComponentStore.All<TComponent>();
}
@ -135,11 +127,16 @@ namespace Encompass
return ref _existingComponentStore.Singular<TComponent>();
}
internal Span<Entity> GetExistingEntities<TComponent>() where TComponent : struct
internal ReadOnlySpan<Entity> GetExistingEntities<TComponent>() where TComponent : struct
{
return _existingComponentStore.AllEntities<TComponent>();
}
internal IEnumerable<Entity> GetExistingEntitiesAsEnumerable<TComponent>() where TComponent : struct
{
return _existingComponentStore.AllEntitiesAsEnumerable<TComponent>();
}
internal ref readonly Entity ExistingSingularEntity<TComponent>() where TComponent : struct
{
return ref _existingComponentStore.SingularEntity<TComponent>();
@ -152,7 +149,7 @@ namespace Encompass
// immediate reads
internal Span<TComponent> ReadImmediateComponentsByType<TComponent>() where TComponent : struct
internal ReadOnlySpan<TComponent> ReadImmediateComponentsByType<TComponent>() where TComponent : struct
{
return _immediateComponentStore.All<TComponent>();
}
@ -162,7 +159,7 @@ namespace Encompass
return ref _immediateComponentStore.Singular<TComponent>();
}
internal Span<Entity> GetImmediateEntities<TComponent>() where TComponent : struct
internal ReadOnlySpan<Entity> GetImmediateEntities<TComponent>() where TComponent : struct
{
return _immediateComponentStore.AllEntities<TComponent>();
}
@ -226,11 +223,16 @@ namespace Encompass
return _immediateComponentStore.Has(type, entityID);
}
internal Span<TComponent> GetComponentsByType<TComponent>() where TComponent : struct
internal ReadOnlySpan<TComponent> GetComponentsByType<TComponent>() where TComponent : struct
{
return _existingComponentStore.All<TComponent>();
}
internal IEnumerable<TComponent> GetComponentsByTypeEnumerable<TComponent>() where TComponent : struct
{
return _existingComponentStore.AllAsEnumerable<TComponent>();
}
internal ref readonly TComponent GetComponentByEntityAndType<TComponent>(int entityID) where TComponent : struct
{
return ref _existingComponentStore.Get<TComponent>(entityID);
@ -254,7 +256,6 @@ namespace Encompass
_immediateComponentStore.Remove(entityID);
_replayStore.Remove(entityID);
_upToDateComponentStore.Remove(entityID);
_drawLayerManager.UnRegisterEntityWithLayer(entityID);
}
_entitiesMarkedForRemoval.Clear();
@ -266,7 +267,6 @@ namespace Encompass
{
_replayStore.Remove<TComponent>(entityID, priority);
_upToDateComponentStore.Remove<TComponent>(entityID, priority);
_drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entityID);
return true;
}
return false;
@ -277,7 +277,6 @@ namespace Encompass
if (_upToDateComponentStore.Remove<TComponent>(entityID, priority))
{
_replayStore.Remove<TComponent>(entityID, priority);
_drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entityID);
}
}

View File

@ -1,132 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Encompass.Exceptions;
namespace Encompass
{
internal class DrawLayerManager
{
private readonly SortedList<int, int> _layerOrder = new SortedList<int, int>();
private readonly Dictionary<int, Dictionary<Type, HashSet<int>>> _layerIndexToTypeToID = new Dictionary<int, Dictionary<Type, HashSet<int>>>();
private readonly Dictionary<int, HashSet<GeneralRenderer>> _layerIndexToGeneralRenderers = new Dictionary<int, HashSet<GeneralRenderer>>(512);
private readonly Dictionary<Type, Dictionary<int, int>> _typeToEntityToLayer = new Dictionary<Type, Dictionary<int, int>>(512);
public IEnumerable<int> LayerOrder { get { return _layerOrder.Values; } }
public DrawLayerManager()
{
RegisterDrawLayer(0);
}
public void RegisterDrawLayer(int layer)
{
if (!_layerIndexToTypeToID.ContainsKey(layer))
{
_layerOrder.Add(layer, layer);
_layerIndexToGeneralRenderers.Add(layer, new HashSet<GeneralRenderer>());
_layerIndexToTypeToID.Add(layer, new Dictionary<Type, HashSet<int>>());
}
}
public void RegisterOrderedDrawable<TComponent>() where TComponent : struct
{
if (!_typeToEntityToLayer.ContainsKey(typeof(TComponent)))
{
_typeToEntityToLayer.Add(typeof(TComponent), new Dictionary<int, int>(128));
}
foreach (var pair in _layerIndexToTypeToID)
{
if (!pair.Value.ContainsKey(typeof(TComponent)))
{
pair.Value.Add(typeof(TComponent), new HashSet<int>());
}
}
}
public void RegisterGeneralRendererWithLayer(GeneralRenderer renderer, int layer)
{
RegisterDrawLayer(layer);
var set = _layerIndexToGeneralRenderers[layer];
set.Add(renderer);
}
public void RegisterComponentWithLayer<TComponent>(int entityID, int layer) where TComponent : struct
{
if (!_layerIndexToTypeToID.ContainsKey(layer))
{
throw new UndefinedLayerException("Layer {0} is not defined. Use WorldBuilder.RegisterDrawLayer to register the layer.", layer);
}
if (_typeToEntityToLayer[typeof(TComponent)].ContainsKey(entityID))
{
if (_typeToEntityToLayer[typeof(TComponent)][entityID] != layer)
{
UnRegisterComponentWithLayer<TComponent>(entityID);
var set = _layerIndexToTypeToID[layer][typeof(TComponent)];
set.Add(entityID);
_typeToEntityToLayer[typeof(TComponent)].Add(entityID, layer);
}
}
else
{
var set = _layerIndexToTypeToID[layer][typeof(TComponent)];
set.Add(entityID);
_typeToEntityToLayer[typeof(TComponent)].Add(entityID, layer);
}
}
public void UnRegisterComponentWithLayer<TComponent>(int entityID) where TComponent : struct
{
if (!_typeToEntityToLayer.ContainsKey(typeof(TComponent))) { return; }
if (_typeToEntityToLayer[typeof(TComponent)].ContainsKey(entityID))
{
var layer = _typeToEntityToLayer[typeof(TComponent)][entityID];
_layerIndexToTypeToID[layer][typeof(TComponent)].Remove(entityID);
}
_typeToEntityToLayer[typeof(TComponent)].Remove(entityID);
}
public void UnRegisterEntityWithLayer(int entityID)
{
foreach (var store in _layerIndexToTypeToID.Values)
{
foreach (var typeToSet in store)
{
var type = typeToSet.Key;
var set = typeToSet.Value;
if (set.Contains(entityID))
{
_typeToEntityToLayer[type].Remove(entityID);
set.Remove(entityID);
}
}
}
}
public IEnumerable<GeneralRenderer> GeneralRenderersByLayer(int layer)
{
return _layerIndexToGeneralRenderers.ContainsKey(layer) ?
_layerIndexToGeneralRenderers[layer] :
Enumerable.Empty<GeneralRenderer>();
}
public IEnumerable<(int, Type)> AllInLayer(int layer)
{
foreach (var kvp in _layerIndexToTypeToID[layer])
{
foreach (var id in kvp.Value)
{
yield return (id, kvp.Key);
}
}
}
}
}

View File

@ -3,7 +3,6 @@ using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using Encompass.Exceptions;
using MoonTools.FastCollections;
namespace Encompass
{
@ -24,6 +23,7 @@ namespace Encompass
internal readonly HashSet<Type> WriteImmediateTypes = new HashSet<Type>();
internal readonly HashSet<Type> QueryWithTypes = new HashSet<Type>();
internal readonly HashSet<Type> QueryWithoutTypes = new HashSet<Type>();
internal readonly HashSet<Type> AddTypes = new HashSet<Type>();
internal readonly Dictionary<Type, int> WritePriorities = new Dictionary<Type, int>();
internal readonly int DefaultWritePriority = 0;
@ -59,6 +59,12 @@ namespace Encompass
{
_id = Guid.NewGuid();
var addsAttribute = GetType().GetCustomAttribute<Adds>(false);
if (addsAttribute != null)
{
AddTypes = addsAttribute.addTypes;
}
var sendsAttribute = GetType().GetCustomAttribute<Sends>(false);
if (sendsAttribute != null)
{
@ -108,11 +114,21 @@ namespace Encompass
QueryWithTypes = queryWithAttribute.QueryWithTypes;
}
foreach (var queryType in QueryWithTypes)
{
ReadTypes.Add(queryType);
}
var queryWithoutAttribute = GetType().GetCustomAttribute<QueryWithout>(false);
if (queryWithoutAttribute != null)
{
QueryWithoutTypes = queryWithoutAttribute.QueryWithoutTypes;
}
foreach (var queryType in QueryWithoutTypes)
{
ReadTypes.Add(queryType);
}
}
public override bool Equals(object obj)
@ -160,7 +176,7 @@ namespace Encompass
_trackingManager = trackingManager;
}
internal void CheckMessageRead<TMessage>() where TMessage : struct, IMessage
internal void CheckMessageRead<TMessage>() where TMessage : struct
{
if (!ReceiveTypes.Contains(typeof(TMessage)))
{
@ -213,7 +229,7 @@ namespace Encompass
/// <summary>
/// Returns all Entities containing the specified Component type.
/// </summary>
protected Span<Entity> ReadEntities<TComponent>() where TComponent : struct, IComponent
protected ReadOnlySpan<Entity> ReadEntities<TComponent>() where TComponent : struct
{
var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent));
var existingRead = ReadTypes.Contains(typeof(TComponent));
@ -238,7 +254,7 @@ namespace Encompass
/// <summary>
/// Returns an Entity containing the specified Component type.
/// </summary>
protected ref readonly Entity ReadEntity<TComponent>() where TComponent : struct, IComponent
protected ref readonly Entity ReadEntity<TComponent>() where TComponent : struct
{
var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent));
var existingRead = ReadTypes.Contains(typeof(TComponent));
@ -263,7 +279,7 @@ namespace Encompass
/// <summary>
/// Returns all of the Components with the specified Component Type.
/// </summary>
protected Span<TComponent> ReadComponents<TComponent>() where TComponent : struct, IComponent
protected ReadOnlySpan<TComponent> ReadComponents<TComponent>() where TComponent : struct
{
var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent));
var existingRead = ReadTypes.Contains(typeof(TComponent));
@ -288,7 +304,7 @@ namespace Encompass
/// <summary>
/// Returns a Component with the specified Component Type. If multiples exist, an arbitrary Component is returned.
/// </summary>
protected ref readonly TComponent ReadComponent<TComponent>() where TComponent : struct, IComponent
protected ref readonly TComponent ReadComponent<TComponent>() where TComponent : struct
{
var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent));
var existingRead = ReadTypes.Contains(typeof(TComponent));
@ -313,7 +329,7 @@ namespace Encompass
/// <summary>
/// Returns true if any Component with the specified Component Type exists.
/// </summary>
protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent
protected bool SomeComponent<TComponent>() where TComponent : struct
{
var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent));
var existingRead = ReadTypes.Contains(typeof(TComponent));
@ -335,7 +351,7 @@ namespace Encompass
}
}
private ref TComponent GetComponentHelper<TComponent>(int entityID) where TComponent : struct, IComponent
private ref TComponent GetComponentHelper<TComponent>(int entityID) where TComponent : struct
{
var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent));
var existingRead = ReadTypes.Contains(typeof(TComponent));
@ -366,7 +382,7 @@ namespace Encompass
/// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that it reads the given Component Type.
/// </exception>
protected ref readonly TComponent GetComponent<TComponent>(in Entity entity) where TComponent : struct, IComponent
protected ref readonly TComponent GetComponent<TComponent>(in Entity entity) where TComponent : struct
{
return ref GetComponentHelper<TComponent>(entity.ID);
}
@ -377,7 +393,7 @@ namespace Encompass
/// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that is Reads the given Component Type.
/// </exception>
protected bool HasComponent<TComponent>(in Entity entity) where TComponent : struct, IComponent
protected bool HasComponent<TComponent>(in Entity entity) where TComponent : struct
{
var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent));
var existingRead = ReadTypes.Contains(typeof(TComponent));
@ -435,7 +451,7 @@ namespace Encompass
/// <exception cref="Encompass.Exceptions.IllegalWriteException">
/// Thrown when the Engine does not declare that it Writes the given Component Type.
/// </exception>
protected void SetComponent<TComponent>(in Entity entity, in TComponent component) where TComponent : struct, IComponent
protected void SetComponent<TComponent>(in Entity entity, in TComponent component) where TComponent : struct
{
var priority = WritePriorities.ContainsKey(typeof(TComponent)) ? WritePriorities[typeof(TComponent)] : DefaultWritePriority;
@ -462,11 +478,6 @@ namespace Encompass
{
_trackingManager.RegisterAddition(entity.ID, typeof(TComponent));
}
if (written && component is IDrawableComponent drawableComponent)
{
_componentManager.RegisterDrawableComponent<TComponent>(entity.ID, drawableComponent.Layer);
}
}
/// <summary>
@ -475,8 +486,13 @@ namespace Encompass
/// <exception cref="Encompass.Exceptions.IllegalWriteException">
/// Thrown when the Engine does not declare that it Writes the given Component Type.
/// </exception>
protected void AddComponent<TComponent>(in Entity entity, in TComponent component) where TComponent : struct, IComponent
protected void AddComponent<TComponent>(in Entity entity, in TComponent component) where TComponent : struct
{
if (!AddTypes.Contains(typeof(TComponent)))
{
throw new IllegalWriteException("Engine {0} tried to add undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
}
if (!EntityCreatedThisFrame(entity.ID))
{
throw new IllegalWriteException("AddComponent used on Entity that was not created in this context. Use SetComponent instead.");
@ -493,11 +509,6 @@ namespace Encompass
}
_trackingManager.RegisterAddition(entity.ID, typeof(TComponent));
if (component is IDrawableComponent drawableComponent)
{
_componentManager.RegisterDrawableComponent<TComponent>(entity.ID, drawableComponent.Layer);
}
}
/// <summary>
@ -506,7 +517,7 @@ namespace Encompass
/// <exception cref="Encompass.Exceptions.IllegalSendException">
/// Thrown when the Engine does not declare that it Sends the Message Type.
/// </exception>
protected void SendMessage<TMessage>(in TMessage message) where TMessage : struct, IMessage
protected void SendMessage<TMessage>(in TMessage message) where TMessage : struct
{
if (!SendTypes.Contains(typeof(TMessage)))
{
@ -520,7 +531,7 @@ namespace Encompass
/// Sends a message after the specified number of seconds, respecting time dilation.
/// </summary>
/// <param name="time">The time in seconds that will elapse before the message is sent.</param>
protected void SendMessage<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
protected void SendMessage<TMessage>(in TMessage message, double time) where TMessage : struct
{
_messageManager.AddMessage(message, time);
}
@ -529,7 +540,7 @@ namespace Encompass
/// Sends a message after the specified number of seconds, ignoring time dilation.
/// </summary>
/// <param name="time">The time in seconds that will elapse before the message is sent.</param>
protected void SendMessageIgnoringTimeDilation<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
protected void SendMessageIgnoringTimeDilation<TMessage>(in TMessage message, double time) where TMessage : struct
{
_messageManager.AddMessageIgnoringTimeDilation(message, time);
}
@ -540,7 +551,7 @@ namespace Encompass
/// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that it Receives the specified Message Type.
/// </exception>
protected Span<TMessage> ReadMessages<TMessage>() where TMessage : struct, IMessage
protected ReadOnlySpan<TMessage> ReadMessages<TMessage>() where TMessage : struct
{
CheckMessageRead<TMessage>();
return _messageManager.GetMessagesByType<TMessage>();
@ -552,7 +563,7 @@ namespace Encompass
/// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that it Receives the specified Message Type.
/// </exception>
protected ref readonly TMessage ReadMessage<TMessage>() where TMessage : struct, IMessage
protected ref readonly TMessage ReadMessage<TMessage>() where TMessage : struct
{
CheckMessageRead<TMessage>();
return ref _messageManager.First<TMessage>();
@ -564,7 +575,7 @@ namespace Encompass
/// <exception cref="Encompass.Exceptions.IllegalReadException">
/// Thrown when the Engine does not declare that it Receives the specified Message Type.
/// </exception>
protected bool SomeMessage<TMessage>() where TMessage : struct, IMessage
protected bool SomeMessage<TMessage>() where TMessage : struct
{
CheckMessageRead<TMessage>();
return _messageManager.Any<TMessage>();
@ -583,7 +594,7 @@ namespace Encompass
/// Destroys an arbitrary Entity containing a Component of the specified Type.
/// Entity destruction takes place after all the Engines have been processed by World Update.
/// </summary>
protected void DestroyWith<TComponent>() where TComponent : struct, IComponent
protected void DestroyWith<TComponent>() where TComponent : struct
{
Destroy(ReadEntity<TComponent>());
}
@ -592,7 +603,7 @@ namespace Encompass
/// Destroys all Entities containing a Component of the specified Type.
/// Entity destruction takes place after all the Engines have been processed by World Update.
/// </summary>
protected void DestroyAllWith<TComponent>() where TComponent : struct, IComponent
protected void DestroyAllWith<TComponent>() where TComponent : struct
{
foreach (var entity in ReadEntities<TComponent>())
{
@ -605,7 +616,7 @@ namespace Encompass
/// Note that the Engine must Read the Component type that is being removed.
/// If a Component with the specified type does not exist on the Entity, returns false and does not mutate the Entity.
/// </summary>
protected void RemoveComponent<TComponent>(in Entity entity) where TComponent : struct, IComponent
protected void RemoveComponent<TComponent>(in Entity entity) where TComponent : struct
{
var priority = WritePriorities.ContainsKey(typeof(TComponent)) ? WritePriorities[typeof(TComponent)] : DefaultWritePriority;
@ -698,7 +709,7 @@ namespace Encompass
/// <typeparam name="TMessage">The Message subtype.</typeparam>
/// <param name="entity">The entity that all messages in the IEnumerable refer to.</param>
/// <returns></returns>
protected IEnumerable<TMessage> ReadMessagesWithEntity<TMessage>(in Entity entity) where TMessage : struct, IMessage, IHasEntity
protected IEnumerable<TMessage> ReadMessagesWithEntity<TMessage>(in Entity entity) where TMessage : struct, IHasEntity
{
CheckMessageRead<TMessage>();
return _messageManager.WithEntity<TMessage>(entity.ID);
@ -708,7 +719,7 @@ namespace Encompass
/// Efficiently reads a single Message of a given type that references a given Entity.
/// It is recommended to use this method in conjunction with SomeMessageWithEntity to prevent errors.
/// </summary>
protected ref readonly TMessage ReadMessageWithEntity<TMessage>(in Entity entity) where TMessage : struct, IMessage, IHasEntity
protected ref readonly TMessage ReadMessageWithEntity<TMessage>(in Entity entity) where TMessage : struct, IHasEntity
{
CheckMessageRead<TMessage>();
return ref _messageManager.WithEntitySingular<TMessage>(entity.ID);
@ -717,7 +728,7 @@ namespace Encompass
/// <summary>
/// Efficiently checks if any Message of a given type referencing a given Entity exists.
/// </summary>
protected bool SomeMessageWithEntity<TMessage>(in Entity entity) where TMessage : struct, IMessage, IHasEntity
protected bool SomeMessageWithEntity<TMessage>(in Entity entity) where TMessage : struct, IHasEntity
{
CheckMessageRead<TMessage>();
return _messageManager.SomeWithEntity<TMessage>(entity.ID);

View File

@ -6,7 +6,7 @@ namespace Encompass
/// A Spawner is a special type of Engine that runs a Spawn method in response to each Message it receives.
/// Spawners are useful for organizing the building of new Entities in your game.
/// </summary>
public abstract class Spawner<TMessage> : Engine where TMessage : struct, IMessage
public abstract class Spawner<TMessage> : Engine where TMessage : struct
{
protected Spawner() : base()
{
@ -21,12 +21,12 @@ namespace Encompass
public override void Update(double dt)
{
foreach (var message in ReadMessages<TMessage>())
foreach (ref readonly var message in ReadMessages<TMessage>())
{
Spawn(message);
}
}
protected abstract void Spawn(TMessage message);
protected abstract void Spawn(in TMessage message);
}
}

View File

@ -1,6 +1,4 @@
using MoonTools.FastCollections;
namespace Encompass
namespace Encompass
{
internal struct EntitySetQuery
{

View File

@ -1,25 +1,12 @@
using System;
using System.Runtime.Serialization;
namespace Encompass.Exceptions
{
[Serializable]
internal class NoComponentOfTypeException : Exception
public class NoComponentOfTypeException : Exception
{
public NoComponentOfTypeException()
{
}
public NoComponentOfTypeException(string message) : base(message)
{
}
public NoComponentOfTypeException(string message, Exception innerException) : base(message, innerException)
{
}
protected NoComponentOfTypeException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
public NoComponentOfTypeException(
string format,
params object[] args
) : base(string.Format(format, args)) { }
}
}

View File

@ -2,9 +2,9 @@ using System;
namespace Encompass.Exceptions
{
public class IllegalSendTypeException : Exception
public class NoMessageOfTypeException : Exception
{
public IllegalSendTypeException(
public NoMessageOfTypeException(
string format,
params object[] args
) : base(string.Format(format, args)) { }

View File

@ -0,0 +1,390 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Encompass
{
internal class DirectedGraph<TNode> where TNode : IEquatable<TNode>
{
protected HashSet<TNode> nodes = new HashSet<TNode>();
protected Dictionary<TNode, HashSet<TNode>> neighbors = new Dictionary<TNode, HashSet<TNode>>();
protected HashSet<(TNode, TNode)> edges = new HashSet<(TNode, TNode)>();
public IEnumerable<TNode> Nodes => nodes;
public IEnumerable<(TNode, TNode)> Edges => edges;
public void AddNode(TNode node)
{
if (!Exists(node))
{
nodes.Add(node);
neighbors.Add(node, new HashSet<TNode>());
}
}
public void AddNodes(params TNode[] nodes)
{
foreach (var node in nodes)
{
AddNode(node);
}
}
public void RemoveNode(TNode node)
{
CheckNodes(node);
var edgesToRemove = new List<(TNode, TNode)>();
foreach (var entry in neighbors)
{
if (entry.Value.Contains(node))
{
edgesToRemove.Add((entry.Key, node));
}
}
foreach (var edge in edgesToRemove)
{
RemoveEdge(edge.Item1, edge.Item2);
}
nodes.Remove(node);
neighbors.Remove(node);
}
public void RemoveEdge(TNode v, TNode u)
{
CheckEdge(v, u);
neighbors[v].Remove(u);
edges.Remove((v, u));
}
public void AddEdge(TNode v, TNode u)
{
CheckNodes(v, u);
if (Exists(v, u)) { throw new ArgumentException($"Edge between {v} and {u} already exists in the graph"); }
if (v.Equals(u)) { throw new ArgumentException("Self-edges are not allowed in a simple graph. Use a multigraph instead"); }
neighbors[v].Add(u);
edges.Add((v, u));
}
public bool Exists(TNode node)
{
return nodes.Contains(node);
}
public bool Exists(TNode v, TNode u)
{
CheckNodes(v, u);
return edges.Contains((v, u));
}
protected void CheckNodes(params TNode[] givenNodes)
{
foreach (var node in givenNodes)
{
if (!Exists(node))
{
throw new System.ArgumentException($"Vertex {node} does not exist in the graph");
}
}
}
protected void CheckEdge(TNode v, TNode u)
{
CheckNodes(v, u);
if (!Exists(v, u)) { throw new ArgumentException($"Edge between vertex {v} and vertex {u} does not exist in the graph"); }
}
public IEnumerable<TNode> Neighbors(TNode node)
{
CheckNodes(node);
return neighbors[node];
}
public DirectedGraph<TNode> Clone()
{
var clone = new DirectedGraph<TNode>();
clone.AddNodes(Nodes.ToArray());
foreach (var v in Nodes)
{
foreach (var n in Neighbors(v))
{
clone.AddEdge(v, n);
}
}
return clone;
}
public DirectedGraph<TNode> SubGraph(params TNode[] subVertices)
{
var subGraph = new DirectedGraph<TNode>();
subGraph.AddNodes(subVertices.ToArray());
foreach (var n in Nodes)
{
if (Nodes.Contains(n))
{
var neighbors = Neighbors(n);
foreach (var u in neighbors)
{
if (subVertices.Contains(u))
{
subGraph.AddEdge(n, u);
}
}
}
}
return subGraph;
}
private IEnumerable<TNode> PostorderNodeDFSHelper(HashSet<TNode> discovered, TNode v)
{
discovered.Add(v);
foreach (var neighbor in Neighbors(v))
{
if (!discovered.Contains(neighbor))
{
foreach (var node in PostorderNodeDFSHelper(discovered, neighbor))
{
yield return node;
}
}
}
yield return v;
}
protected IEnumerable<TNode> PostorderNodeDFS()
{
var dfsDiscovered = new HashSet<TNode>();
foreach (var node in Nodes)
{
if (!dfsDiscovered.Contains(node))
{
foreach (var thing in PostorderNodeDFSHelper(dfsDiscovered, node))
{
yield return thing;
}
}
}
}
public IEnumerable<TNode> TopologicalSort()
{
return PostorderNodeDFS().Reverse();
}
public bool Cyclic()
{
return StronglyConnectedComponents().Any((scc) => scc.Count() > 1);
}
public IEnumerable<IEnumerable<TNode>> SimpleCycles()
{
void unblock(TNode thisnode, HashSet<TNode> blocked, Dictionary<TNode, HashSet<TNode>> B) //refactor to remove closure
{
var stack = new Stack<TNode>();
stack.Push(thisnode);
while (stack.Count > 0)
{
var node = stack.Pop();
if (blocked.Contains(thisnode))
{
blocked.Remove(thisnode);
if (B.ContainsKey(node))
{
foreach (var n in B[node])
{
if (!stack.Contains(n))
{
stack.Push(n);
}
}
B[node].Clear();
}
}
}
}
List<List<TNode>> result = new List<List<TNode>>();
var subGraph = Clone();
var sccs = new Stack<IEnumerable<TNode>>();
foreach (var scc in StronglyConnectedComponents())
{
sccs.Push(scc);
}
while (sccs.Count > 0)
{
var scc = new Stack<TNode>(sccs.Pop());
var startNode = scc.Pop();
var path = new Stack<TNode>();
path.Push(startNode);
var blocked = new HashSet<TNode>
{
startNode
};
var closed = new HashSet<TNode>();
var B = new Dictionary<TNode, HashSet<TNode>>();
var stack = new Stack<(TNode, Stack<TNode>)>();
stack.Push((startNode, new Stack<TNode>(subGraph.Neighbors(startNode))));
while (stack.Count > 0)
{
var entry = stack.Peek();
var thisnode = entry.Item1;
var neighbors = entry.Item2;
if (neighbors.Count > 0)
{
var nextNode = neighbors.Pop();
if (nextNode.Equals(startNode))
{
var resultPath = new List<TNode>();
foreach (var v in path)
{
resultPath.Add(v);
}
result.Add(resultPath);
foreach (var v in path)
{
closed.Add(v);
}
}
else if (!blocked.Contains(nextNode))
{
path.Push(nextNode);
stack.Push((nextNode, new Stack<TNode>(subGraph.Neighbors(nextNode))));
closed.Remove(nextNode);
blocked.Add(nextNode);
continue;
}
}
if (neighbors.Count == 0)
{
if (closed.Contains(thisnode))
{
unblock(thisnode, blocked, B);
}
else
{
foreach (var neighbor in subGraph.Neighbors(thisnode))
{
if (!B.ContainsKey(neighbor))
{
B[neighbor] = new HashSet<TNode>();
}
B[neighbor].Add(thisnode);
}
}
stack.Pop();
path.Pop();
}
}
subGraph.RemoveNode(startNode);
var H = subGraph.SubGraph(scc.ToArray());
var HSccs = H.StronglyConnectedComponents();
foreach (var HScc in HSccs)
{
sccs.Push(HScc);
}
}
return result.Distinct(new SimpleCycleComparer<TNode>());
}
protected IEnumerable<IEnumerable<TNode>> StronglyConnectedComponents()
{
var preorder = new Dictionary<TNode, uint>();
var lowlink = new Dictionary<TNode, uint>();
var sccFound = new Dictionary<TNode, bool>();
var sccQueue = new Stack<TNode>();
uint preorderCounter = 0;
foreach (var source in Nodes)
{
if (!sccFound.ContainsKey(source))
{
var queue = new Stack<TNode>();
queue.Push(source);
while (queue.Count > 0)
{
var v = queue.Peek();
if (!preorder.ContainsKey(v))
{
preorderCounter++;
preorder[v] = preorderCounter;
}
var done = true;
var vNeighbors = Neighbors(v);
foreach (var w in vNeighbors)
{
if (!preorder.ContainsKey(w))
{
queue.Push(w);
done = false;
break;
}
}
if (done)
{
lowlink[v] = preorder[v];
foreach (var w in vNeighbors)
{
if (!sccFound.ContainsKey(w))
{
if (preorder[w] > preorder[v])
{
lowlink[v] = Math.Min(lowlink[v], lowlink[w]);
}
else
{
lowlink[v] = Math.Min(lowlink[v], preorder[w]);
}
}
}
queue.Pop();
if (lowlink[v] == preorder[v])
{
sccFound[v] = true;
var scc = new List<TNode>() { v };
while (sccQueue.Count > 0 && preorder[sccQueue.Peek()] > preorder[v])
{
var k = sccQueue.Pop();
sccFound[k] = true;
scc.Add(k);
}
yield return scc;
}
else
{
sccQueue.Push(v);
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
using System.Linq;
namespace Encompass
{
internal class SimpleCycleComparer<TNode> : IEqualityComparer<IEnumerable<TNode>>
{
public bool Equals(IEnumerable<TNode> x, IEnumerable<TNode> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(IEnumerable<TNode> obj)
{
return obj.Aggregate(0, (current, next) => current.GetHashCode() ^ next.GetHashCode());
}
}
}

View File

@ -1,7 +0,0 @@
namespace Encompass
{
/// <summary>
/// Structs that implement IMessage are considered to be Messages.
/// </summary>
public interface IMessage { }
}

View File

@ -1,4 +0,0 @@
namespace Encompass
{
public interface IComponent { }
}

View File

@ -1,7 +0,0 @@
namespace Encompass
{
public interface IDrawableComponent
{
int Layer { get; }
}
}

View File

@ -13,17 +13,17 @@ namespace Encompass
_timeManager = timeManager;
}
internal void AddMessage<TMessage>(in TMessage message) where TMessage : struct, IMessage
internal void AddMessage<TMessage>(in TMessage message) where TMessage : struct
{
_messageStore.AddMessage(message);
}
internal void AddMessage<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
internal void AddMessage<TMessage>(in TMessage message, double time) where TMessage : struct
{
_messageStore.AddMessage(message, time);
}
internal void AddMessageIgnoringTimeDilation<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
internal void AddMessageIgnoringTimeDilation<TMessage>(in TMessage message, double time) where TMessage : struct
{
_messageStore.AddMessageIgnoringTimeDilation(message, time);
}
@ -38,32 +38,32 @@ namespace Encompass
_messageStore.ProcessDelayedMessages(dt * _timeManager.TimeDilationFactor, dt);
}
internal Span<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage
internal ReadOnlySpan<TMessage> GetMessagesByType<TMessage>() where TMessage : struct
{
return _messageStore.All<TMessage>();
}
internal bool Any<TMessage>() where TMessage : struct, IMessage
internal bool Any<TMessage>() where TMessage : struct
{
return _messageStore.Any<TMessage>();
}
internal ref readonly TMessage First<TMessage>() where TMessage : struct, IMessage
internal ref readonly TMessage First<TMessage>() where TMessage : struct
{
return ref _messageStore.First<TMessage>();
}
internal IEnumerable<TMessage> WithEntity<TMessage>(int entityID) where TMessage : struct, IMessage, IHasEntity
internal IEnumerable<TMessage> WithEntity<TMessage>(int entityID) where TMessage : struct, IHasEntity
{
return _messageStore.WithEntity<TMessage>(entityID);
}
internal ref readonly TMessage WithEntitySingular<TMessage>(int entityID) where TMessage : struct, IMessage, IHasEntity
internal ref readonly TMessage WithEntitySingular<TMessage>(int entityID) where TMessage : struct, IHasEntity
{
return ref _messageStore.FirstWithEntity<TMessage>(entityID);
}
internal bool SomeWithEntity<TMessage>(int entityID) where TMessage : struct, IMessage, IHasEntity
internal bool SomeWithEntity<TMessage>(int entityID) where TMessage : struct, IHasEntity
{
return _messageStore.SomeWithEntity<TMessage>(entityID);
}

View File

@ -1,51 +1,27 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
namespace Encompass
{
internal class RenderManager
{
private readonly EntityManager _entityManager;
private readonly DrawLayerManager _drawLayerManager;
private readonly List<Renderer> renderers = new List<Renderer>();
private readonly Dictionary<Type, Action<Entity>> _drawComponentTypeToOrderedRenderer = new Dictionary<Type, Action<Entity>>(256);
public RenderManager(EntityManager entityManager, DrawLayerManager drawLayerManager)
public RenderManager(EntityManager entityManager)
{
_entityManager = entityManager;
_drawLayerManager = drawLayerManager;
}
public void RegisterOrderedRenderer<TComponent>(Action<Entity> renderAction) where TComponent : struct
public void AddRenderer(Renderer renderer)
{
_drawComponentTypeToOrderedRenderer.Add(typeof(TComponent), renderAction);
_drawLayerManager.RegisterOrderedDrawable<TComponent>();
renderers.Add(renderer);
}
public void RegisterGeneralRendererWithLayer(GeneralRenderer renderer, int layer)
public void Draw(double dt, double alpha)
{
_drawLayerManager.RegisterGeneralRendererWithLayer(renderer, layer);
}
public void Draw()
foreach (var renderer in renderers)
{
foreach (var layer in _drawLayerManager.LayerOrder)
{
var generalRendererSet = _drawLayerManager.GeneralRenderersByLayer(layer);
foreach (var (entityID, componentType) in _drawLayerManager.AllInLayer(layer))
{
if (_drawComponentTypeToOrderedRenderer.ContainsKey(componentType))
{
var internalRenderAction = _drawComponentTypeToOrderedRenderer[componentType];
internalRenderAction(_entityManager.GetEntity(entityID));
}
}
foreach (var generalRenderer in generalRendererSet)
{
generalRenderer.Render();
}
renderer.Render(dt, alpha);
}
}
}

View File

@ -18,37 +18,49 @@ namespace Encompass
_componentManager = componentManager;
}
protected Span<Entity> ReadEntities<TComponent>() where TComponent : struct, IComponent
public abstract void Render(double dt, double alpha);
protected ReadOnlySpan<Entity> ReadEntities<TComponent>() where TComponent : struct
{
return _componentManager.GetExistingEntities<TComponent>();
}
protected ref readonly Entity ReadEntity<TComponent>() where TComponent : struct, IComponent
protected IEnumerable<Entity> ReadEntitiesAsEnumerable<TComponent>() where TComponent : struct
{
return _componentManager.GetExistingEntitiesAsEnumerable<TComponent>();
}
protected ref readonly Entity ReadEntity<TComponent>() where TComponent : struct
{
return ref _componentManager.ExistingSingularEntity<TComponent>();
}
protected Span<TComponent> ReadComponents<TComponent>() where TComponent : struct, IComponent
protected ReadOnlySpan<TComponent> ReadComponents<TComponent>() where TComponent : struct
{
return _componentManager.GetComponentsByType<TComponent>();
}
protected ref readonly TComponent ReadComponent<TComponent>() where TComponent : struct, IComponent
protected IEnumerable<TComponent> ReadComponentsAsEnumerable<TComponent>() where TComponent : struct
{
return _componentManager.GetComponentsByTypeEnumerable<TComponent>();
}
protected ref readonly TComponent ReadComponent<TComponent>() where TComponent : struct
{
return ref _componentManager.ExistingSingular<TComponent>();
}
protected ref readonly TComponent GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
protected ref readonly TComponent GetComponent<TComponent>(Entity entity) where TComponent : struct
{
return ref _componentManager.GetComponentByEntityAndType<TComponent>(entity.ID);
}
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct
{
return _componentManager.EntityHasComponentOfType<TComponent>(entity.ID);
}
protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent
protected bool SomeComponent<TComponent>() where TComponent : struct
{
return _componentManager.SomeExistingComponent<TComponent>();
}

View File

@ -1,11 +0,0 @@
namespace Encompass
{
/// <summary>
/// GeneralRenderer is a Renderer which generically reads the game state in order to draw elements to the screen.
/// GeneralRenderers have a layer specified when they are added to the World.
/// </summary>
public abstract class GeneralRenderer : Renderer
{
public abstract void Render();
}
}

View File

@ -1,18 +0,0 @@
using System;
namespace Encompass
{
/// <summary>
/// OrdereredRenderer provides a structure for the common pattern of wishing to draw a specific DrawComponent at a specific layer.
/// </summary>
public abstract class OrderedRenderer<TComponent> : Renderer where TComponent : struct, IComponent, IDrawableComponent
{
public abstract void Render(Entity entity, in TComponent drawComponent);
internal void InternalRender(Entity entity)
{
ref readonly var component = ref GetComponent<TComponent>(entity);
Render(entity, component);
}
}
}

View File

@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace Encompass
{
@ -16,6 +14,7 @@ namespace Encompass
{
_componentTypes = componentTypes;
_messageTypes = messageTypes;
AddTypes.UnionWith(componentTypes);
ReadTypes.UnionWith(componentTypes);
WriteTypes.UnionWith(componentTypes);
SendTypes.UnionWith(messageTypes);
@ -28,7 +27,8 @@ namespace Encompass
foreach (var type in _componentTypes)
{
var instanceParam = new object[] { Entity, Activator.CreateInstance(type) };
var instance = Activator.CreateInstance(type);
var instanceParam = new object[] { Entity, instance };
var setComponentMethod = typeof(Engine).GetMethod("SetComponent", BindingFlags.NonPublic | BindingFlags.Instance);
var genericSetComponentMethod = setComponentMethod.MakeGenericMethod(type);
genericSetComponentMethod.Invoke(this, instanceParam);
@ -55,7 +55,7 @@ namespace Encompass
// we can't reflect invoke on byref returns or Span returns right now... so we have non-return wrapper methods
protected void CallAllComponentMethods<TComponent>() where TComponent : struct, IComponent
protected void CallAllComponentMethods<TComponent>() where TComponent : struct
{
ReadComponent<TComponent>();
ReadComponents<TComponent>();
@ -70,7 +70,7 @@ namespace Encompass
AddComponent<TComponent>(Entity, default);
}
protected void CallAllMessageMethods<TMessage>() where TMessage : struct, IMessage
protected void CallAllMessageMethods<TMessage>() where TMessage : struct
{
SendMessageIgnoringTimeDilation<TMessage>(default, 0.1);
SendMessage<TMessage>(default);
@ -80,7 +80,7 @@ namespace Encompass
SomeMessage<TMessage>();
}
protected void CallAllEntityMessageMethods<TMessage>() where TMessage : struct, IMessage, IHasEntity
protected void CallAllEntityMessageMethods<TMessage>() where TMessage : struct, IHasEntity
{
ReadMessagesWithEntity<TMessage>(Entity);
ReadMessageWithEntity<TMessage>(Entity);

View File

@ -20,7 +20,7 @@ namespace Encompass
}
// can't reflect invoke on Span returns...
public void Render()
public override void Render(double dt, double alpha)
{
foreach (var type in _componentTypes)
{
@ -28,7 +28,7 @@ namespace Encompass
}
}
protected void CallAllComponentMethods<TComponent>() where TComponent : struct, IComponent
protected void CallAllComponentMethods<TComponent>() where TComponent : struct
{
ReadEntity<TComponent>();
ReadEntities<TComponent>();

View File

@ -69,9 +69,9 @@ namespace Encompass
/// <summary>
/// Causes the Renderers to draw.
/// </summary>
public void Draw()
public void Draw(double dt, double alpha)
{
_renderManager.Draw();
_renderManager.Draw(dt, alpha);
}
}
}

View File

@ -3,8 +3,6 @@ using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using Encompass.Exceptions;
using MoonTools.Core.Graph;
using MoonTools.Core.Graph.Extensions;
namespace Encompass
{
@ -20,7 +18,7 @@ namespace Encompass
{
private readonly int _entityCapacity;
private readonly List<Engine> _engines = new List<Engine>();
private readonly DirectedGraph<Engine, Unit> _engineGraph = GraphBuilder.DirectedGraph<Engine>();
private readonly DirectedGraph<Engine> _engineGraph = new DirectedGraph<Engine>();
private readonly ComponentStore _startingExistingComponentStore;
private readonly ComponentStore _startingUpToDateComponentStore;
@ -28,7 +26,6 @@ namespace Encompass
private readonly EntityManager _entityManager;
private readonly MessageManager _messageManager;
private readonly TimeManager _timeManager;
private readonly DrawLayerManager _drawLayerManager;
private readonly RenderManager _renderManager;
private readonly TrackingManager _trackingManager;
@ -38,18 +35,15 @@ namespace Encompass
private readonly HashSet<Type> _messageTypes = new HashSet<Type>();
private readonly Dictionary<Type, int> _typeToIndex = new Dictionary<Type, int>();
private bool _rendererRegistered = false;
public WorldBuilder(int entityCapacity = 32768)
{
_entityCapacity = entityCapacity;
_drawLayerManager = new DrawLayerManager();
_timeManager = new TimeManager();
_trackingManager = new TrackingManager();
_componentManager = new ComponentManager(_drawLayerManager, _typeToIndex);
_componentManager = new ComponentManager(_typeToIndex);
_messageManager = new MessageManager(_timeManager);
_entityManager = new EntityManager(_componentManager, entityCapacity);
_renderManager = new RenderManager(_entityManager, _drawLayerManager);
_renderManager = new RenderManager(_entityManager);
_startingExistingComponentStore = new ComponentStore(_typeToIndex);
_startingUpToDateComponentStore = new ComponentStore(_typeToIndex);
@ -66,7 +60,7 @@ namespace Encompass
/// <summary>
/// Specifies that the given Message should be sent immediately on the first World Update.
/// </summary>
public void SendMessage<TMessage>(in TMessage message) where TMessage : struct, IMessage
public void SendMessage<TMessage>(in TMessage message) where TMessage : struct
{
_messageManager.AddMessage(message);
}
@ -74,7 +68,7 @@ namespace Encompass
/// <summary>
/// Specifies that the given Message should be sent after the specified number of seconds after the first World Update.
/// </summary>
public void SendMessage<TMessage>(in TMessage message, double time) where TMessage : struct, IMessage
public void SendMessage<TMessage>(in TMessage message, double time) where TMessage : struct
{
_messageManager.AddMessage<TMessage>(message, time);
}
@ -87,12 +81,13 @@ namespace Encompass
RegisterComponentType<TComponent>();
_startingExistingComponentStore.Set(entity.ID, component);
_startingUpToDateComponentStore.Set(entity.ID, component);
if (component is IDrawableComponent drawableComponent)
{
_componentManager.RegisterDrawableComponent<TComponent>(entity.ID, drawableComponent.Layer);
_drawLayerManager.RegisterOrderedDrawable<TComponent>();
}
internal void RegisterComponentTypeNonGeneric(Type type)
{
var method = GetType().GetMethod("RegisterComponentType", BindingFlags.NonPublic | BindingFlags.Instance);
var generic = method.MakeGenericMethod(type);
generic.Invoke(this, null);
}
internal void RegisterComponentType<TComponent>() where TComponent : struct
@ -130,16 +125,29 @@ namespace Encompass
var messageReceiveTypes = engine.ReceiveTypes;
var messageSendTypes = engine.SendTypes;
RegisterMessageTypes(engine.ReceiveTypes.Union(engine.SendTypes));
RegisterMessageTypes(engine.ReceiveTypes);
RegisterMessageTypes(engine.SendTypes);
foreach (var writeImmediateType in engine.WriteImmediateTypes.Intersect(engine.ReadImmediateTypes))
foreach (var writeImmediateType in engine.WriteImmediateTypes)
{
foreach (var readImmediateType in engine.ReadImmediateTypes)
{
if (readImmediateType == writeImmediateType)
{
throw new EngineSelfCycleException("Engine {0} both writes and reads immediate Component {1}", engine.GetType().Name, writeImmediateType.Name);
}
}
}
foreach (var messageType in messageReceiveTypes.Intersect(messageSendTypes))
foreach (var messageReceiveType in messageReceiveTypes)
{
throw new EngineSelfCycleException("Engine {0} both receives and sends Message {1}", engine.GetType().Name, messageType.Name);
foreach (var messageSendType in messageSendTypes)
{
if (messageReceiveType == messageSendType)
{
throw new EngineSelfCycleException("Engine {0} both receives and sends Message {1}", engine.GetType().Name, messageReceiveType.Name);
}
}
}
if (messageSendTypes.Count > 0 || engine.WriteImmediateTypes.Count > 0)
@ -147,7 +155,27 @@ namespace Encompass
_senders.Add(engine);
}
foreach (var componentType in engine.QueryWithTypes.Union(engine.QueryWithoutTypes))
foreach (var componentType in engine.ReadTypes)
{
RegisterComponentTypeNonGeneric(componentType);
}
foreach (var componentType in engine.AddTypes)
{
RegisterComponentTypeNonGeneric(componentType);
}
foreach (var componentType in engine.WriteTypes)
{
RegisterComponentTypeNonGeneric(componentType);
}
foreach (var componentType in engine.WriteImmediateTypes)
{
RegisterComponentTypeNonGeneric(componentType);
}
foreach (var componentType in engine.QueryWithTypes)
{
_trackingManager.RegisterComponentTypeToEngine(componentType, engine);
if (engine.ReadImmediateTypes.Contains(componentType))
@ -156,7 +184,26 @@ namespace Encompass
}
}
foreach (var receiveType in engine.ReceiveTypes.Union(engine.ReadImmediateTypes))
foreach (var componentType in engine.QueryWithoutTypes)
{
_trackingManager.RegisterComponentTypeToEngine(componentType, engine);
if (engine.ReadImmediateTypes.Contains(componentType))
{
_trackingManager.RegisterImmediateComponentTypeToEngine(componentType, engine);
}
}
foreach (var receiveType in engine.ReceiveTypes)
{
if (!_typeToReaders.ContainsKey(receiveType))
{
_typeToReaders.Add(receiveType, new HashSet<Engine>());
}
_typeToReaders[receiveType].Add(engine);
}
foreach (var receiveType in engine.ReadImmediateTypes)
{
if (!_typeToReaders.ContainsKey(receiveType))
{
@ -170,51 +217,37 @@ namespace Encompass
}
/// <summary>
/// Registers a draw layer. This must be done before any Renderers are registered.
/// Adds the specified Renderer to the World.
/// </summary>
/// <param name="layer">The draw layer to register.</param>
public void RegisterDrawLayer(int layer)
public void AddRenderer(Renderer renderer)
{
if (_rendererRegistered)
{
throw new IllegalDrawLayerException("Cannot register a draw layer after a Renderer has been registered.");
}
_drawLayerManager.RegisterDrawLayer(layer);
}
/// <summary>
/// Adds the specified OrderedRenderer to the World.
/// </summary>
public OrderedRenderer<TComponent> AddOrderedRenderer<TComponent>(OrderedRenderer<TComponent> renderer) where TComponent : struct, IComponent, IDrawableComponent
{
RegisterComponentType<TComponent>();
renderer.AssignEntityManager(_entityManager);
renderer.AssignComponentManager(_componentManager);
_renderManager.RegisterOrderedRenderer<TComponent>(renderer.InternalRender);
_rendererRegistered = true;
return renderer;
}
/// <summary>
/// Adds the specified GeneralRenderer to the World at the specified layer.
/// Higher layer numbers draw on top of lower layer numbers.
/// </summary>
/// <param name="renderer">An instance of a GeneralRenderer.</param>
/// <param name="layer">The layer at which the GeneralRenderer should render. Higher numbers draw over lower numbers.</param>
public TRenderer AddGeneralRenderer<TRenderer>(TRenderer renderer, int layer) where TRenderer : GeneralRenderer
{
renderer.AssignEntityManager(_entityManager);
renderer.AssignComponentManager(_componentManager);
_renderManager.RegisterGeneralRendererWithLayer(renderer, layer);
_rendererRegistered = true;
return renderer;
_renderManager.AddRenderer(renderer);
}
private void BuildEngineGraph()
{
foreach (var senderEngine in _senders)
{
foreach (var messageType in senderEngine.SendTypes.Union(senderEngine.WriteImmediateTypes))
foreach (var messageType in senderEngine.SendTypes)
{
if (_typeToReaders.ContainsKey(messageType))
{
foreach (var readerEngine in _typeToReaders[messageType])
{
if (senderEngine != readerEngine)
{
if (!_engineGraph.Exists(senderEngine, readerEngine))
{
_engineGraph.AddEdge(senderEngine, readerEngine);
}
}
}
}
}
foreach (var messageType in senderEngine.WriteImmediateTypes)
{
if (_typeToReaders.ContainsKey(messageType))
{
@ -394,39 +427,20 @@ namespace Encompass
{
var dummyTimeManager = new TimeManager();
var dummyMessageManager = new MessageManager(dummyTimeManager);
var dummyDrawLayerManager = new DrawLayerManager();
var dummyTrackingManager = new TrackingManager();
var dummyComponentManager = new ComponentManager(dummyDrawLayerManager, _typeToIndex);
var dummyComponentManager = new ComponentManager(_typeToIndex);
var dummyEntityManager = new EntityManager(dummyComponentManager, _entityCapacity);
var dummyRenderManager = new RenderManager(dummyEntityManager, dummyDrawLayerManager);
var dummyRenderManager = new RenderManager(dummyEntityManager);
// doing reflection to grab all component types, because not all writes need to be declared
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var componentType in assembly.GetTypes())
{
if (typeof(IComponent).IsAssignableFrom(componentType) && componentType.IsValueType && !componentType.IsEnum && !componentType.IsPrimitive)
{
var method = typeof(WorldBuilder).GetMethod("RegisterComponentType", BindingFlags.NonPublic | BindingFlags.Instance);
var generic = method.MakeGenericMethod(componentType);
generic.Invoke(this, null);
var prepEngineOrder = new List<Engine>();
foreach (var componentType in _componentTypesToPreload)
{
var dummyRegisterMethod = typeof(ComponentManager).GetMethod("RegisterComponentType", BindingFlags.Public | BindingFlags.Instance);
var dummyGeneric = dummyRegisterMethod.MakeGenericMethod(componentType);
dummyGeneric.Invoke(dummyComponentManager, null);
}
if (componentType.GetInterface("IDrawableComponent") != null)
{
var drawLayerManagerRegisterMethod = typeof(DrawLayerManager).GetMethod("RegisterOrderedDrawable");
var drawLayerManagerRegisterGenericMethod = drawLayerManagerRegisterMethod.MakeGenericMethod(componentType);
drawLayerManagerRegisterGenericMethod.Invoke(dummyDrawLayerManager, null);
}
}
}
var prepEngineOrder = new List<Engine>();
var uberEngine = new UberEngine(_componentTypesToPreload, messageTypes);
uberEngine.AssignEntityManager(dummyEntityManager);
@ -460,7 +474,7 @@ namespace Encompass
dummyComponentManager.WriteComponents();
uberRenderer.SetEntity(uberEngine.Entity);
uberRenderer.Render();
uberRenderer.Render(1, 0);
}
}
}

View File

@ -5,18 +5,19 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RootNamespace>Encompass</RootNamespace>
<PackageId>EncompassECS.Framework</PackageId>
<Version>0.21.1</Version>
<Version>0.23.0</Version>
<Authors>Evan Hemsley</Authors>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<Company>Moonside Games</Company>
<Product>Encompass ECS</Product>
<PackageProjectUrl>https://github.com/encompass-ecs</PackageProjectUrl>
<PackageLicenseUrl />
<Copyright>Evan Hemsley 2019</Copyright>
<Description>Encompass is an engine-agnostic Hyper ECS framework to help you code games, or other kinds of simulations.</Description>
<Copyright>Evan Hemsley 2020</Copyright>
<Description>Encompass is an engine-agnostic MECS framework to help you code games, or other kinds of simulations.</Description>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<AssemblyName>EncompassECS.Framework</AssemblyName>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Platforms>x64;x86</Platforms>
</PropertyGroup>
<ItemGroup>
<None Include="..\LICENSE">
@ -25,8 +26,6 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="MoonTools.Core.Graph" Version="1.0.0" />
<PackageReference Include="MoonTools.FastCollections" Version="1.0.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.7.0" />
<PackageReference Include="Microsoft.Bcl.HashCode" Version="1.1.0" />
</ItemGroup>

View File

@ -8,12 +8,12 @@ namespace Tests
{
public class ComponentTests
{
struct MockComponent : IComponent
struct MockComponent
{
public int myInt;
}
struct EntityMessage : IMessage
struct EntityMessage
{
public Entity entity;
}
@ -33,7 +33,7 @@ namespace Tests
}
}
struct AddComponentTestMessage : IMessage
struct AddComponentTestMessage
{
public Entity entity;
public MockComponent mockComponent;
@ -62,8 +62,6 @@ namespace Tests
var entity = worldBuilder.CreateEntity();
const string MyString = "hello";
MockComponent mockComponent;
mockComponent.myInt = 3;
@ -174,7 +172,7 @@ namespace Tests
Assert.DoesNotThrow(() => world.Update(0.01));
}
struct AddMockComponentMessage : IMessage
struct AddMockComponentMessage
{
public Entity entity;
public MockComponent mockComponent;
@ -271,7 +269,7 @@ namespace Tests
Assert.AreEqual(mockComponent, gottenMockComponent);
}
struct HasComponentTestMessage : IMessage
struct HasComponentTestMessage
{
public Entity entity;
}
@ -369,7 +367,7 @@ namespace Tests
Assert.IsFalse(hasComponentRuntimeTypeResult);
}
struct RemoveComponentTestMessage : IMessage
struct RemoveComponentTestMessage
{
public Entity entity;
}
@ -463,7 +461,7 @@ namespace Tests
hasComponentResult.Should().BeFalse();
}
struct CheckHasMockComponentMessage : IMessage
struct CheckHasMockComponentMessage
{
public Entity entity;
public bool shouldHaveComponent;

View File

@ -10,17 +10,18 @@ using Encompass.Exceptions;
namespace Tests
{
struct MockComponent : IComponent
struct MockComponent
{
public int myInt;
}
public class EngineTest
{
static MockComponent[] resultComponents;
static MockComponent resultComponent;
static MockComponent[] resultComponents = new MockComponent[1];
static MockMessage[] resultMessages;
static MockMessage resultMessage;
static MockMessage[] resultMessages = new MockMessage[1];
[Reads(typeof(MockComponent))]
public class ReadComponentsTestEngine : Engine
@ -149,6 +150,17 @@ namespace Tests
Assert.AreEqual(mockComponent, resultComponent);
}
[Test]
public void ReadComponentThrowsWhenNoneExist()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadComponentTestEngine());
var world = worldBuilder.Build();
Assert.Throws<NoComponentOfTypeException>(() => world.Update(0.01f), "No component of type MockComponent exists");
}
[Test]
public void ReadComponentWhenMultipleComponents()
{
@ -259,7 +271,7 @@ namespace Tests
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to update undeclared Component MockComponent"));
}
struct MockMessage : IMessage
struct MockMessage
{
public string myString;
}
@ -277,7 +289,7 @@ namespace Tests
}
[Receives(typeof(MockMessage))]
public class MessageReadEngine : Engine
public class ReadMessagesEngine : Engine
{
public override void Update(double dt)
{
@ -285,18 +297,38 @@ namespace Tests
}
}
[Receives(typeof(MockMessage))]
public class ReadMessageEngine : Engine
{
public override void Update(double dt)
{
resultMessage = ReadMessage<MockMessage>();
}
}
[Test]
public void EmitAndReadMessage()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new MessageEmitEngine());
worldBuilder.AddEngine(new MessageReadEngine());
worldBuilder.AddEngine(new ReadMessageEngine());
var world = worldBuilder.Build();
world.Update(0.01f);
Assert.AreEqual(resultMessages.First().myString, "howdy");
Assert.AreEqual(resultMessage.myString, "howdy");
}
[Test]
public void ReadMessageThrowsWhenNoneOfTypeExist()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadMessageEngine());
var world = worldBuilder.Build();
Assert.Throws<NoMessageOfTypeException>(() => world.Update(0.01), "No Message of type MockMessage exists");
}
public class UndeclaredMessageEmitEngine : Engine
@ -403,7 +435,7 @@ namespace Tests
Assert.Throws<IllegalReadException>(() => world.Update(0.01f));
}
struct EntityMessage : IMessage, IHasEntity
struct EntityMessage : IHasEntity
{
public EntityMessage(Entity entity, int myInt)
{
@ -618,7 +650,7 @@ namespace Tests
world.Update(0.01f);
}
struct DestroyerComponent : IComponent { }
struct DestroyerComponent { }
[Reads(typeof(DestroyerComponent))]
class DestroyerEngine : Engine
@ -810,7 +842,7 @@ namespace Tests
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationEngine());
worldBuilder.AddEngine(new DelayedMessageEngine());
worldBuilder.AddEngine(new MessageReadEngine());
worldBuilder.AddEngine(new ReadMessagesEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent { });
@ -857,7 +889,7 @@ namespace Tests
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationEngine());
worldBuilder.AddEngine(new DelayedMessageIgnoringTimeDilationEngine());
worldBuilder.AddEngine(new MessageReadEngine());
worldBuilder.AddEngine(new ReadMessagesEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, new MockComponent { });
@ -923,7 +955,7 @@ namespace Tests
resultComponents.Should().BeEmpty();
}
struct DestroyComponentMessage : IMessage { public Entity entity; }
struct DestroyComponentMessage { public Entity entity; }
[Reads(typeof(MockComponent))]
[Writes(typeof(MockComponent))]
@ -950,7 +982,7 @@ namespace Tests
}
[Test]
public void GetEntityByComponentType()
public void ReadEntity()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadEntityByComponentTypeEngine());
@ -964,7 +996,18 @@ namespace Tests
entity.Should().BeEquivalentTo(readEntity);
}
struct MockComponentB : IComponent
[Test]
public void ReadEntityThrowsWhenNoComponentOfTypeExists()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ReadEntityByComponentTypeEngine());
var world = worldBuilder.Build();
Assert.Throws<NoComponentOfTypeException>(() => world.Update(0.01), "No component of type MockComponent exists");
}
struct MockComponentB
{
private int value;
@ -1281,6 +1324,7 @@ namespace Tests
undilatedDeltaTime.Should().Be(0.5);
}
[Adds(typeof(MockComponent))]
class AddComponentWithoutPriorityEngine : Engine
{
public override void Update(double dt)
@ -1337,6 +1381,7 @@ namespace Tests
Assert.Throws<IllegalWriteException>(() => world.Update(0.01));
}
[Adds(typeof(MockComponentB))]
[WritesImmediate(typeof(MockComponentB))]
class AddImmediateComponentEngine : Engine
{
@ -1407,11 +1452,10 @@ namespace Tests
public class QueryTests
{
struct MockComponentB : IComponent { }
struct MockComponentC : IComponent { }
struct MockComponentD : IComponent { }
struct MockComponentB { }
struct MockComponentC { }
struct MockComponentD { }
[Reads(typeof(MockComponent), typeof(MockComponentB))]
[Writes(typeof(MockComponentB))]
[QueryWith(typeof(MockComponent), typeof(MockComponentB))]
class EntityQueryWithComponentsEngine : Engine
@ -1465,7 +1509,6 @@ namespace Tests
queriedEntities.Should().BeEmpty();
}
[Reads(typeof(MockComponent))]
[Writes(typeof(MockComponent))]
[QueryWithout(typeof(MockComponent))]
class EntityQueryWithoutComponentsEngine : Engine
@ -1519,7 +1562,6 @@ namespace Tests
queriedEntities.Should().BeEmpty();
}
[Reads(typeof(MockComponent), typeof(MockComponentB), typeof(MockComponentD))]
[QueryWith(typeof(MockComponent), typeof(MockComponentB))]
[QueryWithout(typeof(MockComponentD))]
class EntityQueryWithandWithoutComponentsEngine : Engine
@ -1745,7 +1787,6 @@ namespace Tests
}
[ReadsImmediate(typeof(MockComponentB))]
[Reads(typeof(MockComponent))]
[QueryWith(typeof(MockComponent), typeof(MockComponentB))]
class EntityQueryWithImmediateAndNonImmediateComponents : Engine
{
@ -1863,7 +1904,7 @@ namespace Tests
_components.Should().NotBeEmpty();
}
struct MockTimerComponent : IComponent
struct MockTimerComponent
{
public double Timer { get; }

View File

@ -1,109 +0,0 @@
using System;
using NUnit.Framework;
using FluentAssertions;
using Encompass;
using System.Collections.Generic;
namespace Tests
{
public class OrderedRendererTest
{
struct AComponent : IComponent { }
struct BComponent : IComponent { }
struct CComponent : IComponent { }
struct TestDrawComponent : IComponent, IDrawableComponent
{
public int Layer { get; set; }
}
class TestRenderer : OrderedRenderer<TestDrawComponent>
{
public override void Render(Entity entity, in TestDrawComponent testDrawComponent) { }
}
static bool called = false;
class DeactivatedRenderer : TestRenderer
{
public override void Render(Entity entity, in TestDrawComponent testDrawComponent)
{
called = true;
}
}
static bool calledOnDraw = false;
static (TestDrawComponent, Entity) resultComponent;
class CalledRenderer : OrderedRenderer<TestDrawComponent>
{
public override void Render(Entity entity, in TestDrawComponent testDrawComponent)
{
resultComponent = (testDrawComponent, entity);
calledOnDraw = true;
}
}
[Test]
public void RenderMethodCalledOnWorldDraw()
{
var worldBuilder = new WorldBuilder();
worldBuilder.RegisterDrawLayer(2);
var renderer = worldBuilder.AddOrderedRenderer(new CalledRenderer());
AComponent aComponent;
CComponent cComponent;
var testDrawComponent = new TestDrawComponent { Layer = 2 };
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, aComponent);
worldBuilder.SetComponent(entity, cComponent);
worldBuilder.SetComponent(entity, testDrawComponent);
var world = worldBuilder.Build();
world.Update(0.01f);
world.Draw();
Assert.IsTrue(calledOnDraw);
resultComponent.Should().BeEquivalentTo((testDrawComponent, entity));
}
[Reads(typeof(TestDrawComponent))]
class DestroyerEngine : Engine
{
public override void Update(double dt)
{
foreach (var entity in ReadEntities<TestDrawComponent>())
{
Destroy(entity);
}
}
}
[Test]
public void RenderMethodNotCalledAfterDestroy()
{
calledOnDraw = false;
var worldBuilder = new WorldBuilder();
worldBuilder.RegisterDrawLayer(1);
worldBuilder.AddEngine(new DestroyerEngine());
var renderer = worldBuilder.AddOrderedRenderer(new CalledRenderer());
TestDrawComponent testDrawComponent = new TestDrawComponent { Layer = 1 };
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, testDrawComponent);
var world = worldBuilder.Build();
world.Update(0.01);
world.Draw();
Assert.IsFalse(calledOnDraw);
}
}
}

View File

@ -5,15 +5,15 @@ namespace Tests
{
public static class GeneralRendererTest
{
struct AComponent : IComponent { }
struct AComponent { }
public class SingletonRead
{
static (AComponent, Entity) result;
class TestRenderer : GeneralRenderer
class TestRenderer : Renderer
{
public override void Render()
public override void Render(double dt, double alpha)
{
ref readonly var entity = ref ReadEntity<AComponent>();
result = (GetComponent<AComponent>(entity), entity);
@ -24,7 +24,7 @@ namespace Tests
public void SingletonComponent()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddGeneralRenderer(new TestRenderer(), 1);
worldBuilder.AddRenderer(new TestRenderer());
AComponent aComponent;
@ -34,10 +34,10 @@ namespace Tests
var world = worldBuilder.Build();
world.Update(0.01f);
world.Draw();
world.Draw(0.01f, 0);
world.Update(0.01);
world.Draw();
world.Draw(0.01f, 0);
Assert.That(result, Is.EqualTo((aComponent, entity)));
}
@ -46,7 +46,7 @@ namespace Tests
public void MultipleComponents()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddGeneralRenderer(new TestRenderer(), 1);
worldBuilder.AddRenderer(new TestRenderer());
AComponent aComponent;
AComponent aComponentTwo;
@ -59,10 +59,10 @@ namespace Tests
var world = worldBuilder.Build();
world.Update(0.01f);
world.Draw();
world.Draw(0.01f, 0);
world.Update(0.01f);
world.Draw();
world.Draw(0.01f, 0);
Assert.That(result, Is.EqualTo((aComponent, entity)).Or.EqualTo((aComponentTwo, entityB)));
}

View File

@ -5,8 +5,8 @@ namespace Tests
{
public class SpawnerTest
{
struct TestComponent : IComponent { }
struct SpawnMessageA : IMessage { }
struct TestComponent { }
struct SpawnMessageA { }
static Entity resultEntity;
@ -23,7 +23,7 @@ namespace Tests
[Writes(typeof(TestComponent))]
class TestSpawner : Spawner<SpawnMessageA>
{
protected override void Spawn(SpawnMessageA message)
protected override void Spawn(in SpawnMessageA message)
{
resultEntity = CreateEntity();
SetComponent(resultEntity, new TestComponent());

View File

@ -13,8 +13,8 @@ namespace Tests
{
public class EngineCycleSimple
{
struct AMessage : IMessage { }
struct BMessage : IMessage { }
struct AMessage { }
struct BMessage { }
[Receives(typeof(AMessage))]
[Sends(typeof(BMessage))]
@ -51,10 +51,10 @@ namespace Tests
public class EngineCycleComplex
{
struct AMessage : IMessage { }
struct BMessage : IMessage { }
struct CMessage : IMessage { }
struct DMessage : IMessage { }
struct AMessage { }
struct BMessage { }
struct CMessage { }
struct DMessage { }
[Receives(typeof(AMessage))]
[Sends(typeof(BMessage))]
@ -142,12 +142,12 @@ namespace Tests
public class MultipleEngineWriteWithPriority
{
struct SetMessage : IMessage
struct SetMessage
{
public Entity entity;
}
struct AComponent : IComponent
struct AComponent
{
public int myInt;
}
@ -211,12 +211,12 @@ namespace Tests
public class DefaultWritePriority
{
struct SetMessage : IMessage
struct SetMessage
{
public Entity entity;
}
struct AComponent : IComponent
struct AComponent
{
public int myInt;
}
@ -298,7 +298,7 @@ namespace Tests
public class EngineMessageSelfCycle
{
struct AMessage : IMessage { }
struct AMessage { }
[Receives(typeof(AMessage))]
[Sends(typeof(AMessage))]
@ -319,28 +319,6 @@ namespace Tests
}
}
public class IllegalWriteType
{
struct ANonMessage { }
[Sends(typeof(ANonMessage))]
class MyEngine : Engine
{
public override void Update(double dt)
{
}
}
[Test]
public void ThrowsError()
{
var worldBuilder = new WorldBuilder();
Assert.Throws<IllegalSendTypeException>(() => worldBuilder.AddEngine(new MyEngine()), "ANonMessage must be a Message or Component");
}
}
public class PriorityConflict
{
[Writes(typeof(MockComponent), 2)]
@ -407,13 +385,13 @@ namespace Tests
{
static List<Engine> order = new List<Engine>();
struct AComponent : IComponent { }
struct BComponent : IComponent { }
struct AComponent { }
struct BComponent { }
struct AMessage : IMessage { }
struct BMessage : IMessage { }
struct CMessage : IMessage { }
struct DMessage : IMessage { }
struct AMessage { }
struct BMessage { }
struct CMessage { }
struct DMessage { }
[Sends(typeof(AMessage))]
class AEngine : Engine
@ -520,8 +498,8 @@ namespace Tests
{
static List<Engine> order = new List<Engine>();
struct AMessage : IMessage { }
struct BMessage : IMessage { }
struct AMessage { }
struct BMessage { }
[Sends(typeof(AMessage), typeof(BMessage))]
class AEngine : Engine
@ -558,38 +536,5 @@ namespace Tests
Assert.That(order.IndexOf(engineA), Is.LessThan(order.IndexOf(engineB)));
}
}
public class DrawLayerRegister
{
struct AComponent : IComponent, IDrawableComponent
{
public int Layer { get; set; }
}
class ARenderer : OrderedRenderer<AComponent>
{
public override void Render(Entity entity, in AComponent drawComponent) { }
}
[Test]
public void DrawLayerRegisterAfterOrderedRendererRegisterThrows()
{
var worldBuilder = new WorldBuilder();
var rendererA = worldBuilder.AddOrderedRenderer(new ARenderer());
Assert.Throws<IllegalDrawLayerException>(() => worldBuilder.RegisterDrawLayer(1));
}
[Test]
public void DrawLayerRegisterBeforeOrderedRendererDoesNotThrow()
{
var worldBuilder = new WorldBuilder();
Assert.DoesNotThrow(() => worldBuilder.RegisterDrawLayer(1));
Assert.DoesNotThrow(() => worldBuilder.AddOrderedRenderer(new ARenderer()));
}
}
}
}

View File

@ -1,81 +0,0 @@
using NUnit.Framework;
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Text;
using Encompass;
namespace Tests
{
public class WorldTest
{
struct TestComponent : IComponent { }
struct TestDrawComponent : IComponent, IDrawableComponent
{
public int Layer { get; set; }
}
static List<object> drawOrder = new List<object>();
class TestEntityRenderer : OrderedRenderer<TestDrawComponent>
{
public override void Render(Entity entity, in TestDrawComponent testDrawComponent)
{
drawOrder.Add(entity);
}
}
class TestGeneralRenderer : GeneralRenderer
{
public override void Render()
{
drawOrder.Add(this);
}
}
[Test]
public void DrawOrder()
{
var worldBuilder = new WorldBuilder();
worldBuilder.RegisterDrawLayer(1);
worldBuilder.RegisterDrawLayer(2);
worldBuilder.RegisterDrawLayer(3);
worldBuilder.RegisterDrawLayer(4);
worldBuilder.RegisterDrawLayer(7);
worldBuilder.AddOrderedRenderer(new TestEntityRenderer());
var testGeneralRenderer = worldBuilder.AddGeneralRenderer(new TestGeneralRenderer(), 7);
TestComponent testComponent;
TestDrawComponent drawComponentThree = new TestDrawComponent { Layer = 3 };
var drawComponentTwo = new TestDrawComponent { Layer = 2 };
var drawComponentOne = new TestDrawComponent { Layer = 1 };
var drawComponentFour = new TestDrawComponent { Layer = 4 };
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entity, testComponent);
worldBuilder.SetComponent(entity, drawComponentThree);
var entityTwo = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entityTwo, testComponent);
worldBuilder.SetComponent(entityTwo, drawComponentTwo);
var entityThree = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entityThree, testComponent);
worldBuilder.SetComponent(entityThree, drawComponentThree);
var entityFour = worldBuilder.CreateEntity();
worldBuilder.SetComponent(entityFour, testComponent);
worldBuilder.SetComponent(entityFour, drawComponentFour);
var world = worldBuilder.Build();
world.Update(0.01f);
world.Draw();
drawOrder.Should().BeEquivalentTo(entityFour, entityTwo, entity, entityThree, testGeneralRenderer);
}
}
}

View File

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<RootNamespace>Tests</RootNamespace>
<AssemblyName>EncompassECS.Framework.Tests</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Platforms>x64;x86</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.7.0" />